[LeetCode]-146.LRU Cache
题目:
为最近最少使用(LRU)缓存设计并实现了一个数据结构。它应该支持以下操作:查询和插入,并且时间复杂度为O(1)。
查询(key)-如果键存在于缓存中,则获得键值(总是正数),否则返回- 1。
插入(key,value)-如果键不存在,则插入(键,值);如果键存在,则设置键所对应的值。当缓存达到其容量时,应在插入新项之前使最近使用的项无效。
在替换旧的项时,采用LRU替换策略。将最近最少访问的项换出。
例子:
LRUCache cache = new LRUCache( 2 /* capacity */ ); cache.put(1, 1); cache.put(2, 2); cache.get(1); // returns 1 cache.put(3, 3); // evicts key 2 cache.get(2); // returns -1 (not found) cache.put(4, 4); // evicts key 1 cache.get(1); // returns -1 (not found) cache.get(3); // returns 3 cache.get(4); // returns 4
解题思路:
由于要求时间复杂度为O(1),如果采用队列或数组来实现LRU,则每次插入或删除一个元素时,时间复杂度为O(n),显然不符合要求。
由于链表中元素的删除和插入时间复杂度都为O(1),因此考虑使用链表来实现LRU。链表为了插入删除方便,采用双向链表(带有头
结点,不存储任何数据)。并设置两个指针,head,tail,分别指向链表头和尾。tail指向的节点为最近访问的节点,head->next为最久
未访问的。为了使查找速度为O(1),采用hash_map(c++中现已过时,采用unordered_map替代)。其中键对应着cache中的键,用于快
速查找,值为指向链表中的节点的指针。
unordered_map<int, slist *> m;
cache中键所对应的值,存放在链表中的value中。为了在cache满时,能快速的替换旧项,在链表节点中增加一个key字段,对应着值所对应的键。
在删除时,通过该键,在unordered_map中删除该项。
(1)在查询时,如果查询的键存在,则先通过map获得该键所对应的链表中的节点,然后移除该节点,并将其插入到链表尾,并返回其值;
如果键不存在,则直接返回-1。
(2)在插入时,分为三种情况:
a.如果键存在,则直接将键对应的节点,移到链表尾,然后修改节点中的值。
b.如果键不存在,并且容量未满时,为其分配节点空间,并设置其中的键和值,再将节点插入到链表尾。同时在map插入相应的键和节点指针。
c.如果键不存在,并且容量满时,首先移除链表头的节点,然后根据节点中的key,删除map中的项,然后设置该节点的新键和新值,将其插入到链表尾,
并在map中插入相应的键和对应节点的指针。
代码如下:
1 struct slist{ 2 int value; 3 int key; 4 slist *next; 5 slist *pre; 6 slist(int key,int value) :key(key),value(value),next(NULL),pre(NULL){} 7 8 }; 9 10 class LRUCache { 11 private: 12 int capacity; 13 slist *head; 14 slist *tail; 15 unordered_map<int, slist *> m; 16 private: 17 void push_back(slist *cur) { 18 cur->next = tail->next; 19 tail->next = cur; 20 cur->pre = tail; 21 tail = tail->next; 22 } 23 void remove(slist *cur) 24 { 25 cur->pre->next = cur->next; 26 if (cur->next != NULL) 27 { 28 cur->next->pre = cur->pre; 29 cur->next = NULL; 30 }else{ 31 tail = cur->pre; 32 } 33 cur->pre = NULL; 34 } 35 public: 36 void print() { 37 slist *pos = head->next; 38 cout << "list:"; 39 while (pos) 40 { 41 cout << "(" << pos->key << "," << pos->value << ")\t"; 42 pos = pos->next; 43 } 44 cout <<endl; 45 } 46 LRUCache(int capacity) { 47 this->capacity = capacity; 48 head = new slist(0,0); 49 head->next = NULL; 50 head->pre = NULL; 51 tail = head; 52 } 53 54 int get(int key) { 55 if (m.count(key) > 0) 56 { 57 slist * pos = m[key]; 58 remove(pos); 59 push_back(pos); 60 return pos->value; 61 } 62 else { 63 return -1; 64 } 65 } 66 67 void put(int key, int value) { 68 if (m.count(key) > 0) 69 { 70 slist * pos = m[key]; 71 remove(pos); 72 pos->value = value; 73 push_back(pos); 74 } 75 else if (m.size()>= capacity) 76 { 77 slist *pos = head->next; 78 remove(pos); 79 m.erase(pos->key); 80 pos->key = key; 81 pos->value = value; 82 push_back(pos); 83 m.insert(pair<int,slist*>(key,pos)); 84 85 } 86 else { 87 slist *pos = new slist(key, value); 88 push_back(pos); 89 m.insert(pair<int, slist*>(key, pos)); 90 } 91 92 } 93 };
posted on 2018-02-07 17:04 IT_Amateur 阅读(135) 评论(0) 编辑 收藏 举报