跳表(skiplist)的理解

跳表(skiplist)的理解听到跳表 skiplist 这个名字 既然是 list 那么应该跟链表有关 跳表是有序链表 但是我们知道 即使对于排过序的链表 我们对于查找还是需要进行通过链表的指针进行遍历的 时间复杂度很高依然是 O n 这个显然是不能接受的 是否可以像数组那样 通过二分法进行查找呢 但是由于在内存中的存储的不确定性 不能这做 但是我们可以结合二分法的思想 没错 跳表就是链表与二分法的结合 1 链表

一层节点索引
一个有序的链表,我们选取它的一半的节点用来建索引,这样如果插入一个节点,我们比较的次数就减少了一半。这种做法,虽然增加了50%的空间,但是性能提高了一倍。如上图。

既然,我们已经提取了一层节点索引,那么,可以在第一层索引上再提取索引。如下图。(二级索引应去掉node2节点)
两层索引

对于node5来说,它的next:

node5->next[2] = tailNode; node5->next[1] = node7; node5->next[0] = node6; 

对于node7来说,它的next:

node7->next[1] = node9; node7->next[0] = node8; 

对于node3来说,它的next:

node3->next[0] = node4; 

查找
再看下这张图
如果我们要找node6节点,(二级索引应去掉node2节点)
第一次比较headerNode->next[2]的值,也就是node5的值。显然node5小于node6(跳表的数据是有序的),所以,下一次应该从第2级的node5开始查询,也就是令targetNode = targetNode->next[2];






第二次应该比较node5->next[2]的值,也就是tailNode的值。tailNode的值是最大的。所以结果是大于,下一次应该从第1级的node5开始查询。这里从第2级跳到第1级。但是没有改变targetNode。

第三次我们应该比较node5->next[1]的值,也就是node7的值。因为node7大于node6,所以,下一次应该从第0级的node5开始查询。这里从第1级跳到第0级。也没有改变targetNode。

插入
当有2级索引时,新的节点先和2级索引比较,再和1级索引比较,最后和原链表比较,最终插到原链表中。当节点很多时,比较次数是原来的四分之一。

当然,当节点足够多的时候,我们还可以继续加索引,保证每一层索引数是低级索引的一半。当这一层只剩两个节点时,就没有必要再建索引了,因为一个节点没有比较的意义。

当很多节点插入时,上层索引节点已经不够用,我们需要在新节点中选取一部分节点提到上一层,跳表的设计者用“抛硬币”的方法选取节点是否提拔,也就是随机的方式,每个节点有50%概率会提拔。这样虽然不会让索引绝对均匀分布,但也会大体上是均匀的。

综上,插入的步骤:

  1. 新节点和各层索引节点逐一比较,确定原链表的插入位置。O(logN)
  2. 把索引插入到原链表。O(1)
  3. 利用抛硬币的随机方式,决定新节点是否提升为上一级索引。结果为“正”则提升并继续抛硬币,结果为“负”则停止。O(logN)

总体上,跳表插入操作的时间复杂度是O(logN),而这种数据结构所占空间是2N,既空间复杂度是 O(N)。

删除

  1. 自上而下,查找第一次出现节点的索引,并逐层找到每一层对应的节点。O(logN)
  2. 删除每一层查找到的节点,如果该层只剩下1个节点,删除整个一层(原链表除外)。O(logN)

总体上,跳表删除操作的时间复杂度是O(N)。

应用
Redis当中的Sorted-set这种有序的集合,正是对于跳表的改进和应用。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/176496.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午9:47
下一篇 2026年3月26日 下午9:47


相关推荐

  • createmutex函数参数含义_pthread_create函数

    createmutex函数参数含义_pthread_create函数CreateMutexCreateMutex函数的作用是找出当前系统是否已经存在指定进程的实例,如果没有则创建一个互斥体。//VC声明HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes,//指向安全属性的指针BOOLbInitialOwner,//初始化互斥对象的所有者LPCTSTRlpName//指向互斥对象名的指针);一个应用:HANDLEhMutex;hMutex=CreateMutex(

    2022年10月5日
    5
  • Java项目开发文档(javaweb实战项目)

    项目开发过程中为了增加程序的可读性和程序的健壮性,方便后期程序的调试和维护,所以需要在开发过程中统一技术规范,一般会在项目初期确定好相关文档作为这一统一的规范。不同公司会对文档做不同要求,划不同的分类,但一般来说(或者拿自己的经验说)大致可以分为需求文档、接口文档、流程图(可以单独作为一份文件可以作为附件附在文档中)、变更文件等。一、需求文档在项目启动之后,项目的目标已经明确了,那么就要

    2022年4月15日
    136
  • asp.net core 阿里云消息服务(Message Service,原MQS)发送接口的实现

    asp.net core 阿里云消息服务(Message Service,原MQS)发送接口的实现最近在后台处理订单统计等相关功能用到了大力的mqs,由于官方没有实现asp.netcore的sdk,这里简单实现了发送信息的功能,有兴趣的可以参考实现其他相关功能usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Net.Http;usingSystem.Net.Http.Headers;…

    2025年7月1日
    7
  • php+分针和时针重合,分针和时针每天重合几次?分别在几点几分重合?怎么计算…

    php+分针和时针重合,分针和时针每天重合几次?分别在几点几分重合?怎么计算…22 次重合时间 0 00 1 06 2 12 3 17 4 22 5 27 6 33 7 38 8 43 9 49 10 54 12 00 13 06 14 12 15 17 16 22 17 27 18 33 19 38 20 43 21 49 22 54 计算方法 每 12 小时 时针转一圈 分针转 12 圈 即分针 11 次追上时针 所以取 0 00 为起点 上半天把时钟分为 11 等分即可 每一刻度的时间

    2026年3月19日
    1
  • Spring Boot定制首页和404页面

    Spring Boot定制首页和404页面一、定制首页:方式一:SpringBoot自动映射在静态资源目录resources、static、public的其中一个目录中创建index.html文件,springBoot会自动识别,将这个文件作为首页访问 方式二:使用thymeleaf模板引擎1.导入依赖<!–Thymeleaf模板引擎依赖–><dependency><groupId>org.thymeleaf</groupId><artifact

    2022年7月27日
    15

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号