《Redis設計與實現》第5章 跳躍表(skiplist)

  跳躍表(skiplist)是一種有序數據結構,它通過在每個節點中維持多個指向其他節點的指針,從而達到快速訪問節點的目的。
  跳躍表支持平均O(logN)、最壞O(N)複雜度的節點查找,還可以通過順序性操作來批量處理節點。
  如果一個有序集合包含的元素數量比較多,又或者有序集合中元素的成員(member)是比較長的字符串時,Redis就會使用跳躍表來作爲有序集合鍵的底層實現。
  Redis只在兩個地方用到了跳躍表,一個是實現有序集合鍵,另一個是在集羣節點中用作內部數據結構,除此之外,跳躍表在Redis裏面沒有其他用途。

5.1 跳躍表的實現

  Redis跳躍表由redis.h/zskiplistNode和redis.h/zskiplist兩個結構定義。
zskiplistNode結構,結合圖分析:
  層(level):節點中用L1、L2、L3等字樣標記節點的各個層,L1代表第1層,L2代表第二層,以此內推。每個層還有兩個屬性:前進指針和跨度。前進指針用於訪問表尾方向的其他節點,而跨度則記錄了前進指針所指向節點和當前節點的距離。
  後退指針(backward):它指向位於當前節點的前一個節點。後退指針在程序從表尾向表頭遍歷時使用。
  分值(score):在跳躍表中,節點按各自所保留的分值從小到大排列。
  成員對象(obj):各個節點中的o1、o2和o3是節點所保存的成員對象。


這裏寫圖片描述

  注意表頭節點和其他節點的構造是一樣的:表頭節點也有後退指針、分值和成員對象,不過表頭節點的這些屬性都不會被用到,所以圖中省略了這些部分,只顯示了表頭節點的各個層。

5.1.1 跳躍表節點

1.層
  跳躍表節點的level數組可以包含多個元素,每個元素都包含一個指向其他節點的指針,程序可以通過這些層來加快訪問其他節點的速度,一般來說,層的數量越多,訪問其他節點的速度越快。
  每次創建一個新跳躍表節點的時候,程序都根據冪次定律(power law,越大的數出現的概率越小)隨機生成一個介於1和32之間的值作爲level數組的大小,這個大小就是層的“高度”。
2.前進指針
  下圖中虛線表示出了程序從表頭向表尾方向,遍歷跳躍表中所有節點的路徑:


這裏寫圖片描述

3.跨度
  層的跨度(level[i].span屬性)用於記錄兩個節點之間的距離。
  1、兩個節點之間跨度越大,它們相距的越遠;
  2、指向NULL的所有前進指針的跨度都爲0,因爲它們沒有連向任何節點。
  跨度實際上是用來排位(rank)的:在查找某個節點的過程中,將沿途訪問過的所有層的跨度累計起來,得到的結果就是目標節點在跳躍表中的排位。
  如,查找分值爲3.0,成員對象爲o3的節點時,查找的過程只經過一個層,跨度爲3。

這裏寫圖片描述

4.後退指針

這裏寫圖片描述

5.分值和成員對象
  節點的分值(score)是一個double類型的浮點數,跳躍表中的所有節點都按分值從小到大來排序。
  節點的成員對象(obj)是一個指針,它指向一個字符串對象,而字符串對象則保存着一個SDS值。
  在同一個跳躍表中,各個節點保存的成員對象必須是唯一的,但是多個節點保存的分值卻可以是相同的:分值相同的節點按照成員對象在字典序中的大小來進行排序(增序)。

這裏寫圖片描述

5.2 跳躍表

  僅靠多個跳躍表節點就可以組成一個跳躍表,但通過使用一個zskiplist結構來持有這些節點,程序可以更方便地對整個跳躍表進行處理,比如快速訪問表頭節點和表尾節點,快速獲取跳躍表節點的數量(跳躍表長度)等。

5.3 跳躍表 API


這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章