跳跃表原理和实现
跳跃表原理和实现
前提
有时候会被问到链表如果做到二分搜索,可能会有部分的人会去把链表中的值保存到数组来进行二分,但是如果知道跳跃表的话,那么这个数据结构就可以解决这个困惑,它允许快速查询一个有序连续元素的数据链表,它的效率可以做到和二分相同,都是O(logn)的平均时间复杂度,其空间复杂度为O(n)。
跳跃列表是在很多应用中有可能替代平衡树而作为实现方法的一种数据结构。跳跃列表的算法有同平衡树一样的渐进的预期时间边界,并且更简单、更快速和使用更少的空间。----by 发明者像是redis中有序集合就使用到了跳跃表。
原理
性质
首先,应该要了解跳跃表的性质;
- 由很多层结构组成;
- 每一层都是一个有序的链表,排列顺序为由高层到底层,都至少包含两个链表节点,分别是前面的head节点和后面的nil节点;
- 最底层的链表包含了所有的元素;
- 如果一个元素出现在某一层的链表中,那么在该层之下的链表也全都会出现(上一层的元素是当前层的元素的子集);
- 链表中的每个节点都包含两个指针,一个指向同一层的下一个链表节点,另一个指向下一层的同一个链表节点;
可以看到,这里一共有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层。
删除
在各个层中找到包含指定值的节点,然后将节点从链表中删除即可,如果删除以后只剩下头尾两个节点,则删除这一层。
- 剑指offer代码解析——面试题16反转单链表
- QMainWindow 和 QWidget 设置layout
- 安全工具Aircrack-ng的使用
- Windows Server 2008 R2 搭建微信小程序
- insert事务产生duplicate key error引发的死锁分析
- 零基础入门深度学习 | 第六章:长短时记忆网络(LSTM)
- 第6章 I/O复用:select和poll函数
- 第7章 套接字选项
- 第8章 基本UDP套接字编程
- 第11章 名字与地址转换
- explicit_defaults_for_timestamp参数导致复制中断
- 剑指offer代码解析——面试题15求链表中倒数第K个结点
- 第15章 Unix域协议
- 第13章 守护进程和inetd超级服务器
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- R语言利用基线协变量提高随机对照试验的效率
- R语言使用倾向评分提高RCT(随机对照试验)的效率
- R语言调整随机对照试验中的基线协变量
- R语言用多重插补法估算相对风险
- R语言分析协变量之间的非线性关系
- stata如何处理结构方程模型(SEM)中具有缺失值的协变量
- stata对包含协变量的模型进行缺失值多重插补分析
- 互联网直播点播平台go语言搭建重定向和反向代理的区别及使用
- UNIX时间戳和北京时间的相互转换
- R语言对苏格兰独立民意调查的Meta分析
- 案例:归档自动清理脚本失效及连带影响
- R语言中固定与随机效应Meta分析 - 效率和置信区间覆盖
- R语言使用 LOWESS技术图分析逻辑回归中的函数形式
- R语言在逻辑回归中求R square R方
- R语言Poisson回归的拟合优度检验