134 LRU快取策略

2021-08-14 19:52:57 字數 1844 閱讀 3330

為最近最少使用(lru)快取

策略設計乙個資料結構,它應該支援以下操作:獲取資料(get)和寫入資料(set)。

獲取資料get(key):如果快取中存在key,則獲取其資料值(通常是正數),否則返回-1。

寫入資料set(key, value):如果key還沒有在快取中,則寫入其資料值。當快取達到上限,它應該在寫入新資料之前刪除最近最少使用的資料用來騰出空閒位置。

分析:一、lru快取策略實現原理 

1、使用雙向鍊錶記錄資料的被使用的時間 

因為我們要刪除最久沒有被訪問的資料,為了保證效率,我們在快取中維護乙個雙向鍊錶,該鍊錶將快取中的資料按照訪問時間從新到舊排列起來。 

當我們需要訪問乙個資料的時候,如果快取中已經快取了這個資料,那麼我們就將該資料從快取的雙向鍊錶中摘除,然後再重新放入到雙向鍊錶的表頭。 

如果快取中沒有我們需要的資料,那麼我們可以在外部獲得資料,然後將資料放入到快取中,此過程中會將新資料插入到雙向鍊錶的表頭。

2、使用hash表保證快取中資料的訪問速度 

因為鍊錶進行查詢是o(n),比較慢。因此為了提高效率,我們除了將資料維護在乙個雙向鍊錶中,同時還將資料維護在乙個hash表中,這時我們訪問的效率就變成了o(1)。

3、原理如圖: 

首先明白,hash表和雙向鍊錶用的是同乙個結點。雙向鍊錶按照訪問時間將這些結點串起來,就是圖中黑色的箭頭。hash表按照key值將這些結點串起來,並且使用拉鍊法解決衝突,比如紫色的箭頭。

4、向快取中插入乙個結點 

首先到hash表中去找: 

如果找到的話,再去雙向鍊錶中將這個結點移到雙向鍊錶的頭部。 

如果沒找到的話,則將這個資料插入到雙向鍊錶的頭部,同時也插入到hash表中。如果這時候快取的數量已經超過閾值,則就將雙向鍊錶的最後乙個結點從鍊錶中移除(注意不是刪除),然後再將這個移除的結點,從hash表也移除,最後再刪除這個結點。因為hash表和雙向鍊錶使用的是同乙個結點,所以必須等到兩邊都移除後才能刪除。

class keyvalue 

keyvalue()

};class lrucache

keyvalue *node = prev->next;

prev->next = node->next;

if (node->next != null)

tail->next = node;

node->next = null;

hash[node->key] = tail;

tail = node;

}public:

unordered_maphash;

keyvalue *head, *tail;

int capacity, size;

lrucache(int capacity)

//獲取資料get(key):如果快取中存在key,則獲取其資料值(通常是正數),否則返回-1。

int get(int key)

movetotail(hash[key]);

return hash[key]->next->value;

}//寫入資料set(key,value):如果key還沒有在快取中,則寫入其資料值。當快取達到上限,它應該在寫入新資料之前刪除最近最少使用的資料用來騰出空閒位置。

void set(int key, int value) else

size--;}}

}};

LRU快取策略

為最近最少使用 lru 快取策略設計乙個資料結構,它應該支援以下操作 獲取資料 get 和寫入資料 set 獲取資料get key 如果快取中存在key,則獲取其資料值 通常是正數 否則返回 1。寫入資料set key,value 如果key還沒有在快取中,則寫入其資料值。當快取達到上限,它應該在寫...

lru快取策略

class listnode class hlistnode public int get int key,listnode no else return 1 public void delnode listnode node else else if node.next null else len...

快取策略之LRU和LFU

快取,就是把資料儲存在本地,簡單實用key value做乙個對映就好了。但為什麼還要快取策略,因為快取的大小需要限制,否則儲存的東西只增不減,時間一長就有很多記憶體浪費。因為資源總是有限,所以優化,因為優化所以複雜 這個是least recently used的縮寫,即最近最少使用。它的邏輯很簡單 ...