Redis使用跳躍表作為有序集合鍵的的底層實現,如果一個有序集合包含的元素數量比較多,又或者有序集合中元素的成員是比較長的字符串時Redis就會使用跳躍表
來作為有序集合鍵的底層實現
Redis只在兩個地方用到了跳躍表,一個是實現有序集合鍵,另一個是在集群節點中用作內部數據結構
跳躍表的數據結構為

header :指向跳躍表的表頭節點 tail :指向跳躍表的表尾節點 level記錄目前跳躍表內層數最大的那個節點的層數(表頭除外)
獲取表頭和表尾時間復雜度為O(1)
length :記錄跳躍表的長度跳躍表目前包含節點的數量(表頭除外),獲取有序集合的時間復雜度為O(1)
將包含給定成員和分值的新節點添加到跳躍表中 平均O(logN) 最壞O(N)
刪除跳躍表中包含給定成員和分值的節點 平均O(logN) 最壞O(N)
返回包含給定成員和分值的節點在跳躍表中的排位 平均O(logN) 最壞O(N)
返回跳躍表在給定排位上的節點 平均O(logN) 最壞O(N)
跳躍表節點的數據結構為

跳躍表節點的level數組可以包含多個level,每個level都帶有兩個屬性:前進指針和跨度 前進指針用於訪問位於表尾方向的其他節點,跨度記錄了前進指針所指向節點和當前節點的距離。
兩個節點之間的跨度越大,它們相距的就越遠
指向NULL的所有前進指針的跨度都為0(沒有連向任何節點) 跨度實際上是用來計算排位(rank)的在查找節點的過程中將沿途訪問過的所有層的跨度累計起來得到的結果就是目標節點在跳躍表中的排位
當程序從表頭向表尾進行遍歷時訪問會沿着層的前進指針進行。
backward 后退指針它指向位於當前節點的前一個節點后退指針在程序從表尾向表頭遍歷 節點的后退指針和一次跳過多個節點的前進指針不同,因為每個節點只有一個后退指針,所以每次只能后退至前一個節點。
score 分值 在節點中所保存的分值 在跳躍表中節點按各自所保存的分值從小到大排序
obj 各個節點中所保存的成員對象 obj 是一個指針它指向一個字符串對象,而字符串對象保存一個SDS 在同一個跳躍表中各個節點的成員對象必須是唯一的但是多個節點保存的分值可以是相同的分值相同的節點按照成員對象在字典
序中的大小來進行排序成員對象較小的節點會排在前面成員對象較大的節點則會排在后面
表頭節點和其他節點的構造是一樣的表頭節點也有后退指針、分值和成員對象,不過表頭節點的這些屬性都不會被用到
下圖為完整的跳躍表

程序可以通過這些層來加快訪問其他節點的速度,一般來說層的數量越多訪問其他節點的速度就越快
每次創建一個新跳躍表節點的時候,程序都根據冪次定律隨機生成一個介於1和32之間的值作為level數組的大小,這個大小就是層的高度
遍歷下圖的跳躍表

程序首先訪問跳躍表的第一個節點(header節點),然后從第四層的前進指針移動到表中的第二個節點(第二個節點先指向L4 L4的forward指針指向L2)
在第二節點時,程序沿着第二層的前進指針移到表中的第三個節點
在第三個節點時程序同樣沿着第二層的前進指針移動到表中的第四個節點
當程序再次沿着第四個節點的前進指針移動時,它碰到一個null,程序知道這時已經到達了跳躍表的表尾,於是結束這次遍歷。
