skip list的原理

Java中的LinkedList是一种常见的链表结构,这种结构支持O(1)的随机插入及随机删除, 但它的查找复杂度比较糟糕,为O(n)。

假如我们有一个有序链表如下,如果我们想找到值为59的节点,需要查找7次。怎么提高查询效率呢?通常的做法是使用二分法,但LinkedList的随机访问时间复杂度同样为O(n),因此朴素的二分法并不适用。那怎么办呢?

我们可以在节点中增加额外的跳跃节点,如下:

这样我们可以根据跳跃节点查询,只需要查找3次。至于查询47,我们先根据跳跃节点来查询,于是在节点22上,它的跳跃指针指向55,比47要大,因此我们可以知道47可能会存在于节点22和节点55之间,这时候再根据普通的指针顺序查找。一共需要查找5次。

随着节点的增多,我们的链表结构会变成这样:

跳跃节点的密度为普通节点的一半,理想情况下,这种结构会比原结构查询性能提高一倍。有没有办法再提高呢?有,我们可以在这基础上再加一层新的跳跃节点,这层节点的密度又为第一层跳跃节点的一半。

更直观点:

进一步限定每一层的跳跃节点都由它下一层的跳跃节点中产生,因此,我们的跳跃表最终看起来像是这样的。

我们不区分每一层是原节点还是跳跃节点,将最底下的那一层节点称为第一层节点,第一层节点上面为第二层节点,然后第三层...以此类推。

这样的结构,称之为跳跃表。假设每一层的节点数为下一层的一半,那么时间复杂度为O(logn)。

实现方案

如上所述,skip list是具有分层结构的有序链表,那每一层的节点应该如何产生呢?

我们可以在新增元素的时候使用随机方法决定这个元素有几层节点。设定该元素有且只有一层节点概率为1/2,有且只有两层节点概率为1/4,有且只有三层节点概率为1/8,以此类推。然后触发随机事件,当概率为1/2的事件发生时该元素有一层节点,概率为1/2的事件发生时该元素有两层节点...另外,我们限定一个跳跃表应该具有一个最大的层数限制。

假设一个跳跃表最大层数限制为4,那么可以设定一个整数区间为[1, 2^(4-1)],即[1, 8]。然后取一个1~8的随机数,当落在[5, 8]区间时有一层节点,落在[3, 4]区间时有两层节点,落在[2, 2]区间时有三层,落在[1, 1]上时有四层。由于我们设定了跳跃表的最大层数,因此概率等式1 = 1/2 + 1/4 + 1/8 + ... + 1/2^n的最后两项相同。

Java实现

githup 代码, 见SkipList.java

跳跃表Skip List【附java实现】的更多相关文章

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

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

  2. 跳跃表Skip List的原理

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

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

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

  4. 用golang实现常用算法与数据结构——跳跃表(Skip list)

    背景 最近在学习 redis,看到redis中使用 了skip list.在网上搜索了一下发现用 golang 实现的 skip list 寥寥无几,性能和并发性也不是特别好,于是决定自己造一个并发安 ...

  5. Redis(2)——跳跃表

    一.跳跃表简介 跳跃表(skiplist)是一种随机化的数据结构,由 William Pugh 在论文<Skip lists: a probabilistic alternative to ba ...

  6. 讲讲跳跃表(Skip Lists)

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

  7. skip跳跃表的实现

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

  8. skip list跳跃表实现

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

  9. 基于跳跃表的 ConcurrentSkipListMap 内部实现(Java 8)

    我们知道 HashMap 是一种键值对形式的数据存储容器,但是它有一个缺点是,元素内部无序.由于它内部根据键的 hash 值取模表容量来得到元素的存储位置,所以整体上说 HashMap 是无序的一种容 ...

随机推荐

  1. .net开发windows服务

    最近一个月都异常的繁忙,项目进度非常的紧,回头看看自己的blog,整整一个5月都没有一篇文章,非常惭愧,现在补几篇文章,介绍一下我最近关注的技术.这篇文章将介绍Windows服务程序的开发.摘要:本文 ...

  2. 查看Jquery版本

    1. $.fn.jquery > "1.11.1" 2. 通过这样可以 判断一个对象是否是jquery对象!!

  3. corejava_chap02

    //单行注释  --不能用在一行代码的中间/**/多行注释 --任何地方/** */文档注释  文档注释用在:package.class.member variables.member method. ...

  4. c++实现的Array数据结构

    1.Array.h,Array<T>的定义 template <class T> class Array { protected: T *data; //一个指向数组数据的指针 ...

  5. Codeforces Round #286 (Div. 1) 解题报告

    A.Mr. Kitayuta, the Treasure Hunter 很显然的一个DP,30000的数据导致使用map+set会超时.题解给了一个非常实用的做法,由于每个点有不超过250种状态,并且 ...

  6. yum安装ftp服务器

    1.安装vsftp,本文采用yum安装: #yum install vsftpd 2.安装后运行: # service vsftpd restart Shutting downvsftpd:      ...

  7. phpcms V9利用num++实现多样形式列表标签调用

    在首页或者频道页调用文章列表的时候,经常会使用到左右对称或者每五行出现一条横线的调用形式. 其实代码很简单,利用num++的循环方式,以及{if}{/if}进行样式判断即可.代码如下: {pc:con ...

  8. mysql数据类型——枚举enum(‘F’,'M')

    ENUM(“value1”,“value2”,...) 说明:枚举,列值可赋予值列表中的某个成员 允许的属性:除通用属性外无其他属性 缺省值:如果列可为NULL,则为NULL:如果列为NOTNULL, ...

  9. Fatal error: Class 'ZipArchive' not found的解决办法

    今天在Linux底下编写导出EXCEL文件并显示输出时,抛出“ZipArchive library is not enabled” 的异常.而我在本地的windows下的代码则是运行正常的. 原因是: ...

  10. thinkphp微信开发之jssdk图片上传并下载到本地服务器

    public function test2(){ $Weixin = new \Weixin\Controller\BaseController(); $this->assign('signPa ...