游戏排行榜最优算法-字典树。与超快速跳表、redis跳表性能对比。

如果使用数据库,毫无疑问redis的有序集合(基于跳表)是最简单的
一般来讲很多文章也会推荐跳表skiplist
但是由于战力可转化为整数数值存储,论本地内存计算的数据结构,当属字典树最优

标准树容器都不支持容器内节点的字典序的距离差计算,但其实自己改造树是可以的实现的:每个分支记录分支下元素总数,每当有元素插入删除时,更新其所有祖先上的数量记录,用时O(层数)=O(log(N))

(4、8、16叉……)字典树,可以通过两个键值的异或运算快速找到最小公共父节点,层内定位是随机访问,且无需遍历比较直接用位运算定位节点,局部内存缓存效果超级好,数量加减都在树结构上完成。对比基于对比和概率的跳表来说各方面都优秀的多。

实测百万数据, 32叉字典树 对比高度优化的跳表,根据键值查找对象的性能快25倍,插入和rank性能都快约5~7倍(注意插入时内存申请的耗时已经达到不可忽视的程度)。



104万个数据(数值范围0~104万),操作104万次,相同release编译,每组测试交叉并在之间清除cpu内存缓存
Redis zsortedset源码抽取版(保留数据结构不变,脱离原工作环境,轻度改为模板类)
高度优化的跳表(估计理论极限性能85%+以上,比git上前4的skiplist实现快40%到150%,在含rank的完善实现中估计排行第一) ,
和32叉字典树对比:

redis sortedset
源码抽取版
double键
超快速跳表(15层)
支持重复键
元素总量超(2^层数)时自适应调整概率
元素存储于对应节点
int键(比double键快5%)
32叉字典树
(含排位功能,半支持重复键值)
int键(不支持其他类型)
随机插入 2434ms 827ms
234ms(稳定排序(严格要求按顺序插入时)+最佳建表)
171ms(不稳定排序(不要求同键顺序时)+最佳建表)
312ms(分16组不稳定排序+并集)
77ms(从有序数据源最佳建表=创建跳表副本)
140ms(32个小元素集成至底层节点)
218ms(为每个元素分配空间)
随机顺序 查找>=key的第一个对象 2511ms 890ms
390ms(最佳表)
47ms
值查排位 2589ms 890ms(与链表头部距离)
406ms(最佳表)
203ms(排位)
390ms(随机两键值距离算法)
排位查值 343ms 156ms
46ms(最佳表)
78ms
随机删除 2153ms 702ms(N次删除,每次删除键对应的第一个值)
818ms(N次删除,每次删除键对应的全部值(测试集只对应一个值))
593ms(最佳表 删除键第一个)
421ms(随机顺序删除N/2次,每次正好能删除两个值)
141ms(小类型集成)
171ms(为每个元素new)

new int {i} 104万次 耗时41ms
std哈希表 插入{i,i} 104万次 234ms,1677万次5320ms。

1677万个数据(数值范围0~1677万),操作1677万次。(16倍数据量和16倍操作)
括号内的倍率指与104万测试相比。

redis源码抽取版 超快速跳表24层 32叉字典树
插入 75099ms 28033ms(元素存储于链表节点)(28.19倍)
6193ms(稳定排序+最佳建表)
5288ms(分16组不稳定排序+并集)
2792ms(不稳定排序+最佳建表)
1170ms(从有序数据源最佳建表=创建跳表副本)
4820ms(32个小元素集成至底层节点) (34.42倍)
6100ms(为每个元素分配空间) (27.98倍)
查找>=key的第一个对象 76591ms 29625ms (30.03倍)
12995ms(最佳表)
1607ms (34.19倍)
值查排位 81589ms 30171ms(与链表头部距离) (33.01倍)
13495ms(最佳表)
5553ms(排位) (27.35倍)
10655ms(随机两键后算距离) (27.32倍)
排位查值 7004ms 3027ms(17.70倍)
1014ms(最佳表)
1513ms
删除 73024ms 28969ms(随机顺序查找键的第一个并删除)(35.72倍) 5024ms(小类型集成) (35.63倍)
5679ms(为每个元素new) (33.2105倍)

1677万元素乱序,每次取104万排序后再合并到跳表中,16次,共计 5288ms。
不含排序的每次合并104万有序数据耗时(ms):
95,129,147,155,184,210,217,241,267,261,274,294,305,312,338,333

超快速跳表提供了 修改方面:更新key而不析构value;查询方面:排位(下标)→键值对,键/迭代器→排位(下标)这两个std::map不支持的功能。

你可能感兴趣的:(技术)