redis原始碼剖析 skiplist

2021-10-18 09:01:30 字數 2632 閱讀 9010

試想乙個業務場景:遊戲需要實現乙個實時更新的排行榜應該如何實現

首先想到使用有序的雙端鍊錶, 因為插入的時間複雜度為o(1)  但是定位的平均時間複雜度為o(n)  當頻繁更新排行榜的時候效率比較低

有沒有乙個結構 能夠滿足快速定位到相應的位置並插入?跳躍表就能滿足這個需求

跳躍表的思想是給資料結點建立索引 從最高層索引根據關鍵字查詢   如果當前結點《關鍵字 且下一節點》關鍵字 則降層繼續從當前結點開始查詢  一直到查詢到結點 或 降到第0層

演算法平均複雜度與給定的建立索引概率有關 當p=0.5時接近二分查詢演算法時間複雜度

跳躍表是犧牲記憶體換取時間的一種演算法

看下redis原始碼種skiplist的定義

typedef struct zskiplistnode  level;

} zskiplistnode;

typedef struct zskiplist zskiplist;

zskiplistnode:

ele: 資料結點

score:關鍵字

backward:前置結點

level: n個層的資訊 每層都有乙個指向下一結點的資訊和距離

zskiplist:

header、tail:頭尾結點

length:總共結點數量

level:最大層數

zskiplistnode *zslinsert(zskiplist *zsl, double score, sds ele)

1.從最高層的首結點開始找到關鍵字小於並且最接近score的結點 

2.每一層迴圈查詢

3.根據給定概率p 確定score能夠建立索引層數level

4.如果當前level比zsl的level高  則初始化對應層的

5.從第0層開始到level層 在1中找到的node後插入新的結點

6.更新span

7.如果在最後乙個node後面插入則更新tail

8.zsl的結點數+1

/* insert a new node in the skiplist. assumes the element does not already

* exist (up to the caller to enforce that). the skiplist takes ownership

* of the passed sds string 'ele'. */

zskiplistnode *zslinsert(zskiplist *zsl, double score, sds ele)

update[i] = x;

}/* we assume the element is not already inside, since we allow duplicated

* caller of zslinsert() should test in the hash table if the element is

* already inside or not. */

level = zslrandomlevel();

if (level > zsl->level)

zsl->level = level;

}x = zslcreatenode(level,score,ele);

for (i = 0; i < level; i++)

/* increment span for untouched levels */

for (i = level; i < zsl->level; i++)

x->backward = (update[0] == zsl->header) ? null : update[0];

if (x->level[0].forward)

x->level[0].forward->backward = x;

else

zsl->tail = x;

zsl->length++;

return x;

}

void zsldeletenode(zskiplist *zsl, zskiplistnode *x, zskiplistnode **update)刪除x結點

1.遍歷第0層到最高層 找到有x所在的層(update已經記錄) 刪掉x

2.更新span

3.更新第0層x的forward

4.刪除x可能影響zsl的層數 所以需要判斷 並更新

5.zsl的結點數遞減

/* internal function used by zsldelete, zsldeletebyscore and zsldeletebyrank */

void zsldeletenode(zskiplist *zsl, zskiplistnode *x, zskiplistnode **update) else

}if (x->level[0].forward) else

while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == null)

zsl->level--;

zsl->length--;

}

redis原始碼剖析 dict

typedef struct dictentry v struct dictentry next dictentry typedef struct dicttype dicttype this is our hash table structure.every dictionary has two ...

原始碼剖析 Hashtable 原始碼剖析

hashtable同樣是基於雜湊表實現的,同樣每個元素都是key value對,其內部也是通過單鏈表解決衝突問題,容量不足 超過了閾值 時,同樣會自動增長。hashtable也是jdk1.0引入的類,是執行緒安全的,能用於多執行緒環境中。hashtable同樣實現了serializable介面,它支...

Redis原始碼剖析(八)鍊錶

在之前對redis的介紹中,可以看到鍊錶的使用頻率非常高。鍊錶可以作為單獨的儲存結構,比如客戶端的監視鍊錶記錄該客戶端監視的所有鍵,伺服器的模式訂閱鍊錶記錄所有客戶端和它的模式訂閱。鍊錶也可以內嵌到字典中作為字典的值型別,比如資料庫的監視字典使用鍊錶儲存監視某個鍵的所有客戶端,伺服器的訂閱字典使用鍊...