zoukankan      html  css  js  c++  java
  • SkipList理解

      记下自己对跳表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 = 1;
        while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
            level += 1;
        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 = 4;
      int height = 1;
      while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) {
        height++;
      }
      assert(height > 0);
      assert(height <= kMaxHeight);
      return height;
    }

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

                

  • 相关阅读:
    IDEA 删除java类的3种提示
    IDEA类和方法注释模板设置(非常详细)
    IntelliJ IDEA 2019,从入门到疯狂,图文教程
    intellij idea 如何将普通项目转换为maven项目
    使用idea误点 Add as Ant Build File选项后
    idea使用"svn"到项目报错Error:Cannot run program "svn" (in directory "E:XXXXXX"):CreateProcess error=2,
    Alertmanager 部署配置
    Prometheus PromQL 简单用法
    Prometheus PromQL 基础
    Prometheus 自动发现
  • 原文地址:https://www.cnblogs.com/lnlvinso/p/8848883.html
Copyright © 2011-2022 走看看