附William Pugh的论文 Skip Lists: A Probabilistic Alternative to Balanced Trees

写在前面

以下内容针对的是Skip List的插入和删除,建议你先到其他地方大概了解一下Skip List长什么样子的,然后再过来看看这篇,最好还是看一眼论文先,部分挺容易看懂的。Redis中的Sorted Set基本就是使用Skip List,只是稍作修改。


初识 Skip List

Skip List 是一种数据结构,实质上为一个链表,专门用于存储有序元素,提供的查找速度可与平衡二叉树媲美,优点是实现简单。

论文中Skip List就是长上面这样的,每个节点有多个forward指针,指向在其后面的元素。将forward指针分层,称为level,level为1的那层就是单纯的有序单链表,随着层次递增,元素会越来越少。比如level的取值范围可以是[1, 32]


Skip List 的插入

先快速看一眼下面翻译过来的伪码实现。

void Insert(list, searchKey, newValue)
{
local update[1..MaxLevel];
x = list->header;
// 查找searchKey应存放的位置
for(i = list->level to 1)
{
while(x->forward[i]->key < searchKey)
x = x->forward[i];
// 位置关系: x->key < searchKey <= x->forward[i]->key
update[i] = x; // 看上行注释便知update保存的是什么
}
x = x->forward[1]; // 这在最低层
if(x->key == searchKey)
{
// 已有相同的key,替换即可
x->value = newValue;
}
else
{
lv = randomLevel(); // 为新节点随机取个level
if(lv > list->level) // 特殊处理:新节点level比当前最大level高
{
for(i = list->level+1 to lv)
update[i] = list->header;
list->level = lv;
}
x = createNode(v, searchKey, newValue);
for(i = 1 to lv) // 调整相关指针
{
x->forward[i] = update[i]->forward[i];
update[i]->forward[i] = x;
}
}
}

实现原理是,用一个update数组保存"最大且小于searchKey的元素",用它来调整涉及到的指针指向。搜索时从高层往低层搜索,顺便记录update数组,调整指针时从低层往高层调整。可能出现的情况是,新节点的level大于原来list的最大level,此时需要更新一下list的最大level。

randomLevel()比较容易实现,就是抛硬币法,有概率性,越高的level出现频率越低,因为不能直接一下子就返回过大的数字。返回一个数字n表示抛了n+1次才出现反面,但要求n<=MaxLevel。这种取level的方式很巧妙。


Skip List 的删除

void Delete(list, searchKey)
{
int update[1..MaxLevel];
x = list->header;
// 查找searchKey的存放位置
for(i = list->level to 1)
{
while(x->forward[i]->key < searchKey)
x = x->forward[i];
update[i] = x;
}
x = x->forward[i];
if(x->key == searchKey) // 若命中,则删
{
// 调整指向x的指针
for(i = 1 to list->level)
{
if(update[i]->forward[i] != x) break;
update[i]->forward[i] = x->forward[i]
}
free(x);
// 可能需要更新list的max level
while(list->level > 1 && !list->header->forward[list->level])
list->level = list->level - 1;
}
}

看过Insert之后,这个不用解释也能看懂了。

