站长统计app进入网址新版小猪设计建设网站
news/
2025/9/23 3:22:23/
文章来源:
站长统计app进入网址新版小猪,设计建设网站,大商创 多用户商城,久久诗词网Redis为什么用跳表实现有序集合
手写一个跳表
为了更好的回答上述问题以及更好的理解和掌握跳表#xff0c;这里可以通过手写一个简单的跳表的形式来帮助读者理解跳表这个数据结构。
我们都知道有序链表在添加、查询、删除的平均时间复杂都都是 O(n) 即线性增长#xff0c…Redis为什么用跳表实现有序集合
手写一个跳表
为了更好的回答上述问题以及更好的理解和掌握跳表这里可以通过手写一个简单的跳表的形式来帮助读者理解跳表这个数据结构。
我们都知道有序链表在添加、查询、删除的平均时间复杂都都是 O(n) 即线性增长所以一旦节点数量达到一定体量后其性能表现就会非常差劲。而跳表我们完全可以理解为在原始链表基础上建立多级索引通过多级索引检索定位将增删改查的时间复杂度变为 O(log n) 。
可能这里说的有些抽象我们举个例子以下图跳表为例其原始链表存储按序存储 1-10有 2 级索引每级索引的索引个数都是基于下层元素个数的一半。 假如我们需要查询元素 6其工作流程如下 从 2 级索引开始先来到节点 4。 查看 4 的后继节点是 8 的 2 级索引这个值大于 6说明 2 级索引后续的索引都是大于 6 的没有再往后搜寻的必要我们索引向下查找。 来到 4 的 1 级索引比对其后继节点为 6查找结束。
相较于原始有序链表需要 6 次我们的跳表通过建立多级索引我们只需两次就直接定位到了目标元素其查寻的复杂度被直接优化为O(log n)。 对应的添加也是一个道理假如我们需要在这个有序集合中添加一个元素 7那么我们就需要通过跳表找到小于元素 7 的最大值也就是下图元素 6 的位置将其插入到元素 6 的后面让元素 6 的索引指向新插入的节点 7其工作流程如下 从 2 级索引开始定位到了元素 4 的索引。 查看索引 4 的后继索引为 8索引向下推进。 来到 1 级索引发现索引 4 后继索引为 6小于插入元素 7指针推进到索引 6 位置。 继续比较 6 的后继节点为索引 8大于元素 7索引继续向下。 最终我们来到 6 的原始节点发现其后继节点为 7指针没有继续向下的空间自此我们可知元素 6 就是小于插入元素 7 的最大值于是便将元素 7 插入。 这里我们又面临一个问题我们是否需要为元素 7 建立索引索引多高合适
我们上文提到理想情况是每一层索引是下一层元素个数的二分之一假设我们的总共有 16 个元素对应各级索引元素个数应该是 1. 一级索引:16/28
2. 二级索引:8/2 4
3. 三级索引:4/22
由此我们用数学归纳法可知 1. 一级索引:16/216/2^18
2. 二级索引:8/2 16/2^2 4
3. 三级索引:4/216/2^32
假设元素个数为 n那么对应 k 层索引的元素个数 r 计算公式为: rn/2^k
同理我们再来推断以下索引的最大高度一般来说最高级索引的元素个数为 2我们设元素总个数为 n索引高度为 h代入上述公式可得 2 n/2^h2*2^hn2^(h1)nh1log2^nhlog2^n -1
而 Redis 又是内存数据库我们假设元素最大个数是65536我们把65536代入上述公式可知最大高度为 16。所以我们建议添加一个元素后为其建立的索引高度不超过 16。
因为我们要求尽可能保证每一个上级索引都是下级索引的一半在实现高度生成算法时我们可以这样设计 跳表的高度计算从原始链表开始即默认情况下插入的元素的高度为 1代表没有索引只有元素节点。 设计一个为插入元素生成节点索引高度 level 的方法。 进行一次随机运算随机数值范围为 0-1 之间。 如果随机数大于 0.5 则为当前元素添加一级索引自此我们保证生成一级索引的概率为 50% 这也就保证了 1 级索引理想情况下只有一半的元素会生成索引。 同理后续每次随机算法得到的值大于 0.5 时我们的索引高度就加 1这样就可以保证节点生成的 2 级索引概率为 25% 3 级索引为 12.5% ……
我们回过头上述插入 7 之后我们通过随机算法得到 2即要为其建立 1 级索引 最后我们再来说说删除假设我们这里要删除元素 10我们必须定位到当前跳表各层元素小于 10 的最大值索引执行步骤为 2 级索引 4 的后继节点为 8指针推进。 索引 8 无后继节点该层无要删除的元素指针直接向下。 1 级索引 8 后继节点为 10说明 1 级索引 8 在进行删除时需要将自己的指针和 1 级索引 10 断开联系将 10 删除。 1 级索引完成定位后指针向下后继节点为 9指针推进。 9 的后继节点为 10同理需要让其指向 null将 10 删除。 总结 有几个原因 1、它们不是很占用内存。这主要取决于你。改变节点拥有给定层数的概率的参数会使它们比 B 树更节省内存。 2、有序集合经常是许多 ZRANGE 或 ZREVRANGE 操作的目标也就是说以链表的方式遍历跳表。通过这种操作跳表的缓存局部性至少和其他类型的平衡树一样好。 3、它们更容易实现、调试等等。例如由于跳表的简单性我收到了一个补丁已经在 Redis 主分支中用增强的跳表实现了O(log(N))的 ZRANK。它只需要对代码做很少的修改。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/911223.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!