skiplistジャンプテーブル

ジャンプテーブルは何ですか?

  SkipListが広くleveldb、Redisのとlucenceで使用される、データ構造がより効率的です。そのコードのシンプルさと原則の実現のため、より許容できます。私たちは、まず、それがジャンプテーブルと呼ばれている理由SkipList、の定義を見て?

  「スキップリストは、確率的均衡ではなく、厳密に施行バランシングを使用するデータ構造です。その結果、スキップリストの挿入や削除のためのアルゴリズムは、はるかに簡単かつバランスの取れた木のための同等のアルゴリズムよりも大幅に高速です。

  翻訳:ノードを挿入および削除するため、確率的バランシング技術の代わりに、バランスの取れた義務を使ってジャンプテーブルは、伝統的なバランスの取れたツリーアルゴリズムよりシンプルかつ効率的です。 

ジャンプテーブルを理解します

 ソートされたリストを検索:順序付きリストを考えてみましょう

      

 

  順序付けられたリストの検索要素<23、43、59>から、必要な比較の数が<2,4,6>た、合計回数は、比較は、2 + 4 + 6 = 12倍です。そこリストが順番にある?何の最適化アルゴリズムは行いませんですが、バイナリ検索を使用することはできません。同様のバイナリ検索ツリーは、我々はインデックスとしていくつかのノードを展開します。次の構造を取得します。

         

 

  インデックスとして抽出し、その検索は、比較の回数を減らすことができるとき。 
 私たちは、その後、二次、三次インデックスとして、インデックスをインデックスからいくつかの要素を抽出することができます... 

           

 ここでは多くの要素は、要素の十分な数の、このようなインデックス構造は、ここでの利点を反映することができれば、利点を反映していません。

ジャンプ台

 以下の構造は、ジャンプテーブルである: 
 -1最小INT_MIN、リンクされたリストを表し、INT_MAX 1は最大値、リンクされたリストを表します。

               

 ジャンプテーブルは、以下の特性を有する:
  (1)多くの層からなる構造は、
  (2)各層が順序付けられたリストである
  (3)最低レベル(レベル1)は、すべての要素のリンクリスト含ま
  要素のレベルが表示された場合(4)私のリストで、その下のリストには、レベルIに表示されます。
  (5)各ノードは二つのポインタ、同じリスト内の次の要素へのポインタ、次の要素のいずれかへのポインタを含みます。

検索ジャンプテーブル

              

 

 例:検索要素117
  背面に見て21未満(1)21比較大きく、
  層を探し始めることが37以下から、リストの最大値よりも少ない、37よりも大きい(2)37比較、
  71より(3)71比較大、71以下の層を探し始めるには、リストの最大値よりも小さい
  (4)比較85は、85よりも大きいが、後ろから見て
  (5)比較117を、ノードを見つけるために、117に等しいです。

次のように特定の検索アルゴリズムは次のとおりです。

/ * xが存在する場合、ここでノードXに返す
 *そうでなければ後続ノードX * /   
(X)検索    
{   
    P = トップ、  
     しばらく1 ){  
         一方(P->ネクスト>キー< X)   
            P = P - > 次に、  
         IF(P-> ==ダウンNULL)   
             戻り P-> 次に、   
        P = P-> ダウン;   
    }   
}

ジャンプテーブルを挿入

 最初の(完全で失われた硬貨の方法によってKによって占有される要素の層の数を決定ランダムにある) 
 、次いでレベル1 ...レベルK個々の層は、要素のリスト内に挿入されます。 
 例:挿入119、K = 2 

             

 

 Kは、リストの層数よりも大きい場合、誰が新しいレイヤーを追加したいです。 
 例:挿入119、K = 4 

             

 

 丢硬币决定 K 
 插入元素的时候,元素所占有的层数完全是随机的,通过一下随机算法产生: 

int random_level()  
{  
    K = 1;  

    while (random(0,1))  
        K++;  

    return K;  
} 

 

  相当与做一次丢硬币的实验,如果遇到正面,继续丢,遇到反面,则停止,
  用实验中丢硬币的次数 K 作为元素占有的层数。显然随机变量 K 满足参数为 p = 1/2 的几何分布,
  K 的期望值 E[K] = 1/p = 2. 就是说,各个元素的层数,期望值是 2 层。

  跳表的高度。
    n 个元素的跳表,每个元素插入的时候都要做一次实验,用来决定元素占据的层数 K, 跳表的高度等于这 n 次实验中产生的最大 K,待续。。。
  

  跳表的空间复杂度分析
    根据上面的分析,每个元素的期望高度为 2, 一个大小为 n 的跳表,其节点数目的期望值是 2n。

跳表的删除
 在各个层中找到包含 x 的节点,使用标准的 delete from list 方法删除该节点。
 例子:删除 71


               

 

skiplist与平衡树、哈希表的比较

  • skiplist和各种平衡树(如AVL、红黑树等)的元素是有序排列的,而哈希表不是有序的。因此,在哈希表上只能做单个key的查找,不适宜做范围查找。所谓范围查找,指的是查找那些大小在指定的两个值之间的所有节点。
  • 在做范围查找的时候,平衡树比skiplist操作要复杂。在平衡树上,我们找到指定范围的小值之后,还需要以中序遍历的顺序继续寻找其它不超过大值的节点。如果不对平衡树进行一定的改造,这里的中序遍历并不容易实现。而在skiplist上进行范围查找就非常简单,只需要在找到小值之后,对第1层链表进行若干步的遍历就可以实现。
  • 平衡树的插入和删除操作可能引发子树的调整,逻辑复杂,而skiplist的插入和删除只需要修改相邻节点的指针,操作简单又快速。
  • 从内存占用上来说,skiplist比平衡树更灵活一些。一般来说,平衡树每个节点包含2个指针(分别指向左右子树),而skiplist每个节点包含的指针数目平均为1/(1-p),具体取决于参数p的大小。如果像Redis里的实现一样,取p=1/4,那么平均每个节点包含1.33个指针,比平衡树更有优势。
  • 查找单个key,skiplist和平衡树的时间复杂度都为O(log n),大体相当;而哈希表在保持较低的哈希值冲突概率的前提下,查找时间复杂度接近O(1),性能更高一些。所以我们平常使用的各种Map或dictionary结构,大都是基于哈希表实现的。
  • 从算法实现难度上来比较,skiplist比平衡树要简单得多。

 

Redis为什么用skiplist而不用平衡树?

There are a few reasons:

1) They are not very memory intensive. It’s up to you basically. Changing parameters about the probability of a node to have a given number of levels 
will make then less memory intensive than btrees.

2) A sorted set is often target of many ZRANGE or ZREVRANGE operations, that is, traversing the skip list as a linked list. With this operation the cache 
locality of skip lists is at least as good as with other kind of balanced trees.

3) They are simpler to implement, debug, and so forth. For instance thanks to the skip list simplicity I received a patch (already in Redis master) 
with augmented skip lists implementing ZRANK in O(log(N)). It required little changes to the code.

  这里从内存占用、对范围查找的支持实现难易程度这三方面总结的原因。  

 

 

资料出处:https://blog.csdn.net/u014427196/article/details/52454462

 

おすすめ

転載: www.cnblogs.com/myseries/p/11442335.html