• 跳跃表的分析与实现


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

    在了解了

    Bitcask存储模型后,又開始研究LSM树存储引擎。LSM在实现的过程中使用了一个非常有意思的数据结构:跳跃表。

    之前在《算法导论公开课》中听过这一节。当时感觉这样的结构和二叉树简直是殊途同归,可是一直没有亲自己主动手实现过。这次又遇到了。就来实现试试看。话说跳跃表和各种平衡树一样,都是用来加速查询的。要随手实现一个B树不easy,可是实现一个跳跃表就简单非常多。

    跳跃表的简介

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


    分析的时候。经常使用的形状例如以下:  


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


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

    更具体的介绍,请看跳表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()
    推断表是否为空

    代码地址见上面的链接。


    欢迎光临我的站点----蝴蝶忽然的博客园----人既无名的专栏
    假设阅读本文过程中有不论什么问题,请联系作者,转载请注明出处。


  • 相关阅读:
    OS + Multipass
    服务器间文件实时双向同步(rsync+inotify)
    全链路追踪 & 性能监控工具 SkyWalking 实战
    TCP Dup ACK linux kernel 3.2
    Ns3.35 errata Compilation on Python 3.10 systems
    LeetCode 108. Convert Sorted Array to Binary Search Tree
    LeetCode 98. Validate Binary Search Tree
    LeetCode 701. Insert into a Binary Search Tree
    LeetCode 235. Lowest Common Ancestor of a Binary Search Tree
    LeetCode 783. Minimum Distance Between BST Nodes
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/6849184.html
Copyright © 2020-2023  润新知