1 /*
2 Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.
3
4 get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
5 set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity,
6 it should invalidate the least recently used item before inserting a new item.
7 Problem link: https://oj.leetcode.com/problems/lru-cache/
8
9 Author: Vincent Zhang
10 */
11
12 #include <map>
13 using namespace std;
14
15 struct CacheNode {
16 int key;
17 int value;
18 CacheNode* prev;
19 CacheNode* next;
20 CacheNode(int k,int v) : key(k), value(v), prev(NULL), next(NULL) {}
21 };
22
23 class LRUCache{
24 public:
25 LRUCache(int capacity) {
26 this->cache_capacity = capacity;
27 head = NULL;
28 tail = NULL;
29 }
30
31 int get(int key) {
32 map<int,CacheNode*>::iterator it = cache_map.find(key);
33 if (it == cache_map.end())
34 return -1;
35 else
36 {
37 CacheNode *tp = it->second;
38 moveToHead(tp);
39 return tp->value;
40 }
41 }
42
43 void set(int key, int value) {
44 map<int,CacheNode*>::iterator it = cache_map.find(key);
45 // new key and value
46 if (it == cache_map.end())
47 {
48 // cache is full, release the LRU one and add new
49 if (cache_map.size() == cache_capacity)
50 {
51 cache_map.erase(tail->key);
52 tail->key = key;
53 tail->value = value;
54 CacheNode *tp = tail;
55 moveToHead(tp);
56
57 cache_map.insert(map<int,CacheNode*>::value_type(key,tp));
58 }
59 else // cache is not full, add new
60 {
61 CacheNode *newNode = new CacheNode(key,value);
62 attachToHead(newNode);
63 cache_map.insert(map<int,CacheNode*>::value_type(key,newNode));
64 }
65
66 }
67 else // has an exist node
68 {
69 CacheNode *tp = it->second;
70 tp->value = value;
71
72 isolateNode(tp);
73 attachToHead(tp);
74 }
75
76 }
77 private:
78 int cache_capacity;
79 CacheNode *head,*tail;
80 map<int,CacheNode*> cache_map;
81
82 void moveToHead(CacheNode *node)
83 {
84 if (node == head)
85 return;
86 else
87 {
88 isolateNode(node);
89 attachToHead(node);
90 }
91 }
92 void isolateNode(CacheNode* node)
93 {
94 if (node->prev != NULL)
95 node->prev->next = node->next;
96 else // node is head
97 head = node->next;
98
99 if (node->next !=NULL)
100 node->next->prev = node->prev;
101 else // node is tail
102 tail = node->prev;
103
104 node->next = NULL;
105 node->prev = NULL;
106 }
107 void attachToHead(CacheNode* node)
108 {
109 // head is null, list is empty
110 if (head == NULL)
111 {
112 head = node;
113 tail = head;
114 }
115 else
116 {
117 node->next = head;
118 head->prev = node;
119 head = node;
120 }
121 }
122 };