1.引言

Golang在Timer(计时器)的实现中使用了四叉堆,而不是常见的二叉堆,这个问题引起了我的兴趣。

对于这个问题,网上的解释是这样的

但是我仔细查阅了资料以后,有了点有趣的发现。

2.说明

dn

Timer最常见的2个操作

1)Insert()

添加一个计时器。涉及 sift-up(上推)操作,时间复杂度为O(log n log d)

Python代码

import math
result = math.log(n, d)

时间消耗(需要交换或者比较的次数)

n(数量)二叉堆四叉堆八叉堆
1w13.36.644.43
10w16.618.305.54
100w19.939.976.64
1000w23.2511.637.75

2) Delete()

指定时间到达后,清除计时器。涉及 sift-down(下推)操作,时间复杂度为O(d * log n log d)

Python代码

import math
result = d * math.log(n, d)

时间消耗(需要交换或者比较的次数)

n(数量)二叉堆四叉堆八叉堆
1w26.5826.5835.43
10w33.3333.3344.29
100w39.8639.8653.15
1000w46.5146.5162.01

3. 结论

正常情况下,插入操作:多叉堆执行性能优于二叉堆; 删除操作:多叉堆执行性能弱于二叉堆。
但是细心的朋友应该已经发现,四叉堆插入操作的耗时只有二叉堆的一半,而删除操作的耗时与二叉堆完全相同。 这么一对比,优势确实显著。

参考资料

1.Heap (data structure)
2.Binary heap
3.d-ary heap
4.Golang 定时器底层实现深度剖析
5.数据结构:堆(Heap)

微信公众号