試想乙個業務場景:遊戲需要實現乙個實時更新的排行榜應該如何實現
首先想到使用有序的雙端鍊錶, 因為插入的時間複雜度為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的介紹中,可以看到鍊錶的使用頻率非常高。鍊錶可以作為單獨的儲存結構,比如客戶端的監視鍊錶記錄該客戶端監視的所有鍵,伺服器的模式訂閱鍊錶記錄所有客戶端和它的模式訂閱。鍊錶也可以內嵌到字典中作為字典的值型別,比如資料庫的監視字典使用鍊錶儲存監視某個鍵的所有客戶端,伺服器的訂閱字典使用鍊...