跳躍表(Skip List)是一種用於有序元素序列快速搜索的數據結構。它的效率和紅黑樹以及AVL(自平衡二叉查找樹)相近,可是實現起來更加容易(相對於複雜的自平衡算法)。redis
大概結構以下:算法
在最原始的已排序的鏈表基礎上經過添加多個層級,理想狀況下每一個層級節點數是上一個層級1/2,查找時經過最上層開始,利用須要查找的值與當前層級值對比縮小範圍並經過下一層進一步縮小範圍,最終找到查詢值的方式(相似於二分查找方式)。數組
Redis使用跳躍表做爲有序集合的底層實現之一,若是一個有序集合包含的元素比較多或者集合中的元素時比較長的字符串時,Redis會使用跳躍表做爲有序集合鍵的底層實現。數據結構
Redis跳躍表大體結構以下:spa
分爲zskiplistNode和zskiplist兩個結構,代碼以下:指針
redis.h/zskiplistNode:code
typedef struct zskiplistNode { // 成員對象 robj *obj; // 分值 double score; // 後退指針 struct zskiplistNode *backward; // 層 struct zskiplistLevel { // 前進指針 struct zskiplistNode *forward; // 跨度 unsigned int span; } level[]; } zskiplistNode;
level數組包含了當前元素在不用層高的下一個元素指針和跨度,Redis中程序會根據冪次定律(power law, 越大的數出現的機率越小)隨機生成一個介於1~32之間的值做爲level數組的大小,這個大小就是層的「高度」。對象
span表示跨度,因爲底層的鏈表是有序的,因此從頭部到當前節點跨度之和也就是元素的排位。用於Redis有序集合的ZRANK命令獲取元素排行。排序
backward回退指針用於逆序遍歷鏈表,對應Redis有序集合的ZREVRANGE命令。ip
redis.h/zskiplist:
typedef struct zskiplist { // 表頭節點和表尾節點 struct zskiplistNode *header, *tail; // 表中節點的數量 unsigned long length; // 表中層數最大的節點的層數 int level; } zskiplist;