【Redis】14. 跳躍表(SkipList) — 爲什麼 Redis 使用跳躍表來實現有序集合(Sorted Set)而不是紅黑樹或者平衡二叉樹呢?

Redis 的有序集合(Sorted Set)就是用跳錶來實現的。跳躍表是一種隨機化的數據結構。我們可以把他看做 Java 中 SortedSet 和HashMap 的結合體,set 保證了value 值就有唯一性,且可以保證每一個value 有一個自己的權重值 socre ,用socre 達到排序的目的。

問題

一個單鏈表的結構無論是不是有序的,遍歷都是從頭到尾進行遍歷,時間複雜度爲 O(n),有的人說了,用二分法,二分法是針對數組進行查找的一種方法,而鏈表不可以,鏈表邏輯上是連續的,物理存儲上是不連續的。數組不支持隨機的插入和刪除,所以我們選擇採用鏈表的形式。那有沒有一種可以提高有序鏈表查詢效率的方法。—— 加索引

什麼是跳錶

不加索引 如果不加索引,我們找18這個節點,則需要遍歷12個節點後纔可以找到。
在這裏插入圖片描述
添加一級索引 :我們先遍歷一級索引,則只需要遍歷8個節點後就可以找到。
在這裏插入圖片描述
添加二級索引:我們需要先遍歷二級索引,在遍歷一級索引,最終只需要 遍歷7個節點
在這裏插入圖片描述
對有序鏈表加了多級索引的結構,就是跳錶,我們通過加索引,減少了查詢的次數,提高到了查詢效率。

此時問題來了,加索引的間隔是多少呢?上述鏈表中每隔兩個節點建一個索引,頂級索引是有兩個結點的,加入鏈表長度爲 n ,一級索引長度爲 n/2,二級索引長度爲 n/4,三級索引長度爲n/8,k 級索引長度n/(2^k),頂級索引長度爲2,索引總長度爲它們之和,則空間複雜度爲O(n),跳錶的高度爲 O(logn)。

有序鏈表加了索引就是跳錶,它實際上用到了一種空間換時間的思想,其實我們無需考慮這些額外的額空間。

跳錶更新

跳錶可以實現動態的插入和刪除,有一種這樣的插入情況,在兩個節點之間插入了大量的數據,此時跳錶退化爲單鏈表,那跳錶是如何維護自己的平衡性的呢?— 隨機函數
在這裏插入圖片描述
隨機函數爲2,則可以對該數據插入第一級和第二級索引。就是增加數據的時候,適當的增加索引。

爲什麼 redis 實現有序集合不用紅黑樹或者平衡二叉樹呢?

  • 在實現方面,紅黑樹實現更加複雜,跳躍表實現比較簡單,也更加直觀,更加靈活。
  • 跳錶區間查找數據的效率更高一些。
  • 紅黑樹/平衡二叉樹這種樹形結構,每次每隔兩個節點建一個索引,而跳躍表可以多個節點,不限於兩個節點。
  • 跳躍表插入或刪除操作只需要修改節點前後的指針,而不需要對多個節點都進行調整,而平衡二叉樹則需要左旋或者右旋實現平衡。
  • 從內存佔用上來說,skiplist比平衡樹更靈活一些。一般來說,平衡樹每個節點包含2個指針(分別指向左右子樹),而skiplist每個節點包含的指針數目平均爲1/(1-p),具體取決於參數p的大小。如果像Redis裏的實現一樣,取p=1/4,那麼平均每個節點包含1.33個指針,比平衡樹更有優勢。

參考博客

Redis爲什麼用跳錶而不用平衡樹?

跳躍標的實現

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