跳跃表(跳表)是什么

为什么要有跳表

正常链表只能一个一个往下走但是如果我直到我的目标位置就在链表的中部但是我还得一步一步走过去很浪费时间,所以跳表就是在正常链表的基础上添加了多步跳跃的指针。

什么是跳表

跳表(Skip List)是一种概率型的数据结构,它是基于链表的,通过创建多个层次的链表来加快搜索速度。每个节点不仅有指向下一节点的指针,还可能有指向更高层次节点的指针,从而实现快速跳跃。跳表的时间复杂度为 O(log n) 级别,适用于插入、删除和查找操作。

演示图只是为了方便,实际跳表并不一定是二分的,一个节点最初始在最底层(L0),他有75%的概率不增长层数有25%的概率往上增长一层,后续也是如此25%概率增长一层,我们的层数基本控制在log n。

cpp 复制代码
以下源码来自 redis7.0
​
#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^64 elements */
#define ZSKIPLIST_P 0.25   /* Skiplist P = 1/4 */
​
/* Returns a random level for the new skiplist node we are going to create.
 * The return value of this function is between 1 and ZSKIPLIST_MAXLEVEL
 * (both inclusive), with a powerlaw-alike distribution where higher
 * levels are less likely to be returned. */
int zslRandomLevel(void) {
    static const int threshold = ZSKIPLIST_P*RAND_MAX;
    int level = 1;
    while (random() < threshold)
        level += 1;
    return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

跳表的基本结构

跳表由以下几个部分组成:

  1. 表头(head):负责维护跳跃表的节点指针。

  2. 跳跃表节点:保存着元素值,以及多个层。

  3. :保存着指向其他元素的指针。高层的指针越过的元素数量大于等于低层的指针,为了提高查找的效率,程序总是从高层先开始访问,然后随着元素值范围的缩小,慢慢降低层次。

  4. 表尾:全部由 NULL 组成,表示跳跃表的末尾。

跳表的实现

在Redis中,跳表由 zskiplistNodezskiplist 两个结构定义。其中 zskiplistNode 结构用于表示跳跃表节点,而 zskiplist 结构则用于保存跳跃表节点的相关信息,比如节点的数量,以及指向表头节点和表尾节点的指针等等。

zskiplistNode 结构
  • 后退指针(backward):指向当前节点的前一个节点。

  • 分值(score):用于排序,跳跃表中的所有节点都按分值大小进行排序。

  • 成员对象(ele):即真正要往链表中存放的对象。

  • 层(level):每个节点都包含很多层,每一层指向的都是同一个对象。每一层包含一个前进指针和一个跨度(span),前进指针指向同一层的下一个节点,跨度表示两个节点之间的距离。

cpp 复制代码
typedef struct zskiplistNode {
    //Zset 对象的元素值
    sds ele;
    //元素权重值
    double score;
    //后退指针
    struct zskiplistNode *backward;
  
    //节点的level数组,保存每层上的前向指针和跨度
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned long span;
    } level[];
} zskiplistNode;
zskiplist 结构
  • header:指向跳跃表的表头节点。

  • tail:指向跳跃表的表尾节点。

  • level:记录目前跳跃表内,层数最大的那个节点的层数(表头节点的层数不计算在内)。

  • length:记录跳跃表的长度,也即是,跳跃表目前包含节点的数量(表头节点不计算在内)。

跳表的操作

跳表支持以下基本操作:

  1. 插入(Insert):插入一个元素时,从最高层开始,查找到当前节点的目标插入位置,随机生成它的层数(25%概率增长一层),然后将元素插入到跳表中并更新指针。需要使用一个数组记录该节点在各层的上一节点,用于跟新指针。

  2. 删除(Delete):删除元素时,需要最高层级开始找到对应的节点,删除并更新相关层级指针。

  3. 查找(Search):查找元素时,从高层开始向下查找,直到找到元素或到达底层。

跳表是一种以空间换时间的方案,它通过增加索引层数来提高查找效率,但同时也会占用更多的内存。在Redis中,跳表主要用于实现有序集合(Sorted Set),它能够保证元素的快速查找和有序存储。

相关推荐
stolentime21 分钟前
洛谷P10515 转圈题解
c++·算法·数学建模·贪心算法
tdtsmt1 小时前
穿戴硬件量产工艺实录:天地通电子智能手表主板 SMT 贴片案
c++
和裕1 小时前
蜂窝板 vs 七层瓦楞重型纸箱:大件工业设备运输性能与成本全对比
大数据·运维·网络·人工智能·算法
衡石科技2 小时前
Data_Agent记忆机制与经验复用衡石分析智能体会话记忆与长期学习技术解析
人工智能·科技·学习·算法·企业级bi
Msshu1233 小时前
2~5串锂电快充优选|XSP36 Type‑C升压/升降压快充管理芯片
数据结构·随机森林·贪心算法·排序算法·线性回归·启发式算法
shirsl3 小时前
算法 Day 2 滑动窗口 + 栈 / 单调栈
开发语言·python·算法
土司大王4 小时前
LeetCode hot100 回溯专题总结:Java 通用模板、决策树模型
java·算法·leetcode·决策树
2601_962218614 小时前
万象生鲜系统订单全生命周期状态同步技术实现业务可视
大数据·数据库·人工智能·python·算法
那年窗外下的雪.5 小时前
AIDC 学习日志|第 22 天|All-Active/Single-Active 故障演练设计
服务器·网络·学习·算法·哈希算法
m0_734571765 小时前
深入理解C++ 析构函数<一>基本概念
开发语言·c++