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.
直到做到这道题时,我才知道了原来Clock算法不等于LRU算法,Clock算法只是一种近似的LRU算法,但两者的调度结果不完全一样。一上来我先想的是Clock算法,然后就一直WA!
LRU算法就是维护一个链表,最新的结果放在链表的最后面,所以每次只要替换链表的头结点就行了,下面是代码:
1 class LRUCache{ 2 public: 3 struct Node { 4 int key; 5 int val; 6 Node *next; 7 Node() : key(-1), val(-1) {} 8 Node(int k, int v) : key(k), val(v) {} 9 }; 10 11 Node *cache; 12 Node *tail; 13 int capacity; 14 int size; 15 16 LRUCache(int capacity) { 17 this->capacity = capacity; 18 size = 0; 19 cache = new Node(); 20 tail = cache; 21 } 22 23 int get(int key) { 24 Node *pos = cache; 25 int val; 26 while (pos != tail && pos->next != NULL) { 27 if (pos->next->key == key) { 28 val = pos->next->val; 29 tail->next = pos->next; 30 pos->next = pos->next->next; 31 tail = tail->next; 32 tail->next = NULL; 33 return val; 34 } 35 pos = pos->next; 36 } 37 return -1; 38 } 39 40 void set(int key, int value) { 41 Node *pos = cache; 42 while (pos != tail && pos->next != NULL) { 43 if (pos->next->key == key) { 44 pos->next->val = value; 45 tail->next = pos->next; 46 pos->next = pos->next->next; 47 tail = tail->next; 48 tail->next = NULL; 49 return; 50 } 51 pos = pos->next; 52 } 53 if (size < capacity) { 54 tail->next = new Node(key, value); 55 tail = tail->next; 56 ++size; 57 } else { 58 cache->next->key = key; 59 cache->next->val = value; 60 tail->next = cache->next; 61 cache->next = cache->next->next; 62 tail = tail->next; 63 tail->next = NULL; 64 } 65 } 66 };
可以使用map来加速查找的过程,使用STL里的list也可以使代码精简不少。
1 class LRUCache{ 2 private: 3 list<pair<int, int>> mlist; 4 unordered_map<int, list<pair<int, int>>::iterator> mmap; 5 int mcapacity; 6 7 public: 8 LRUCache(int capacity) { 9 mlist.clear(); 10 mmap.clear(); 11 mcapacity = capacity; 12 } 13 14 int get(int key) { 15 if (mmap.find(key) != mmap.end()) { 16 pair<int, int> tmp = *(mmap[key]); 17 mlist.erase(mmap[key]); 18 mlist.push_front(tmp); 19 mmap[key] = mlist.begin(); 20 return mlist.front().second; 21 } else { 22 return -1; 23 } 24 } 25 26 void set(int key, int value) { 27 if (mmap.find(key) != mmap.end()) { 28 mlist.erase(mmap[key]); 29 mlist.push_front(make_pair(key, value)); 30 } else { 31 if (mlist.size() == mcapacity) { 32 mmap.erase(key); 33 mlist.pop_back(); 34 } 35 mlist.push_front(make_pair(key, value)); 36 } 37 mmap[key] = mlist.begin(); 38 } 39 };
虽然Clock算法不合题意,代码还是帖上来吧,下面是Clock算法:
1 class LRUCache{ 2 public: 3 struct node { 4 int key; 5 int value; 6 bool tag; 7 node() { 8 key = -1; 9 value = -1; 10 tag = false; 11 } 12 }; 13 14 node *cache; 15 int size; 16 int pos; 17 18 LRUCache(int capacity) { 19 pos = 0; 20 size = capacity; 21 cache = new node[capacity]; 22 } 23 24 int get(int key) { 25 for (int i = 0; i < size; ++i) { 26 if (cache[i].key == key) { 27 cache[i].tag = true; 28 return cache[i].value; 29 } 30 } 31 return -1; 32 } 33 34 void set(int key, int value) { 35 for (int i = 0; i < size; ++i) { 36 if (cache[i].key == key) { 37 cache[i].tag = true; 38 cache[i].value = value; 39 return; 40 } 41 } 42 while(cache[pos].tag) { 43 cache[pos].tag = false; 44 ++pos; 45 pos %= size; 46 } 47 cache[pos].key = key; 48 cache[pos].value = value; 49 cache[pos].tag = true; 50 ++pos; 51 pos %= size; 52 } 53 };