当前位置: 首页 > news >正文

跳跃表原理和实现

跳跃表原理和实现

前提

有时候会被问到链表如果做到二分搜索,可能会有部分的人会去把链表中的值保存到数组来进行二分,但是如果知道跳跃表的话,那么这个数据结构就可以解决这个困惑,它允许快速查询一个有序连续元素的数据链表,它的效率可以做到和二分相同,都是O(logn)的平均时间复杂度,其空间复杂度为O(n)。

跳跃列表是在很多应用中有可能替代平衡树而作为实现方法的一种数据结构。跳跃列表的算法有同平衡树一样的渐进的预期时间边界,并且更简单、更快速和使用更少的空间。----by 发明者像是redis中有序集合就使用到了跳跃表。

原理

性质

首先,应该要了解跳跃表的性质;

  1. 由很多层结构组成;
  2. 每一层都是一个有序的链表,排列顺序为由高层到底层,都至少包含两个链表节点,分别是前面的head节点和后面的nil节点;
  3. 最底层的链表包含了所有的元素;
  4. 如果一个元素出现在某一层的链表中,那么在该层之下的链表也全都会出现(上一层的元素是当前层的元素的子集);
  5. 链表中的每个节点都包含两个指针,一个指向同一层的下一个链表节点,另一个指向下一层的同一个链表节点;

可以看到,这里一共有4层,最上面就是最高层(Level 3),最下面的层就是最底层(Level 0),然后每一列中的链表节点中的值都是相同的,用指针来连接着。跳跃表的层数跟结构中最高节点的高度相同。理想情况下,跳跃表结构中第一层中存在所有的节点,第二层只有一半的节点,而且是均匀间隔,第三层则存在1/4的节点,并且是均匀间隔的,以此类推,这样理想的层数就是logN。

搜索

其基本原理就是从最高层的链表节点开始,如果比当前节点要大和比当前层的下一个节点要小,那么则往下找,也就是和当前层的下一层的节点的下一个节点进行比较,以此类推,一直找到最底层的最后一个节点,如果找到则返回,反之则返回空。

代码实现大致为:

find(x)   
{  
    p = top;  
    while (1) {  
        while (p->next->key < x)  
            p = p->next;  
        if (p->down == NULL)   
            return p->next;  
        p = p->down;  
    }  
}  

插入

既然要插入,首先需要确定插入的层数,这里有不一样的方法。1. 看到一些博客写的是抛硬币,只要是正面就累加,直到遇见反面才停止,最后记录正面的次数并将其作为要添加新元素的层;2. 还有就是一些博客里面写的统计概率,先给定一个概率p,产生一个0到1之间的随机数,如果这个随机数小于p,则将高度加1,直到产生的随机数大于概率p才停止,根据给出的结论,当概率为1/2或者是1/4的时候,整体的性能会比较好(其实当p为1/2的时候,也就是抛硬币的方法)。

当确定好要插入的层数以后,则需要将元素都插入到从最底层到第k层。

删除

在各个层中找到包含指定值的节点,然后将节点从链表中删除即可,如果删除以后只剩下头尾两个节点,则删除这一层。

转载于:https://www.cnblogs.com/George1994/p/7635731.html

相关文章:

  • 【Linux】命令——网络管理
  • python初学-元组、集合
  • 读Zepto源码之Fx模块
  • JS_dom_自定义对象
  • [CQOI 2010]扑克牌
  • 判断是否为汉字
  • 编程感悟
  • Oracle 重启监听
  • iOS 静默拍照!!!
  • 指定网卡ping另外的网卡
  • 4 Median of Two Sorted Arrays(medium)
  • jdk8 stream可以与list,map等数据结构互相转换
  • 软件开发阶段数据库升级维护策略
  • web基础,用html元素制作web页面
  • js 右键菜单
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • iOS 颜色设置看我就够了
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • java中的hashCode
  • leetcode388. Longest Absolute File Path
  • leetcode讲解--894. All Possible Full Binary Trees
  • nodejs实现webservice问题总结
  • Otto开发初探——微服务依赖管理新利器
  • SpiderData 2019年2月25日 DApp数据排行榜
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 记一次删除Git记录中的大文件的过程
  • 驱动程序原理
  • 少走弯路,给Java 1~5 年程序员的建议
  • 时间复杂度与空间复杂度分析
  • 携程小程序初体验
  • [Shell 脚本] 备份网站文件至OSS服务(纯shell脚本无sdk) ...
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • Mac 上flink的安装与启动
  • 浅谈sql中的in与not in,exists与not exists的区别
  • #pragma once
  • #常见电池型号介绍 常见电池尺寸是多少【详解】
  • #微信小程序(布局、渲染层基础知识)
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (八)Spring源码解析:Spring MVC
  • (二)linux使用docker容器运行mysql
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (三)elasticsearch 源码之启动流程分析
  • (未解决)macOS matplotlib 中文是方框
  • (一)Dubbo快速入门、介绍、使用
  • (转)关于pipe()的详细解析
  • .apk 成为历史!
  • .form文件_一篇文章学会文件上传
  • .net 7 上传文件踩坑
  • .NET Reactor简单使用教程
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .Net 知识杂记
  • .NETCORE 开发登录接口MFA谷歌多因子身份验证
  • @Bean, @Component, @Configuration简析
  • [20171101]rman to destination.txt
  • [28期] lamp兄弟连28期学员手册,请大家务必看一下