探索Skip List (跳跃表)的更多相关文章

  1. skip list跳跃表实现

    跳表(skip List)是一种随机化的数据结构,基于并联的链表,实现简单,插入.删除.查找的复杂度均为O(logN).跳表的具体定义,跳表是由William Pugh发明的,这位确实是个大牛,搞出一 ...

  2. 探索c#之跳跃表(SkipList)

    阅读目录: 基本介绍 算法思想 演化步骤 实现细节 总结 基本介绍 SkipList是William Pugh在1990年提出的,它是一种可替代平衡树的数据结构. SkipList在实现上相对比较简单 ...

  3. 跳跃表Skip List的原理和实现

    >>二分查找和AVL树查找 二分查找要求元素可以随机访问,所以决定了需要把元素存储在连续内存.这样查找确实很快,但是插入和删除元素的时候,为了保证元素的有序性,就需要大量的移动元素了.如果 ...

  4. skip跳跃表的实现

    skiplist介绍 跳表(skip List)是一种随机化的数据结构,基于并联的链表,实现简单,插入.删除.查找的复杂度均为O(logN).跳表的具体定义, 跳表是由William Pugh发明的, ...

  5. 跳跃表Skip List【附java实现】

    skip list的原理 Java中的LinkedList是一种常见的链表结构,这种结构支持O(1)的随机插入及随机删除, 但它的查找复杂度比较糟糕,为O(n). 假如我们有一个有序链表如下,如果我们 ...

  6. 数据结构与算法(c++)——跳跃表(skip list)

    今天要介绍一个这样的数据结构: 单向链接 有序保存 支持添加.删除和检索操作 链表的元素查询接近线性时间 ——跳跃表 Skip List 一.普通链表 对于普通链接来说,越靠前的节点检索的时间花费越低 ...

  7. 讲讲跳跃表(Skip Lists)

    跳跃表(Skip Lists)是一种有序的数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的.在大部分情况下,跳跃表的效率可以和平衡树相媲美,并且在实现上比平衡树要更为 ...

  8. 跳跃表Skip List的原理

    1.二分查找和AVL树查找 二分查找要求元素可以随机访问,所以决定了需要把元素存储在连续内存.这样查找确实很快,但是插入和删除元素的时候,为了保证元素的有序性,就需要大量的移动元素了.如果需要的是一个 ...

  9. Skip List(跳跃表)原理详解与实现【转】

    转自:http://dsqiu.iteye.com/blog/1705530 Skip List(跳跃表)原理详解与实现 本文内容框架: §1 Skip List 介绍 §2 Skip List 定义 ...

随机推荐

  1. 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_类型的各种成员

    [Class中,可能包含的成员] 常量, 字段, 实例构造器, 类型构造器, 方法, 操作符重载, 转换操作符, 属性, 事件, 类型(Class)

  2. P3225 [HNOI2012]矿场搭建

    传送门 对于一个点双联通分量,如果它连接了两个或更多割点 那么不论哪个点GG都有至少一条路通到其他的点双联通分量,所以我们不用考虑 如果它只连接一个割点,如果这个割点GG,那整个块也一起GG,所以要再 ...

  3. Java 初始化和清理

    初始化和清理是影响代码安全的两个重要因素. 一.初始化 1. 方法重载 构造器与类名相同,成为强制重载方法名的原因之一.重载规则:每个重载的方法必须拥有独一无二的参数类型列表.不能根据返回值来区分重载 ...

  4. .Net默认IE版本号的两种方式

    1.直接在页面的header部位meta标签中加入如下代码 <meta http-equiv="X-UA-Compatible" content="IE=8&quo ...

  5. 从零开始使用vue-cli搭建一个vue项目及注意事项

    一.安装node.js 1.根据电脑的自行下载node.js安装包http://nodejs.cn 2.点击安装,按照正常的的一路点击下去 3.验证安装是否成功,按键win+r,输入cmd打开命令行工 ...

  6. MySQL 0 学习

    ubuntu  安装mysql  创建用户  以及外部如何可视化连接的   方法   https://www.linuxidc.com/Linux/2017-01/139502.htm 2.3 MyS ...

  7. 2019.03.19 读书笔记 string与stringbuilder的性能

    1 string与stringbuilder 并不是stringbuilder任何时候都在性能上占优势,在少量(大约个位数)的字符串时,并不比普通string操作快. string慢的原因不是stri ...

  8. javascript判断input框只能输入数字的方法

    javascript 只允许输入数字有很多方法,总结如下 1,只允许输入数字和小数点. <input onKeypress="return (/[\d.]/.test(String.f ...

  9. 初识contiki(2.7版本)

    一个偶然的机会,我接触到了contiki这个家伙. Contiki 是一个开源的.高度可移植的.采用 C 语言开发的非常小型的嵌入式操作系统,针对小内存微控制器设计,适用于联网嵌入式系统和无线传感器网 ...

  10. mysql java 通用AES加密

    最近有个需求,需要对数据库某些字段加密,调研发现采用AES加密的方式较多,而且反向解密速度快,符合需求,于是采用:下面是遇到的问题及相关代码 首先第一个问题,AES的秘钥是16位,mysql的密码长度 ...