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

 

posted @ 2020-07-14 22:29  __rookie  阅读(155)  评论(0编辑  收藏  举报