首页 > 代码库 > LRU Cache -- LeetCode

LRU Cache -- LeetCode

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算法,支持两种操作,get(查询key对应的value),和set(将key,value加入集合中)

首先,我用双向链表实现,代码细节需要注意的地方较多,因为是处理指针。

技术分享
  1 class LRUCache{  2 public:  3     class Node {  4     public:  5         int key, value;  6         Node *prv, *nxt;  7         Node():key(0), value(0), prv(NULL), nxt(NULL) {}  8         Node(int key, int val):key(key), value(val), prv(NULL), nxt(NULL) {}  9     }; 10     class DoubleLinkedList { 11     public: 12         Node *head, *tail; 13         int size, capacity; 14         DoubleLinkedList():size(0), capacity(0), head(NULL), tail(NULL) {} 15         DoubleLinkedList(int c):size(0), capacity(c), head(NULL), tail(NULL) {} 16         /*~DoubleLinkedList() { 17             while (head != NULL) { 18                 Node *tmp = head; 19                 head = head->nxt; 20                 delete tmp; 21             } 22         }*/ 23         void erase(Node *it) { 24             if (size == 0) return ; 25             if (it->prv != NULL && it->nxt != NULL) { 26                 it->prv->nxt = it->nxt; 27                 it->nxt->prv = it->prv; 28             } 29             if (it->prv == NULL) { 30                 head = it->nxt; 31                 if (head != NULL) 32                     head->prv = NULL; 33             } 34             if (it->nxt == NULL) { 35                 tail = it->prv; 36                 if (tail != NULL) 37                     tail->nxt = NULL; 38             } 39             size--; 40         } 41         int insert(Node *it) { 42             if (tail != NULL) { 43                 tail->nxt = it; 44                 it->nxt = NULL; 45                 it->prv = tail; 46                 tail = it; 47             } else { 48                 head = tail = it; 49             } 50             //if (head == NULL) head = it; 51             //if (tail == NULL) tail = it; 52             size++; 53             if (size > capacity && size > 0) { 54                 int key = head->key; 55                 if (size == 1) { 56                     delete head; 57                     head = tail = NULL; 58                 } else { 59                     Node *tmp = head; 60                     head = head->nxt; 61                     head->prv = NULL; 62                     delete tmp; 63                     tmp = NULL; 64                 } 65                 size--; 66                 return  key; 67             } 68             return -1; 69         } 70     }; 71     LRUCache(int capacity) { 72         //DoubleLinkedList DLL(capacity); 73         DLL.capacity = capacity; 74     } 75      76     int get(int key) { 77         if (HashMap.find(key) == HashMap.end()) { 78             return -1; 79         } else { 80             Node *it = HashMap[key]; 81             DLL.erase(it); 82             DLL.insert(it); 83             return (it->value); 84         } 85     } 86      87     void set(int key, int value) { 88         if (HashMap.find(key) != HashMap.end()) { 89             Node *it = HashMap[key]; 90             it->value =http://www.mamicode.com/ value; 91             DLL.erase(it); 92             DLL.insert(it); 93         } else { 94             Node *tmp = new Node(key, value); 95             HashMap.insert(pair<int, Node*>(key, tmp)); 96             int k = DLL.insert(tmp); 97             if (k != -1) HashMap.erase(k); 98         } 99     }100     101 private:102     unordered_map<int, Node*> HashMap;103     DoubleLinkedList DLL;104 };
View Code

后来,有人说可以用list来简化代码,我原以为面试的时候应该尽量少的使用STL等高级手段,后来巨巨们说并不是这样,于是就用list实现了一遍。

技术分享
 1 class LRUCache{ 2 public: 3     LRUCache(int c) { 4         capacity = c; 5     } 6      7     int get(int key) { 8         int ans = -1; 9         auto it = disc.find(key);10         if (it != disc.end()) {11             ans = it->second->second;12             data.erase(it->second);13             data.push_front(pair<int, int>(key, ans));14             disc[key] = data.begin();15         }16         return ans;17     }18     19     void set(int key, int value) {20         auto it = disc.find(key);21         if (it != disc.end()) {22             data.erase(it->second);23             data.push_front(pair<int, int>(key, value));24             disc[key] = data.begin();25         } else {26             data.push_front(pair<int, int>(key, value));27             disc[key] = data.begin();28             if (data.size() > capacity) {29                 auto it2 = data.end(); it2--;30                 int k = it2->first;31                 disc.erase(k);32                 data.pop_back();33             }34         }35     }36 private:37     unordered_map<int, list<pair<int, int> >::iterator > disc;38     list<pair<int, int> > data; 39     int capacity;40 };
View Code

代码较之前短了很多,但是时间效率也是慢了一倍。

后来听说到有个东西unique_ptr,智能指针,虽然没有使用过,不过还是看了下介绍,可以省去delete操作,方便而且不容易出错。

另外,在使用list解答 本题的时候发现原来我一直没有真正理解迭代器这个概念。我们熟悉的指针也是一种迭代器,但是不可以说迭代器就是指针。

比如,数组下标也是一种迭代器,但是他就不是地址。

当使用list.erase(it)操作时,他返回的是下一个元素的迭代器,而it对应的元素已经被销毁,所以it不可以继续使用,

可以这样:

it = list.erase(it)

或者:

list.erase(it++)

下面一种方法中,在it被erase之前,已经做了一次后自增,所以此时的it是指向下一个元素的,删除了的是it之前的那个元素。

 

LRU Cache -- LeetCode