雙向鍊錶與LRU快取淘汰機制

2021-09-12 21:54:25 字數 1818 閱讀 1427

雙向鍊錶作為在日常開發中最常用的資料結構之一,應用十分廣泛,在諸多著名開源專案中如redis的list結構, groupcache的lru中均是核心實現。在設計此類資料集合的時候,外面看上去鍊錶似乎與陣列相似,但鍊錶是乙個非連續性記憶體的儲存方案,提供了高效的節點重排能力與順序訪問方式,對比與運算元組,只需知道給定項的位址和位置的鏈結就能在記憶體中找到它,並且可以通過增減節點的方式來靈活的調整長度。反而陣列,比如插入乙個新的元素,那麼該位置後的元素都要往後移動一位。

redis 中的雙向鍊錶

golang 中的雙向鍊錶

其結構如圖

在雙向鍊錶中頭結點的前指標為空,尾節點的後指標為空, 對頭尾的操作十分簡單, 插入頭節點只需要將新節點的next設定為當前鍊錶的頭節點, 當前列表的prev為新節點, 並與之交換位置即可, 插入尾部反之

在節點中間按游標插入的話則需要考慮正向反向的問題, 下圖當i 為正數表示正向插入,負數反向插入, 其實不管是只操作頭尾節點還是中間節點,其核心就是交換當前節點與前乙個和後乙個節點之間的鏈結

將某個節點移動至頭部跟插入頭部動作多了一步交換當前節點前後節點鏈結的操作

而刪除某個節點就只需要將其前後節點的鏈結互相相連,使其不被引用,它會自動被**掉

lru全稱least recently used, 直譯為「最近最少使用」, 其對於記憶體管理方面十分有效,比如容量只有十的乙個集合,當寫入第十一條資料時候,最少使用的那個資料將會被淘汰,故此方法很適用於對有給定容量限制的熱資料做快取管理

在開源專案groupcache中, 快取的過期沒有設定過期時間而是依賴於lru淘汰機制,那麼其用來實現lru的核心就是乙個雙向鍊錶, 為了保證效率, 快取資料被儲存在乙個map中使每次快取的訪問時間複雜度為o(1), 而雙向鍊錶則負責管理記憶體的容量以及實現淘汰機制

在寫入新的快取項時,會把其插入至鍊錶的頭部, 並且判斷如果當前鍊錶長度大於給定長度時,刪除鍊錶尾部的元素,同時刪除其在map中的key

每當有訪問命中快取時, 會將命中的快取移至鍊錶頭部

上述插入和命中時將其放到鍊錶頭部的策略,使得鍊錶尾部的元素永遠是使用得最少的那個快取,故新快取進來時就將其淘汰。

本文說明了雙向鍊錶的實現以及其實際應用,但是在真實應用中,golang 的雙向鍊錶是非執行緒安全的,如遇到併發情況操作鍊錶則會因為找不到位址而報錯, 所以groupcache專案在從lru策略中獲取快取的時候,在外部包了乙個帶讀寫鎖的結構體來保證其併發安全

146 LRU 快取機制(雙向鍊錶 雜湊表)

難度 中等 運用你所掌握的資料結構,設計和實現乙個 lru 最近最少使用 快取機制 實現 lrucache 類 lrucache int capacity 以正整數作為容量 capacity 初始化 lru 快取 int get int key 如果關鍵字 key 存在於快取中,則返回關鍵字的值,否...

LRU快取機制(雜湊鍊錶)

題目 參考 solution lru ce lue xiang jie he shi xian by labuladong 運用你所掌握的資料結構,設計和實現乙個 lru 最近最少使用 快取機制。它應該支援以下操作 獲取資料 get 和 寫入資料 put 獲取資料 get key 如果金鑰 key ...

力扣 146LRU快取機制(雙向鍊錶)

題目描述 運用你所掌握的資料結構,設計和實現乙個 lru 最近最少使用 快取機制。它應該支援以下操作 獲取資料 get 和 寫入資料 put 獲取資料 get key 如果關鍵字 key 存在於快取中,則獲取關鍵字的值 總是正數 否則返回 1。寫入資料 put key,value 如果關鍵字已經存在...