Redis中有序集合zset須要使用skiplist做爲存儲數據結構, 關於skiplist數據結構描述能夠查詢wiki, 本文主要介紹Redis實現的skiplist的細節.redis
typedef struct zskiplistNode { /*成員object對象*/ robj *obj; /*分數字段依賴此值對skiplist進行排序*/ double score; /*插入層中指向上一個元素level數組*/ struct zskiplistNode *backward; struct zskiplistLevel { /*每層中指向下一個元素指針*/ struct zskiplistNode *forward; /*距離下一個元素之間元素數量, 即forward指向的元素*/ unsigned int span; } level[]; } zskiplistNode; typedef struct zskiplist { /*跳躍表頭節點和尾節點*/ struct zskiplistNode *header, *tail; /*跳躍表中元素個數*/ unsigned long length; /*跳躍表當前最大層數*/ int level; } zskiplist;
建立跳躍表過程比較簡單, 初始化zskiplist數據結構, 跳躍表默認最大層數32層, 跳躍表是按score進行升序排列.數組
/*建立跳躍表*/ zskiplist *zslCreate(void) { int j; zskiplist *zsl; zsl = zmalloc(sizeof(*zsl)); zsl->level = 1; zsl->length = 0; /*初始化建立一個頭節點, 初始化節點信息*/ zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL); for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) { zsl->header->level[j].forward = NULL; zsl->header->level[j].span = 0; } zsl->header->backward = NULL; zsl->tail = NULL; return zsl; } /*建立一個跳躍表節點*/ zskiplistNode *zslCreateNode(int level, double score, robj *obj) { zskiplistNode *zn = zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel)); zn->score = score; zn->obj = obj; return zn; }
zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj) { zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x; unsigned int rank[ZSKIPLIST_MAXLEVEL]; int i, level; redisAssert(!isnan(score)); x = zsl->header; /*從頭節點開始搜索, 一層一層向下搜索, 直到直到最後一層, update數組中保存着每層應該插入的位置*/ for (i = zsl->level-1; i >= 0; i--) { rank[i] = i == (zsl->level-1) ? 0 : rank[i+1]; while (x->level[i].forward && (x->level[i].forward->score < score || (x->level[i].forward->score == score && compareStringObjects(x->level[i].forward->obj,obj) < 0))) { /*記錄每層距離頭部位置的距離*/ rank[i] += x->level[i].span; x = x->level[i].forward; } update[i] = x; } /* 隨機一個層數, 若是隨機的層數是新的層數, 則須要給update數組中新的層數賦值*/ level = zslRandomLevel(); if (level > zsl->level) { for (i = zsl->level; i < level; i++) { rank[i] = 0; /*新的一層上一個指針確定是header*/ update[i] = zsl->header; update[i]->level[i].span = zsl->length; } zsl->level = level; } /*建立新的節點插入到update數組對應的層*/ x = zslCreateNode(level,score,obj); for (i = 0; i < level; i++) { x->level[i].forward = update[i]->level[i].forward; update[i]->level[i].forward = x; /* header update[i] x update[i]->forward |-----------|-----------|-----------|-----------|-----------|-----------| |<---update[i].span---->| |<-------rank[i]------->| |<-------------------rank[0]------------------->| 更新update數組中span值和新插入元素span值, rank[0]存儲的是x元素距離頭部的距離, rank[i]存儲的是update[i]距離頭部的距離, 上面給出了示意圖 */ x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]); update[i]->level[i].span = (rank[0] - rank[i]) + 1; } /* level可能小zsl->level, 無變更的元素span依次增長1*/ for (i = level; i < zsl->level; i++) { update[i]->level[i].span++; } /*上一個元素level數組, 從新賦值*/ x->backward = (update[0] == zsl->header) ? NULL : update[0]; if (x->level[0].forward) x->level[0].forward->backward = x; else /*下一個元素爲空,則表示x爲尾部元素*/ zsl->tail = x; zsl->length++; return x; }
排名其實就是元素在skiplist中排列的序號, 獲取排名須要給出分數和成員member, 經過score查找, 匹配member成員, 時間複雜度log(N). 因爲skiplist是升序排列的,所以函數返回的rank是score按升序排列的rank, 若是想獲取降序rank應該是(length-rank).數據結構
unsigned long zslGetRank(zskiplist *zsl, double score, robj *o) { zskiplistNode *x; unsigned long rank = 0; int i; x = zsl->header; /*循環遍歷並累加每層的span值, 獲取總的排名*/ for (i = zsl->level-1; i >= 0; i--) { while (x->level[i].forward && (x->level[i].forward->score < score || (x->level[i].forward->score == score && compareStringObjects(x->level[i].forward->obj,o) <= 0))) { rank += x->level[i].span; x = x->level[i].forward; } /* 判斷成員是否相等 */ if (x->obj && equalStringObjects(x->obj,o)) { /*升序排列的排名*/ return rank; } } return 0; }
/*經過排名查找元素, rank是從1開始, rank是升序排列的rank值*/ zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank) { zskiplistNode *x; unsigned long traversed = 0; int i; /*遍歷每一層,並記錄排名, 與待查rank比較, 相等則找到, 找不到則返回NULL*/ x = zsl->header; for (i = zsl->level-1; i >= 0; i--) { while (x->level[i].forward && (traversed + x->level[i].span) <= rank) { traversed += x->level[i].span; x = x->level[i].forward; } /*找到直接返回*/ if (traversed == rank) { return x; } } return NULL; }
刪除元素須要精確匹配到分數和memberdom
/*刪除一個元素*/ int zslDelete(zskiplist *zsl, double score, robj *obj) { zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x; int i; x = zsl->header; for (i = zsl->level-1; i >= 0; i--) { while (x->level[i].forward && (x->level[i].forward->score < score || (x->level[i].forward->score == score && compareStringObjects(x->level[i].forward->obj,obj) < 0))) x = x->level[i].forward; update[i] = x; } /* 因爲score值可能相等, 所以須要精確匹配score和obj值 */ x = x->level[0].forward; if (x && score == x->score && equalStringObjects(x->obj,obj)) { zslDeleteNode(zsl, x, update); zslFreeNode(x); return 1; } return 0; /* not found */ } /* 具體進行刪除元素所在節點*/ void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) { int i; /*刪除元素須要更新update元素的span值*/ for (i = 0; i < zsl->level; i++) { if (update[i]->level[i].forward == x) { update[i]->level[i].span += x->level[i].span - 1; update[i]->level[i].forward = x->level[i].forward; } else { update[i]->level[i].span -= 1; } } if (x->level[0].forward) { /*非尾部元素則須要重置backforward指針*/ x->level[0].forward->backward = x->backward; } else { /*刪除x多是最後一個元素, 須要重置尾部指針*/ zsl->tail = x->backward; } /*刪除元素位於最上層, 而且僅有此一個元素, 刪除以後,須要下降跳躍表層數*/ while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL) zsl->level--; zsl->length--; }