LRU快取機制

2021-10-12 11:28:47 字數 3284 閱讀 5508

題目:

運用你所掌握的資料結構,設計和實現乙個 lru (最近最少使用) 快取機制 。

實現 lrucache 類:

1.lrucache(int capacity) 以正整數作為容量 capacity 初始化 lru 快取

2.int get(int key) 如果關鍵字 key 存在於快取中,則返回關鍵字的值,否則返回 -1 。

3.void put(int key, int value) 如果關鍵字已經存在,則變更其資料值;如果關鍵字不存在,則插入該組「關鍵字-值」。當快取容量達到上限時,它應該在寫入新資料之前刪除最久未使用的資料值,從而為新的資料值留出空間。

示例:

輸入

[「lrucache」, 「put」, 「put」, 「get」, 「put」, 「get」, 「put」, 「get」, 「get」, 「get」]

[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]

輸出[null, null, null, 1, null, -1, null, -1, 3, 4]

解釋

lrucache lrucache = new lrucache(2);

lrucache.put(1, 1); // 快取是

lrucache.put(2, 2); // 快取是

lrucache.get(1); // 返回 1

lrucache.put(3, 3); // 該操作會使得關鍵字 2 作廢,快取是

lrucache.get(2); // 返回 -1 (未找到)

lrucache.put(4, 4); // 該操作會使得關鍵字 1 作廢,快取是

lrucache.get(1); // 返回 -1 (未找到)

lrucache.get(3); // 返回 3

lrucache.get(4); // 返回 4

背景記憶體是有限的,在記憶體不夠用時,必須要淘汰舊頁,通常來說就是採用lru淘汰掉最久未使用的頁。lru簡單來說就是,最頻繁使用的頁在lru列表的隊頭,而最少使用的頁在lru列表的隊尾,當緩衝池不能存放新讀取到的頁時,將首先釋放lru列表的隊尾的頁。

分析lrucache主要要實現兩個功能:

用什麼方式實現這個lru列表呢?由於上述功能涉及到了乙個關鍵操作:調至隊頭。而這個操作涉及到了兩方面內容:刪除和插入。同樣還有乙個關鍵操作:刪除最久未使用的資料值,即隊尾的資料值。可以看到,涉及的操作都是插入和刪除,而我們知道鍊錶進行插入和刪除操作僅需修改指標,時間複雜度為o(1),所以我們敲定:使用鍊錶表示這個lru列表。

那麼使用單鏈表還是雙鏈表?答案是使用雙鏈表。為什麼要用雙鏈表?只要是由於鍊錶的刪除操作需要找到當前節點的前乙個節點,雙鏈表可以在o(1)內找到前乙個節點從而在o(1)內刪除當前節點。似乎單向鍊錶也可以快速刪除,為什麼在這裡為什麼不能使用呢?

1.不是真正的刪除,而是替換。真正刪除的是下乙個節點。

2.無法刪除尾節點。

上述功能還涉及到了乙個關鍵操作:判斷關鍵字是否存在那麼如何判斷關鍵字是否存在呢或者說如何試圖去找到這個關鍵字呢?我們知道順序表具有隨機訪問特性,可以「忽然」訪問到某個值,這樣就可以在o(1)內試圖去找到這個關鍵字。而鍊錶沒有這種隨機訪問特性,我們當然希望鍊錶具有這種特性,否則無法在o(1)內完成上述功能。那麼我們可以使用雜湊表來改造雙鏈表,借助雜湊表使得雙鏈表具有了隨機訪問特性。具體來說就是 雜湊表儲存 key,而雜湊表的 value 指向雙向鍊錶實現的 lru 的 node 節點,節點的資料域是key和value,如圖所示。

這樣一來,我們就可以我們首先使用雜湊表進行定位,找出快取項在雙鏈表中的位置,隨後執行相應的插入和刪除操作,即可在 o(1)內完成 get 或者 put 操作。具體來說:

1.對於 get 操作,首先判斷 key 是否存在:

1)如果 key 不存在,則返回 -1;

2)如果 key 存在,通過雜湊表定位到該節點,並將其插入到頭節點,最後返回該節點的值。

2.對於 put 操作,首先判斷 key 是否存在:

1)如果 key 不存在,使用 key 和 value 建立乙個新的節點,並將其插入到頭節點,並將 key 和該節點新增進雜湊表中。然後判斷雙向鍊錶的節點數是否超出容量,如果超出容量,則刪除雙鏈表的尾節點,並刪除雜湊表中對應的項;

2)如果 key 存在,通過雜湊表定位到該節點,將該節點的value值改為指定的value值,並將其插入到頭節點。細節

**

//雙鏈表

struct dlinklist

dlinklist(int key, int value):key(key), value(value),

pre(nullptr), next(nullptr){}

};class lrucache

//刪除節點

void removenode(dlinklist* node)

//將節點插入到頭節點

void addtohead(dlinklist* node)

//刪除尾結點

dlinklist* removetail()

int get(int key)

else

}void put(int key, int value)

}else

}};/**

* your lrucache object will be instantiated and called as such:

* lrucache* obj = new lrucache(capacity);

* int param_1 = obj->get(key);

* obj->put(key,value);

*/

LRU快取機制

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

LRU快取機制

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

LRU快取機制

lru快取機制 最近最少使用 雙向鍊錶 雜湊表 不使用自帶 linkedhashmap 雙向鍊錶按照被使用的順序儲存了這些鍵值對,靠近頭部的鍵值對是最近使用的,而靠近尾部的鍵值對是最久未使用的。雜湊錶即為普通的雜湊對映 hashmap 通過快取資料的鍵對映到其在雙向鍊錶中的位置。首先使用雜湊表進行定...