@@ -139,7 +139,7 @@ type timersBucket struct {
139
139
140
140
### 四叉小顶堆性质
141
141
142
- 四叉堆高度上比二叉堆要矮一些。直接孩子节点一定比父节点大,同一层的相邻四个节点是按从小到大排列的,但如果不相邻,那么就不遵循这样的关系,所以,下面这种情况是符合四叉小顶堆的性质的 :
142
+ 四叉堆高度上比二叉堆要矮一些。一个节点的所有(最多有4个)孩子节点都比这个节点要大。一个节点的(只有一个)父节点一定比当前节点小。下面是填好值之后的一个典型的四叉堆 :
143
143
144
144
```
145
145
┌─────┐
@@ -152,7 +152,7 @@ type timersBucket struct {
152
152
▼
153
153
┌─────┬─────┬─────┬─────┐
154
154
│ │ │ │ │
155
- │ 1 │ 2 │ 7 │ 11 │
155
+ │ 3 │ 2 │ 2 │ 10 │
156
156
└─────┴─────┴─────┴─────┘
157
157
│ │ │ │
158
158
│ │ │ │
@@ -164,13 +164,13 @@ type timersBucket struct {
164
164
▼ │ │ ▼
165
165
┌─────┬─────┬─────┬─────┐ │ │ ┌─────┬─────┬─────┬─────┐
166
166
│ │ │ │ │ ▼ ▼ │ │ │ │ │
167
- │ 13 │ 15 │ 17 │ 20 │ ┌─────┬─────┬─────┬─────┐ ┌─────┬─────┬─────┬─────┐ │ 12 │ 13 │ 15 │ 16 │
167
+ │ 20 │ 4 │ 5 │ 13 │ ┌─────┬─────┬─────┬─────┐ ┌─────┬─────┬─────┬─────┐ │ 99 │ 13 │ 11 │ 12 │
168
168
└─────┴─────┴─────┴─────┘ │ │ │ │ │ │ │ │ │ │ └─────┴─────┴─────┴─────┘
169
- │ 12 │ 14 │ 15 │ 16 │ │ 8 │ 9 │ 11 │ 12 │
169
+ │ 12 │ 14 │ 15 │ 16 │ │ 3 │ 10 │ 3 │ 3 │
170
170
└─────┴─────┴─────┴─────┘ └─────┴─────┴─────┴─────┘
171
171
```
172
172
173
- 当然,二叉小顶堆同一层的大小关系也是不确定的。只是四叉堆在同一层还有这种特殊的相邻的情况 。
173
+ 和二叉堆一样,对于一个节点的要求只有和其父节点以及子节点之间的大小关系。相邻节点之间没有任何关系 。
174
174
175
175
### 时间堆插入
176
176
@@ -379,8 +379,13 @@ func timerproc(tb *timersBucket) {
379
379
380
380
``` go
381
381
func siftupTimer (t []*timer , i int ) {
382
+ // 先暂存当前刚插入到数组尾部的节点
382
383
when := t[i].when
383
384
tmp := t[i]
385
+
386
+ // 从当前插入节点的父节点开始
387
+ // 如果最新插入的那个节点的触发时间要比父节点的触发时间更早
388
+ // 那么就把这个父节点下移
384
389
for i > 0 {
385
390
p := (i - 1 ) / 4 // parent
386
391
if when >= t[p].when {
@@ -390,6 +395,9 @@ func siftupTimer(t []*timer, i int) {
390
395
t[i].i = i
391
396
i = p
392
397
}
398
+
399
+ // 如果发生过移动,用最新插入的节点
400
+ // 覆盖掉最后一个下移的父节点
393
401
if tmp != t[i] {
394
402
t[i] = tmp
395
403
t[i].i = i
@@ -405,8 +413,8 @@ func siftdownTimer(t []*timer, i int) {
405
413
when := t[i].when
406
414
tmp := t[i]
407
415
for {
408
- c := i*4 + 1 // left child
409
- c3 := c + 2 // mid child
416
+ c := i*4 + 1 // 最左孩子节点
417
+ c3 := c + 2 // 第三个孩子节点
410
418
if c >= n {
411
419
break
412
420
}
@@ -440,6 +448,60 @@ func siftdownTimer(t []*timer, i int) {
440
448
}
441
449
```
442
450
451
+ 这段代码实在是称不上优雅,其实就是在所有孩子节点中先找出最小的那一个,如果最小的比当前要下移的节点还要大,那么就 break。反之,则将最小的节点上移,然后再判断这个最小节点的 4 个子节点是否都比要下移的节点大。以此类推。用图来模拟一下这个过程:
452
+
453
+ ```
454
+ │ ┌───┐
455
+ │ │ 5 │
456
+ │ └───┘
457
+ │ │
458
+ │ ┌─────┘
459
+ │ ▼
460
+ │ ┌───┬───┳━━━┳───┐
461
+ │ │ 7 │ 3 │ 2 ┃ 6 │
462
+ │ └───┴───┻━━━┻───┘
463
+ ┌───────────────────┐ │ │
464
+ │ siftdownTimer │ │ └──────────┐
465
+ └───────────────────┘ │ ▼
466
+ .─────────. │ ┌───┬───┬───┳━━━┓
467
+ ( before ) │ │ 4 │ 5 │ 9 │ 3 ┃
468
+ `─────────' │ └───┴───┴───┻━━━┛
469
+ │ │
470
+ │ └─────────────┐
471
+ │ ▼
472
+ │ ┌───┬───┬───┳━━━┓
473
+ │ │ 6 │ 6 │ 6 │ 4 ┃
474
+ │ └───┴───┴───┻━━━┛
475
+ │
476
+ ▼
477
+
478
+
479
+
480
+ │ ┌───┐
481
+ │ │ 2 │
482
+ │ └───┘
483
+ │ │
484
+ │ ┌─────┘
485
+ │ ▼
486
+ │ ┌───┬───┳━━━┳───┐
487
+ │ │ 7 │ 3 │ 3 ┃ 6 │
488
+ │ └───┴───┻━━━┻───┘
489
+ ┌───────────────────┐ │ │
490
+ │ siftdownTimer │ │ └──────────┐
491
+ └───────────────────┘ │ ▼
492
+ .─────────. │ ┌───┬───┬───┳━━━┓
493
+ ( after ) │ │ 4 │ 5 │ 9 │ 4 ┃
494
+ `─────────' │ └───┴───┴───┻━━━┛
495
+ │ │
496
+ │ └─────────────┐
497
+ │ ▼
498
+ │ ┌───┬───┬───┳━━━┓
499
+ │ │ 6 │ 6 │ 6 │ 5 ┃
500
+ │ └───┴───┴───┻━━━┛
501
+ │
502
+ ▼
503
+ ```
504
+
443
505
### time.After
444
506
445
507
``` go
0 commit comments