redis中zSet排序原理----skipList跳躍表

skiplist簡介

skip List是一種隨機化的數據結構,基於並聯的鏈表,實現簡單,插入、刪除、查找的複雜度均爲O(logN)(大多數狀況下),由於其性能匹敵紅黑樹且實現較爲簡單,所以在不少著名項目都用跳錶來代替紅黑樹,例如LevelDB、Reddis的底層存儲結構就是用的SkipList。segmentfault

目前經常使用的key-value數據結構有三種:Hash表、紅黑樹、SkipList,它們各自有着不一樣的優缺點:
Hash表:插入、查找最快,爲O(1);如使用鏈表實現則可實現無鎖;數據有序化須要顯式的排序操做。
紅黑樹:插入、查找爲O(logn),但常數項較小;無鎖實現的複雜性很高,通常須要加鎖;數據自然有序。
SkipList:插入、查找爲O(logn),但常數項比紅黑樹要大;底層結構爲鏈表,可無鎖實現;數據自然有序。數組

SkipList基本數據結構及其實現

一個跳錶,應該具備如下特徵:數據結構

一、一個跳錶應該有幾個層(level)組成;
一般是10-20層,leveldb中默認爲12層。併發

二、跳錶的第0層包含全部的元素;
且節點值是有序的。性能

三、每一層都是一個有序的鏈表;
層數越高應越稀疏,這樣在高層次中能'跳過’許多的不符合條件的數據。spa

四、若是元素x出如今第i層,則全部比i小的層都包含x;線程

五、每一個節點包含key及其對應的value和一個指向該節點第n層的下個節點的指針數組
x->next[level]表示第level層的x的下一個節點指針

skiplist的查詢過程

查詢的第一個比vx大的節點的前一個值,看是否相等。相等則存在,不然查找下一層,直到層數爲0。blog

以已有數據1三、2二、7五、80、99爲例排序

clipboard.png

從最高層(此處爲2)開始

一、level2找到結點Node75小於80,且level2.Node75->next 大於80,則進入level1查找(此處已經跳過了13~75中間的結點(22),

二、level1.Node75 < 80 < level1.Node75->next,進入level0

三、level0.Node75->next 等於80,找到結點

skiplist的插入過程

假設插入一新鍵值key,值爲84,level爲當前層

clipboard.png

一、從最高層開始找到每一層比84大的節點的前一個值,存入prev[level]。

這裏

prev[2] = leve2.Node75

prev[1] = leve1.Node75

prev[0] = level0.Node80

二、初始化一個新的節點84
三、爲x隨機選擇一個高度h,這裏選2
四、x->next[0..h-1] = prev[0..h-1]->next
五、prev[0..h-1]->next[0..h-1] = x

(步驟四、5爲鏈表插入結點的操做)

skiplist刪除操做

刪除操做相似於插入操做,包含以下3步:一、查找到須要刪除的結點 二、刪除結點 三、調整指針

總結

若是要實現一個key-value結構,需求的功能有插入、查找、迭代、修改,那麼首先Hash表就不是很適合了,由於迭代的時間複雜度比較高;而紅黑樹的插入極可能會涉及多個結點的旋轉、變色操做,所以須要在外層加鎖,這無形中下降了它可能的併發度。而SkipList底層是用鏈表實現的,能夠實現爲lock free,同時它還有着不錯的性能(單線程下只比紅黑樹略慢),很是適合用來實現咱們需求的那種key-value結構。

相關文章
相關標籤/搜索