1. 程式人生 > 實用技巧 >LeetCode146 LRU快取機制

LeetCode146 LRU快取機制

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

獲取資料 get(key) - 如果關鍵字 (key) 存在於快取中,則獲取關鍵字的值(總是正數),否則返回 -1。
寫入資料 put(key, value) - 如果關鍵字已經存在,則變更其資料值;如果關鍵字不存在,則插入該組「關鍵字/值」。當快取容量達到上限時,它應該在寫入新資料之前刪除最久未使用的資料值,從而為新的資料值留出空間。

進階:

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

使用一個雜湊表記錄key,用雙鏈表記錄key,value和順序。雜湊表中key對應的是雙鏈表節點的指標。每次查詢就把當前節點移動到連結串列的頭部。每次put的時候也會把put的節點移動到頭部,同時判斷是否超出capacity,如果超出就刪除dummyhead前面的一個節點。

注意delete釋放空間,修改指標要修改全。

連結串列雙向主要是可以在O(1)時間內找到需要刪除的節點(即dummyTail前一個節點)。節點需要記錄key主要是刪除的時候得到key,這樣才能在O(1)時間內在雜湊表中找到並刪除。

 1 struct DLinkedNode {
 2     int key, value;
 3     DLinkedNode* prev;
 4     DLinkedNode* next;
 5     DLinkedNode() : key(0), value(0), prev(nullptr), next(nullptr) {}
 6     DLinkedNode(int
_key, int _value) : key(_key), value(_value), prev(nullptr), next(nullptr) {} 7 }; 8 9 struct LRU_Node { 10 int key; 11 int value; 12 LRU_Node* next; 13 LRU_Node* prev; 14 LRU_Node() : key(0), value(0), next(nullptr), prev(nullptr) {} 15 LRU_Node(int _key, int _value) :key(_key), value(_value), next(nullptr), prev(nullptr) {}
16 }; 17 18 class LRUCache { 19 private: 20 int num; 21 int capacity; 22 unordered_map<int, LRU_Node*> map_LRU; 23 LRU_Node* dummyHead; 24 LRU_Node* dummyTail; 25 26 public: 27 LRUCache(int _capacity) { 28 num = 0; 29 capacity = _capacity; 30 dummyHead = new LRU_Node(-1, -1); 31 dummyTail = new LRU_Node(-1, -1); 32 dummyHead->next = dummyTail; 33 dummyTail->prev = dummyHead; 34 map_LRU.clear(); 35 cout << "LRUCache is created.\n"; 36 } 37 38 LRU_Node* moveToHead(LRU_Node* cur) { 39 cur->prev->next = cur->next; 40 cur->next->prev = cur->prev; 41 cur->next = dummyHead->next; 42 cur->prev = dummyHead; 43 dummyHead->next = cur; 44 cur->next->prev = cur; 45 return cur; 46 } 47 48 LRU_Node* insertHead(LRU_Node* new_node) { 49 new_node->next = dummyHead->next; 50 new_node->prev = dummyHead; 51 dummyHead->next = new_node; 52 new_node->next->prev = new_node; 53 return new_node; 54 } 55 56 int get(int key) { 57 if (map_LRU.find(key) != map_LRU.end()) { 58 LRU_Node* cur = map_LRU[key]; 59 cur = moveToHead(cur); 60 map_LRU[key] = cur; 61 return cur->value; 62 } 63 return -1; 64 } 65 66 void put(int key, int value) { 67 if (map_LRU.find(key) != map_LRU.end()) { 68 LRU_Node* cur = map_LRU[key]; 69 cur->value = value; 70 cur = moveToHead(cur); 71 map_LRU[key] = cur; 72 } 73 else { 74 LRU_Node* new_node = new LRU_Node(key, value); 75 new_node = insertHead(new_node); 76 map_LRU[key] = new_node; 77 if (num != capacity) 78 ++num; 79 else { 80 int deleteKey = dummyTail->prev->key; 81 LRU_Node* toBeDelete=dummyTail->prev; 82 dummyTail->prev=dummyTail->prev->prev; 83 dummyTail->prev->next=dummyTail; 84 delete toBeDelete; 85 toBeDelete=nullptr; 86 auto it = map_LRU.find(deleteKey); 87 map_LRU.erase(it); 88 } 89 } 90 return; 91 } 92 }; 93 94 /** 95 * Your LRUCache object will be instantiated and called as such: 96 * LRUCache* obj = new LRUCache(capacity); 97 * int param_1 = obj->get(key); 98 * obj->put(key,value); 99 */