leecode第146题:LRU缓存机制

题目:运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

原题链接

解题思路:采用双向链表和哈希表实现。双向链表中记录key, val两个值,以及prev和next两个指针。哈希表以key作为索引,值为链表节点。

  • 获取数据时,在哈希表中根据key查找

    • key在哈希表中,根据表中存储的链表节点返回val;并将该节点放到链表的头部。
    • key不在哈希表中,返回-1。
  • 写入数据时,判断key是否已经在哈希表中

    • key在哈希表中,重新覆盖该链表的val值,并将该链表节点移动至头部;
    • key不在哈希表中,新建一个链表节点,并将链表节点放到头部;之后判断此时的链表长度是否超过容量,若超过容量,则删除链表的尾部节点,并将该节点对应的key从哈希表中删除。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
struct dListNode {
int key;
int val;
dListNode* prev;
dListNode* next;
dListNode(): key(0), val(0), prev(NULL), next(NULL){}
dListNode(int k, int v): key(k), val(v), prev(NULL), next(NULL) {}
};

class LRUCache {
private:
int size;
int capacity;
dListNode* head = new dListNode();
dListNode* tail = new dListNode();
unordered_map<int, dListNode*> cache;
public:
LRUCache(int capacity) {
this->capacity = capacity;
this->size = 0;
this->head->next = this->tail;
this->tail->prev = this->head;
}
int get(int key) {
if (!cache.count(key)) {
return -1;
} else {
dListNode* tmp = cache[key];
mv2head(tmp);
return tmp->val;
}
}

void put(int key, int value) {
if (!cache.count(key)) {
dListNode* tmp = new dListNode(key, value);
cache[key] = tmp; //注意,新增加的节点要添加进哈希表中。
add2head(tmp);
size += 1;
if (size>capacity) {
dListNode* tail_rmed = rm_tail();
cache.erase(tail_rmed->key); //删除的节点要从哈希表中删除
delete tail_rmed; //释放内存
size -= 1;
}
}
else {
dListNode* tmp = cache[key];
tmp->val = value;
mv2head(tmp);
}
}
void rm_node(dListNode* p) {
p->next->prev = p->prev;
p->prev->next = p->next;
}
void add2head(dListNode* p) {
p->next = head->next;
p->prev = head;
head->next = p;
p->next->prev = p;
}
dListNode* rm_tail() {
dListNode* tmp = tail->prev;
tail->prev = tmp->prev;
tail->prev->next = tail;
return tmp;
}
void mv2head(dListNode* p) {
rm_node(p);
add2head(p);
}
~LRUCache () {
while (head) {
dListNode* tmp = head->next;
delete head;
head = tmp;
}
}
};

/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/