Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
关于题意:
一开始以为LRU指的是在满的时候删除引用最少的节点。后来才发现是按访问时间来排序的最早的节点。
读懂题意之后就比较简单了:
1. 存储数据肯定是要用map的。
2. 怎样构建这个按访问时间排序的列表呢?这个列表需要能够快速增删。链表当然就最好。如果按时间插入,那么在删除时是删除表头,增加是在表尾。
3. 插入链表时,需要把原来的节点给删掉。链表删除需要在o(1),只能用双向链表。而且当知道key的时候,需要知道当前的对应的链表节点的指针。所以map存的value可以直接设成对应的链表节点。
4. 当空间满的时候,知道了LRU的元素(表头),需要把这个元素从map中删除,所以list的节点需要知道对应的map的指针。
事后诸葛亮。。。
1 record DoublyLinkedNode { 2 prev // A reference to the previous node 3 next // A reference to the next node 4 data // Data or a reference to data 5 } 6 record DoublyLinkedList { 7 DoublyLinkedNode firstNode // points to first node of list 8 DoublyLinkedNode lastNode // points to last node of list 9 }
1 function insertAfter(List list, Node node, Node newNode) 2 newNode.prev := node 3 newNode.next := node.next 4 if node.next == null 5 list.lastNode := newNode 6 else 7 node.next.prev := newNode 8 node.next := newNode
1 function insertBefore(List list, Node node, Node newNode) 2 newNode.prev := node.prev 3 newNode.next = node 4 if node.prev == null 5 list.firstNode := newNode 6 else 7 node.prev.next := newNode 8 node.prev := newNode
1 function insertBeginning(List list, Node newNode) 2 if list.firstNode == null 3 list.firstNode := newNode 4 list.lastNode := newNode 5 newNode.prev := null 6 newNode.next := null 7 else 8 insertBefore(list, list.firstNode, newNode)
1 function insertEnd(List list, Node newNode) 2 if list.lastNode == null 3 insertBeginning(list, newNode) 4 else 5 insertAfter(list, list.lastNode, newNode)
1 function remove(List list, Node node) 2 if node.prev == null 3 list.firstNode := node.next 4 else 5 node.prev.next := node.next 6 if node.next == null 7 list.lastNode := node.prev 8 else 9 node.next.prev := node.prev 10 destroy node
1 function remove(List list, Node node) 2 if node.next == node 3 list.lastNode := null 4 else 5 node.next.prev := node.prev 6 node.prev.next := node.next 7 if node == list.lastNode 8 list.lastNode := node.prev; 9 destroy node
同样是两个指针,next指针还是指向下一个,但是pre指针存的是自己的地址(指针的指针)。
特点:
1. 单向遍历;
2. 增删都是o(1);
3. 只要节点存在,它的prev指针一定存在。
1 function insertBefore(Node node, Node newNode) 2 if node.prev == null 3 error "The node is not in a list" 4 newNode.prev := node.prev 5 atAddress(newNode.prev) := newNode 6 newNode.next := node 7 node.prev = addressOf(newNode.next)
1 function insertAfter(Node node, Node newNode) 2 newNode.next := node.next 3 if newNode.next != null 4 newNode.next.prev = addressOf(newNode.next) 5 node.next := newNode 6 newNode.prev := addressOf(node.next)
1 function remove(Node node) 2 atAddress(node.prev) := node.next 3 if node.next != null 4 node.next.prev = node.prev 5 destroy node
1 class LRUCache{ 2 public: 3 struct Data { 4 int val; 5 map<int, list<Data>::iterator >::iterator it; 6 }; 7 8 LRUCache(int capacity) { 9 this->capacity = capacity; 10 } 11 12 int get(int key) { 13 map<int, list<Data>::iterator >::iterator it = keyValues.find(key); 14 if (it == keyValues.end()) { 15 return -1; 16 } else { 17 int val = it->second->val; 18 data.erase(it->second); 19 Data d; 20 d.val = val; 21 d.it = it; 22 data.push_front(d); 23 keyValues[key] = data.begin(); 24 return val; 25 } 26 } 27 28 void set(int key, int value) { 29 map<int, list<Data>::iterator >::iterator it = keyValues.find(key); 30 if (it == keyValues.end()) { 31 if (data.size() >= capacity) { 32 keyValues.erase(data.back().it); //need to erase the map 33 data.pop_back(); 34 } 35 Data d; 36 d.val = value; 37 data.push_front(d); 38 keyValues[key] = data.begin(); 39 data.begin()->it = keyValues.find(key); 40 } else { 41 Data d; 42 d.val = value; 43 d.it = it; 44 data.erase(it->second); 45 data.push_front(d); 46 keyValues[key] = data.begin(); 47 } 48 } 49 50 private: 51 int capacity; 52 list<Data> data; 53 map<int, list<Data>::iterator > keyValues; 54 };