跳跃表的分析与实现

简介: ----《大规模分布式存储系统:原理解析与架构实战》读书笔记 在了解了 Bitcask存储模型后,又开始研究LSM树存储引擎。LSM在实现的过程中使用了一个很有意思的数据结构:跳跃表。之前在《算法导论公开课》中听过这一节。当时感觉这种结构和二叉树简直是殊途同归,但是一直没有亲自动手实现过。这次又遇到了,就来实现试试看。话说跳跃表和各种平衡树一样,都是用来加速

----《大规模分布式存储系统:原理解析与架构实战》读书笔记

在了解了

Bitcask存储模型后,又开始研究LSM树存储引擎。LSM在实现的过程中使用了一个很有意思的数据结构:跳跃表。之前在《算法导论公开课》中听过这一节。当时感觉这种结构和二叉树简直是殊途同归,但是一直没有亲自动手实现过。这次又遇到了,就来实现试试看。话说跳跃表和各种平衡树一样,都是用来加速查询的。要随手实现一个B树不容易,但是实现一个跳跃表就简单很多。

跳跃表的简单介绍

跳跃列表一个有序链表,按层建造的。底层是一个普通的有序链表。每个更高层都充当下面列表的"快速跑道",查找一个元素时,可以先通过高层的“快车道”,在快车道上找不到时,从最接近目标元素的快车道逐步进入慢车道,直到最后找的目标元素。
分析的时候,常用的形状如下:  


各层是完全分开的列表。但是在实际实现中,则使用的为如下结构:


这种方式将多条联表的值合并到一起,同时使用指针来构造高层"快车道"。这种方式管理起来简单,节省空间。

更详细的介绍,请看跳表SkipList

跳跃表的复杂度分析以及概率因子p

来看看跳跃表的复杂度分析:

  • 空间复杂度: O(n) (期望)
  • 跳跃表高度: O(logn) (期望)

相关操作的时间复杂度:

  • 查找: O(logn) (期望)
  • 插入: O(logn) (期望)
  • 删除: O(logn) (期望)

跳跃表的操作时间负责度是基于概率的,所有加上了期望。
在层 i 中的元素按某个固定的概率 p 出现在层 i+1 中。当p=1/2或者1/e的时候查找的性能最好。

更详细的对比,请看到这篇文章:跳跃表,当中对不同概率的P对查询性能的影响做了对比。

跳跃表的高度

实际使用时,如果高度太高,会造成空间浪费,我们要做一个空间和时间的平衡。那么跳跃表的高度多少最合适?
假设跳跃表中的元素个数为N,当跳跃表的高度为log(N)时,跳跃表进化为一个二叉树结构,其查询次数与二分查找法一致。这无疑最理想的结果。

如果有一亿条记录,高度log(N)约等于30。redis中,最大高度也就是32,最多可以存几亿条记录。通常,我们用不了这么多记录。所以高度可以降低一点。

跳跃表的实现

跳跃表在levledb和redis中均有实现。二者都是用C实现的。我这个实现是C++版本的

主要特点为:

  • 支持模板
  • 0.2版本增加了对迭代器和反向迭代器的支持
  • 可自定义高度,默认为8,0.2版本版本改为了16
    因为高度为8的话适合几百条的记录,这时候,选用跳跃表并没有太多优势,不如之间使用排序数组。将默认值改为16的话,可以方便几万条记录大小的地方使用。
  • 概率p:暂时使用p=1/2
  • 做过单元测试,放心使用啦

初始版本简单直接,支持的函数为insert,find,remove。不支持范围操作。0.2版本增了对了迭代器的支持。
另外,在实现的时候也遇到一些问题,要注意模板编程与平时编程有所不同,平时编程通常实现和定义分离,分别放在.cpp和.h中。但是模板编程编写的通常是没有具现的实现,为了方便,一般定义和实现都会放在.h文件中。

初始版本简单直接,支持的函数为insert,find,remove。不再介绍。下面是0.2版本实现的函数及其功能:
void insert(const_value_type &value)
在当前表中插入value值。值可以重复。
void remove(const_value_type &value)
删除第一个值为value的元素。重复值需要多次删除
void clear()
清空跳跃表
iterator find(const_value_type &value)
返回第一个值为value的元素的迭代器,否则返回end.
iterator begin(int level = 0)
返回指向当前表中第level层的第一个元素的迭代器。使用begin的时候,可以指定遍历不同的层,默认为最底层。这个实际上并不是标准的迭代器,为了实现分层遍历进行了特化。
iterator end() const
返回指向当前表中最后一个元素的迭代器。
iterator rbegin() const
返回指向当前表中最后一个元素的反向迭代器。
iterator rend() const
返回指向表中第一个元素的反向迭代器。
unsigned long size()
返回当前表中元素的数目
unsigned int level()
返回当前表的总层数
unsigned int maxlevel()
返回当前表的能使用的最大层数
bool empty()
判断表是否为空

代码地址见上面的链接。


欢迎光临我的网站----蝴蝶忽然的博客园----人既无名的专栏
如果阅读本文过程中有任何问题,请联系作者,转载请注明出处!


相关文章
|
存储
链表的总体涵盖以及无哨兵位单链表实现——【数据结构】
链表的总体涵盖以及无哨兵位单链表实现——【数据结构】
84 0
数据结构——二叉搜索树与KV模型(上)
数据结构——二叉搜索树与KV模型(上)
|
存储 算法
数据结构和算法之图的遍历
6.2 图的遍历 6.2.1 图的遍历——DFS 遍历:把图里面每个顶点都访问一遍而且不能有重复的访问 深度优先搜索(DFS) 当访问完了一个节点所有的灯后,一定原路返回对应着堆栈的出栈入栈的一个行为 深度优先搜索的算法描述 void DFS(Vertex V)//从迷宫的节点出来 { visited[V] = true;//给每个节点一个变量,true相当于灯亮了,false则是熄灭状态 for(V的每个邻接点W)//视野看得到的灯 if(!visited[W])//检测是否还有没点亮的 DFS(W);//递归调用 } //类似树的先序遍历 若有N个顶点、E条边,时间复杂度是 用邻
120 0
数据结构146-二叉搜索树-删除操作分析
数据结构146-二叉搜索树-删除操作分析
52 0
数据结构146-二叉搜索树-删除操作分析
|
存储 缓存 算法
常见数据结构-散列表(下)散列表和链表的组合
常见数据结构-散列表(下)散列表和链表的组合
146 0
|
机器学习/深度学习 数据格式
数据结构(荣誉)实验二 跳表 Trie树
数据结构(荣誉)实验二 跳表 Trie树
77 0
数据结构(荣誉)实验二 跳表 Trie树
|
算法 Go 数据库
数据结构和算法-单链表的有序插入|学习笔记
快速学习数据结构和算法-单链表的有序插入
174 0
数据结构和算法-单链表的有序插入|学习笔记
|
存储 算法
数据结构 查找 静态查找表算法 折半查找 二叉排序树查找算法 实验报告
数据结构 查找 静态查找表算法 折半查找 二叉排序树查找算法 实验报告
121 0
数据结构 查找 静态查找表算法 折半查找 二叉排序树查找算法 实验报告
|
NoSQL Redis
跳跃表介绍
有序集合在生活中比较常见,例如根据成绩对学生排名,根据得分对玩家排名等。对于有序集合的底层实现,可以用数组、平衡树、链表等。数组不便元素的插入、删除;平衡树或红黑树虽然效率高但结构复杂;链表查询需要遍历所有效率低。
跳跃表介绍