leetcode LRU緩存機制(list+unordered_map)詳細解析

運用你所掌握的數據結構,設計和實現一個  LRU (最近最少使用) 緩存機制。它應該支持以下操作: 獲取數據 get 和 寫入數據 put 。

獲取數據 get(key) - 如果密鑰 (key) 存在於緩存中,則獲取密鑰的值(總是正數),否則返回 -1。
寫入數據 put(key, value) - 如果密鑰不存在,則寫入其數據值。當緩存容量達到上限時,它應該在寫入新數據之前刪除最近最少使用的數據值,從而爲新的數據值留出空間。

進階:

你是否可以在 O(1) 時間複雜度內完成這兩種操作?

示例:

LRUCache cache = new LRUCache( 2 /* 緩存容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 該操作會使得密鑰 2 作廢
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 該操作會使得密鑰 1 作廢
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4

題解:

就是一種緩存淘汰策略。

計算機的緩存容量有限,如果緩存滿了就要刪除一些內容,給新內容騰位置。但問題是,刪除哪些內容呢?我們肯定希望刪掉哪些沒什麼用的緩存,而把有用的數據繼續留在緩存裏,方便之後繼續使用。那麼,什麼樣的數據,我們判定爲「有用的」的數據呢?

LRU 緩存淘汰算法就是一種常用策略。LRU 的全稱是 Least Recently Used,也就是說我們認爲最近使用過的數據應該是是「有用的」,很久都沒用過的數據應該是無用的,內存滿了就優先刪那些很久沒用過的數據。

要讓 put 和 get 方法的時間複雜度爲 O(1)O(1),我們可以總結出 cache 這個數據結構必要的條件:查找快,插入快,刪除快,有順序之分。

因爲顯然 cache 必須有順序之分,以區分最近使用的和久未使用的數據;而且我們要在 cache 中查找鍵是否已存在;如果容量滿了要刪除最後一個數據;每次訪問還要把數據插入到隊頭。

那麼,什麼數據結構同時符合上述條件呢?哈希表查找快,但是數據無固定順序;鏈表有順序之分,插入刪除快,但是查找慢。所以結合一下,形成一種新的數據結構:哈希鏈表。

 

參考代碼:

 1 class LRUCache {
 2 private:
 3     list<pair<int,int>> cache;
 4     unordered_map<int, list<pair<int,int>>::iterator> ump;
 5     int cap;
 6 public:
 7     LRUCache(int capacity) {
 8         this->cap=capacity;
 9     }
10     
11     int get(int key) {
12         auto it=ump.find(key);
13         if(it==ump.end()) return -1;
14         pair<int,int> pv=*ump[key];
15         cache.erase(ump[key]);
16         cache.push_front(pv);
17         ump[key]=cache.begin();
18 
19         return pv.second;
20     }
21     
22     void put(int key, int value) {
23         auto it=ump.find(key);
24         if(it==ump.end())
25         {
26             if(cache.size()==cap)
27             {
28                 ump.erase(cache.back().first);
29                 cache.pop_back();
30             }
31             cache.push_front(make_pair(key,value));
32             ump[key]=cache.begin();
33         }
34         else
35         {
36             cache.erase(ump[key]);
37             cache.push_front(make_pair(key,value));
38             ump[key]=cache.begin();
39         }
40     }
41 };
42 
43 /**
44  * Your LRUCache object will be instantiated and called as such:
45  * LRUCache* obj = new LRUCache(capacity);
46  * int param_1 = obj->get(key);
47  * obj->put(key,value);
48  */
C++

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章