跳躍表在redis中主要用於有序集合鍵的實現,其他地方沒怎麼用到,但是這種資料結構在面試的時候經常會問到,因為它作為一種查詢時間複雜度為o(logn)的特殊的鍊錶,效率堪比紅黑樹或平衡樹,而實現難度卻遠小於它們。下面分3個模組講解redis的跳躍表實現:
一、跳躍表的應用場景
在redis中,當有序集合包含的元素數量較多,或者有序集合中元素的成員是比較長的字串時,就會使用跳躍表做有序集合鍵的底層實現。其中,跟有序集合有關的命令主要有zadd、zrange等
二、跳躍表的資料結構
首先介紹下跳躍表的節點定義:
type struct zskiplistnode level; //level陣列,陣列索引表示層數,最多32層(索引值為0~31)
struct zskiplistnode *backward; //後退指標
double score; //分數
robj *obj; //成員物件
}zskiplistnode;
看起來很複雜是吧,沒關係,下面對結構體的所有成員變數乙個個介紹:
1. level
每個跳躍表節點都包含乙個level陣列,這個陣列包含1~32個元素,具體是多少呢,由冪次定律決定,假設為1的概率為
level陣列的每個元素都是乙個zskiplistlevel結構體變數,這個變數包含2個元素forward和span,其中forward是乙個指向下乙個跳躍表節點的前進指標,span表示與下乙個跳躍表節點的跨度,不理解的話可以看下面的例子說明。
2. backward
後退指標主要用於指向上乙個跳躍表節點,形成逆向鍊錶(個人覺得作用不大)
3. score
有序集合的分值,排序時用到,決定了跳躍表節點的位置
4. obj
obj是乙個指向實際成員物件的指標
下面介紹完整的跳躍表定義:
typedef struct zskiplist zskiplist;
其中需要注意的一點是,header指向的跳躍表頭節點固定有32層(即該節點對應的level陣列有32個元素),且一開始的時候每一層指向的下乙個跳躍表節點都為null,直到有節點插入到跳躍表中去。
三、跳躍表的插入過程(重點):
1. 一開始跳躍表是空的,如下圖:
2. 先插入元素a,對應的score為5,隨機生成的層數為2
3. 再插入元素b,對應的score為3,隨機生成的層數為1
4. 最後再插入元素c,對應的score為7,隨機生成的層數為1
5. 此時如果要查詢分值為7的元素c,先從最高層的鍊錶往右查,發現最上面的鍊錶的第乙個元素(不考慮header指向的節點)的分值為5<7,就往右前進,此時最上面的鍊錶已經沒有下乙個節點了,所以就降一層再往右查,進而查到元素c的存在,整個過程其實直接跳過了對元素a對應節點的訪問,從而提公升了查詢效率。
總結:其實跳躍表就是由level條前進鍊錶+1條後退鍊錶構成的,後退鍊錶的存在主要用於從後往前遍歷所有跳躍表節點,而多條前進鍊錶的存在則是為了提公升查詢效率。
Redis內部資料結構總結(5)skiplist
redis的sorted set 底層是由skiplist,dict,ziplist來實現的。在reids.config中有兩個配置 zset max ziplist entries 128 zset max ziplist value 64 sorted set是乙個有序集合,當資料較少時,sor...
Redis資料結構
字典 dict 是redis裡最核心的資料結構,正如其全稱remote dictionary service所說,redis其實就是乙個字典服務,字典以key value的形式呈現給使用者,key是簡單的字串,而value可以是各種資料結構,比如字串 string 鍊錶 list 集合 set 排序...
Redis 資料結構
最近接觸到了redis的使用,借這個機會深入的了解一下redis的實現和設計原理。下面先介紹一下redis底層所用到的資料結構。redis的實現幾乎都是基於下面的幾個資料結構之上的。struct sdshdr struct listnode struct list struct dictentry ...