下图分别展示了三个高度为 1 层、 3 层和 5 层的节点,因为 C 语言的数组索引总是从 0 开始的,所以节点的第一层是 level[0] ,而第二层是 level[1] ,以此类推 。
文章插图
前进指针每个层都有一个指向表尾方向的前进指针(level[i].forward 属性),用于从表头向表尾方向访问节点 。
文章插图
上图用虚线表示出了程序从表头向表尾方向,遍历跳跃表中所有节点的路径:
- 迭代程序首先访问跳跃表的第一个节点(表头),然后从第四层的前进指针移动到表中的第二个节点 。
- 在第二个节点时,程序沿着第二层的前进指针移动到表中的第三个节点 。
- 在第三个节点时,程序同样沿着第二层的前进指针移动到表中的第四个节点 。
- 当程序再次沿着第四个节点的前进指针移动时,它碰到一个 NULL ,程序知道这时已经到达了跳跃表的表尾,于是结束这次遍历 。
- 两个节点之间的跨度越大,它们相距得就越远 。
- 指向 NULL 的所有前进指针的跨度都为 0 ,因为它们没有连向任何节点 。
举个例子,如下用虚线标记了在跳跃表中查找分值为 3.0 、 成员对象为 o3 的节点时,沿途经历的层: 查找的过程只经过了一个层,并且层的跨度为 3 ,所以目标节点在跳跃表中的排位为 3 。
文章插图
再举个例子,如下用虚线标记了在跳跃表中查找分值为 2.0 、 成员对象为 o2 的节点时,沿途经历的层: 在查找节点的过程中,程序经过了两个跨度为 1 的节点,因此可以计算出,目标节点在跳跃表中的排位为 2。
文章插图
后退指针节点的后退指针(backward 属性)用于从表尾向表头方向访问节点: 跟可以一次跳过多个节点的前进指针不同,因为每个节点只有一个后退指针,所以每次只能后退至前一个节点 。
文章插图
上图用虚线展示了如果从表尾向表头遍历跳跃表中的所有节点: 程序首先通过跳跃表的 tail 指针访问表尾节点,然后通过后退指针访问倒数第二个节点,之后再沿着后退指针访问倒数第三个节点,再之后遇到指向 NULL 的后退指针,于是访问结束 。
分值和成员
- 节点的分值(score 属性)是一个 double 类型的浮点数,跳跃表中的所有节点都按分值从小到大来排序 。
- 节点的成员对象(obj 属性)是一个指针,它指向一个字符串对象,而字符串对象则保存着一个 SDS(简单动态字符串) 值 。
举个例子,在下图所示的跳跃表中,三个跳跃表节点都保存了相同的分值 10086.0 ,但保存成员对象 o1 的节点却排在保存成员对象 o2 和 o3 的节点之前,而保存成员对象 o2 的节点又排在保存成员对象 o3 的节点之前,由此可见, o1 、 o2 、 o3 三个成员对象在字典中的排序为 o1 <= o2 <= o3 。
文章插图
跳跃表虽然仅靠多个跳跃表节点就可以组成一个跳跃表,如下图 所示:
文章插图
推荐阅读
- 八张图了解Redis和MySQL数据一致性问题
- Nginx可以做什么?看完这篇你就懂了
- 基于Redis实现的分布式锁知识点总结
- 基于SSM实现的个人网盘系统源码
- 从Linux源码看Socket的listen及连接队列
- 大佬把Spring框架总结的「无比详细」,看完还说不懂别学了
- Spring Cloud微服务分布式物联网平台前后端分离源码
- 一口气看完45个寄存器,CPU核心技术大揭秘
- Python爬虫遇到验证码的几种处理方式,文章末尾有源码
- 运动|“长期化妆”和“长期素颜”,5年后皮肤有什么区别?看完你就懂