记下自己对跳表SkipList的理解。

SkipList采用空间换时间的思想,通过增加数据间的链接,达到加快查找速度的目的。

数据库LevelDB和RocksDB中用到了SkipList,Redis中的有序set即zset也用到了SkipList。Java中也提供了ConcurrentSkipListMap,在并发量大的情况下,ConcurrentSkipListMap性能好。

先看SkipList的查找过程,引用网上的经典图片,查找19。注意的是数据是有序的。

查找的过程从上至下,查找指针所经历的位置顺序如图中的1,2,3,直到找到目标数据19。

再加一张图,是怎么二分法查找的。

   SkipList中创建新结点时,产生一个在1~MAX_LEVEL之间的随机level值作为该结点的level。每个节点的高度是随机的。

MAX_LEVEL可以静态指定,也可以动态增长。

关于MAX_LEVEL,觉得这篇文章的解释是比较清楚的:https://blog.csdn.net/kisimple/article/details/38706729。下面是复制了部分的内容

   每个节点所能reach到的最远的节点是随机的,正如作者所说,SkipList使用的是概率平衡而不是强制平衡。

  O(logN)?

   既然是随机算法,那怎么能保证O(logN)的复杂度?SkipList作者在论文中有给出了说明,这里从另一个角度说下我的理解。先定义一下,A node that has k forward pointers is called a level k node。假设k层节点的数量是k+1层节点的P倍,那么其实这个SkipList可以看成是一棵平衡的P叉树,从最顶层开始查找某个节点需要的时间是O(logpN),which is O(logN) when p is a constant。

  下面看下Redis与LevelDB中实现SkipList所使用的随机算法。

  Redis

     在t_zset.c中找到了redis使用的随机算法。

/* 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) {
int level = ;
while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
level += ;
return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

    执行level += 1;的概率为ZSKIPLIST_P,也就是说k层节点的数量是k+1层节点的1/ZSKIPLIST_P倍。ZSKIPLIST_P(这个P是作者论文中的p)与ZSKIPLIST_MAXLEVELredis.h中定义,

#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
#define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */

    所以redis中的SkipList相当于是一棵四叉树。

  LevelDB

    在skiplist.h中找到了LevelDB使用的随机算法。

template<typename Key, class Comparator>
int SkipList<Key,Comparator>::RandomHeight() {
// Increase height with probability 1 in kBranching
static const unsigned int kBranching = ;
int height = ;
while (height < kMaxHeight && ((rnd_.Next() % kBranching) == )) {
height++;
}
assert(height > );
assert(height <= kMaxHeight);
return height;
}

  (rnd_.Next() % kBranching) == 0)的概率为1/kBranching,所以LevelDB中的SkipList也是一棵四叉树(kBranching = 4;不就是这个意思吗^_^)。

SkipList理解的更多相关文章

  1. 深入理解Redis:底层数据结构

    简介 redis[1]是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorte ...

  2. 浅析SkipList跳跃表原理及代码实现

    本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈“跳跃表”的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代 ...

  3. skiplist 跳表(2)-----细心学习

    快速了解skiplist请看:skiplist 跳表(1) http://blog.sina.com.cn/s/blog_693f08470101n2lv.html 本周我要介绍的数据结构,是我非常非 ...

  4. redis skiplist (跳跃表)

    redis skiplist (跳跃表) 概述 redis skiplist 是有序的, 按照分值大小排序 节点中存储多个指向其他节点的指针 结构 zskiplist 结构 // 跳跃表 typede ...

  5. 深夜学算法之SkipList:让链表飞

    1. 前言 上次写Python操作LevelDB时提到过,有机会要实现下SkipList.摘录下wiki介绍: 跳跃列表是一种随机化数据结构,基于并联的链表,其效率可比拟二叉查找树. 我们知道对于有序 ...

  6. Redis数据结构之skiplist(续)

    本文摘抄于<Redis内部数据结构详解-skiplist> 一.skiplist的由来 skiplist,顾名思义,首先它是一个list.实际上,它是在有序链表的基础上发展起来的. 我们先 ...

  7. leveldb学习:skiplist

    leveldb中的memtable仅仅是一个封装类,它的底层实现是一个跳表. 跳表是一种基于随机数的平衡数据结构.其它的平衡数据结构还有红黑树.AVL树.但跳表的原理比它们简单非常多.跳表有点像链表, ...

  8. 深入理解跳表在Redis中的应用

    本文首发于:深入理解跳表在Redis中的应用微信公众号:后端技术指南针持续输出干货 欢迎关注 前面写了一篇关于跳表基本原理和特性的文章,本次继续介绍跳表的概率平衡和工程实现, 跳表在Redis.Lev ...

  9. 深入理解跳跃链表在Redis中的应用

    0.前言 前面写了一篇关于跳表基本原理和特性的文章,本次继续介绍跳表的概率平衡和工程实现,跳表在Redis.LevelDB.ES中都有应用,本文以Redis为工程蓝本,分析跳表在Redis中的工程实现 ...

随机推荐

  1. 《DSP using MATLAB》Problem 6.13

    代码: %% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %% Output In ...

  2. MySQL--线程池(Thread Pool)

    ================================================================= 线程池技术 在MySQL社区版中,MySQL使用one-thread ...

  3. 线性代数及其应用 (David C.Lay, Steven R.Lay 著)

    第1章 线性代数中的线性方程组 (已看) 介绍性实例 经济学与工程中的线性模型 1.1 线性方程组 1.2 行化简与阶梯形矩阵 1.3 向量方程 1.4 矩阵方程Ax=b 1.5 线性方程组的解集 1 ...

  4. 学习笔记:Javascript 变量 包装对象

    学习笔记:Javascript 变量 包装对象 如下代码,可以输出字符的长度. var str = "Tony"; str.length; 这时再试试以下代码,返回是 undefi ...

  5. 用C语言解决python多线程中的GIL问题

    在使用python多线程的时候为了解决GIL问题,有些代码得用C语言写,那么就得生成动态链接库. 当创建动态链接库时,独立位置信息(position independent)代码也需要生成.这可以帮助 ...

  6. JVisualVM监控本地Java进程

    一.基于JVisualVM的可视化监控 1.打开C:\Program Files\Java\jdk1.8.0_131\bin下的jvisualvm.exe 2.打开后,会列出本机所有的Java进程 3 ...

  7. tornado输入-get_query_argument()等 笔记

    最外面的代码结构 import tornado.web import tornado.ioloop import tornado.options import tornado.httpserver f ...

  8. C++Builder XE7 up1 简单测试

    很久没用BCB了, 新装了BCBXE7up1试试了,发现有点找不到北了,好像与BCB6的一些默认设置项不一样,编译了一个空APP,提示找不到bpl 和 dll. 设置为不带包编译后,还是提示DLL找不 ...

  9. 如何使用Hanlp加载大字典

        问题 因为需要加载一个 近 1G 的字典到Hanlp中,一开始使用了CustomDictionay.add() 方法来一条条的加载,果然到了中间,维护DoubleArraTre 的成本太高,添 ...

  10. 浏览器实现PDF预览

    1.使用jquery.media.js预览PDF <!DOCTYPE html> <html> <head> <meta charset="utf- ...