跳躍表(skiplist)是一種有序數據結構,它經過在每一個節點中維持多個指向其餘節點的指針,從而達到快速訪問節點的目的。redis
跳躍表支持平均O(logN),最壞O(N)複雜度的節點查找,還能夠經過順序性操做批量處理節點。
在大部分狀況下,跳躍表的效率能夠和平衡樹相媲美,而且由於跳躍表的實現比平衡數要來得更爲簡單,因此有很多程序都使用跳躍表來代替平衡樹。
redis 使用跳躍表做爲有序集合鍵的底層實現之一,若是一個有序集合包含的元素數量比較多,又或者有序集合中元素的成員(member)是比較長的字符串時,Redis就會使用跳躍表做爲有序集合鍵的底層實現。數據結構
和鏈表,字典等數據結構被普遍地應用在Redis內部不一樣,Redis只有兩個地方用到了跳躍表,一個是實現有序集合鍵,另外一個是在集羣節點中用做內部數據結構,除此以外,跳躍表在Redis裏面沒有其餘用途。spa
/* ZSETs use a specialized version of Skiplists */ typedef struct zskiplistNode { robj *obj; //成員對象 double score; //分值 struct zskiplistNode *backward; //後退指針 struct zskiplistLevel { //層 struct zskiplistNode *forward; //前進指針 unsigned int span; //跨度 } level[]; } zskiplistNode; typedef struct zskiplist { struct zskiplistNode *header, *tail; //header:指向跳躍表的表頭節點,tail :指向跳躍表的表尾節點 unsigned long length; //記錄跳躍表的長度,也便是,跳躍表目前包含節點的數量(表頭節點不計算在內) int level; //記錄目前跳躍表內,層數最大的那個節點的層數(表頭節點的層數不計算在內) } zskiplist; typedef struct zset { dict *dict; zskiplist *zsl; } zset;
hearder和tail 指針分別指向跳躍表的表頭和表尾節點,經過這兩個指針,程序定位表頭節點和表尾節點的複雜度爲O(1)。指針
經過使用length屬性來記錄節點的數量,程序能夠在O(1)複雜度內返回跳躍表的長度。code
總結:對象
跳躍表是有序集合的底層實現之一。排序
Redis的跳躍表實現由zskiplist 和zskiplistNode兩個結構組成,其中zskiplist用於保存跳躍表信息(好比表頭節點,表尾節點,長度),而zskiplistNode 則用於表示跳躍表節點。ip
每一個跳躍表節點的層高都是1至32之間的隨機數。ci
在同一個跳躍表中,多個節點能夠包含相同的分值,但每一個節點的成員對象必須是惟一的。字符串
跳躍表中的節點按照分值大小進行排序,當分值相同時,節點按照成員對象的大小進行排序。