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 */