redis 跳躍表

qq_35728402發表於2020-10-15

跳躍表可以看作是對有序連結串列的改進,我們知道對連結串列中元素查詢的時間複雜度時O(n),但是,如果我們可以知道中間節點的大小,就可以判斷元素是在連結串列的前半段還是後半段,將查詢範圍減半,通過這種思想,就可以把連結串列的查詢時間複雜度降低到O(lgn)
跳躍表就是藉助這種思想,但是因為連結串列中的元素數隨著插入元素和刪除元素的減少,很難定位中位數在哪裡,所以,跳躍表採用隨機的方法來定義每個節點的層數。

跳躍表類定義

redis 中跳躍表主要有兩個結構zskiplist和zskiplistNode
zskiplist儲存跳躍表的頭尾節點以及跳躍表的節點最大層高
zskiplistNode 儲存跳躍表中的具體資料

typedef struct zskiplistNode {
	//成員物件
    sds ele;

	//分值
    double score;

	// 後退指標
    struct zskiplistNode *backward;
  	// 層
    struct zskiplistLevel {
    	//跨度指標
        struct zskiplistNode *forward;
        
        //跨度
        unsigned long span;
    } level[];
} zskiplistNode;

typedef struct zskiplist {

	//表頭結點和表尾節點
    struct zskiplistNode *header, *tail;
    
    //表中節點數量
    unsigned long length;
    
    //表中層數最大的節點層數
    int level;
} zskiplist;

跳躍表結構

如下圖所示:
有32層的時跳躍表建立的時候建立的頭節點,這個節點不儲存資料
第一個資料score為1.0,儲存的資料時O1,層數是4
第二個資料score為2.0, 儲存資料為O2, 層數為2
第三個資料score為3.0,儲存資料為O3, 層數為5

分析查詢score為2.0的節點的過程

  • 首先從zskiplist可以得到當前存在節點中最大的層數為5
  • 檢視header的第5層指向的節點的score,得到score為3,比2大,所以當前節點還是header節點
  • 檢視header的第四層指向的節點的score,得到score為1,比2小,當前節點為O1
  • 檢視O1的第四層指向的節點的score值,得到score為3,比2大,當前節點為O1
  • 檢視O1的第三層指向的節點的score值,得到score為2,等於2,返回

總結

  • redis有zskiplist和zsdkiplistNode兩個結構組成,zskiplist儲存跳躍表的表頭、表尾節點,長度等資訊,zskiplistNode儲存具體的資料
  • 跳躍表是按照score的升序排列的,score的值可以相同,如果score的值相同,就按照value的字典升序排列
  • 每個跳躍表的層數是1~32的一個隨機數

相關文章