leetcode-146.LRU缓存

本文最后更新于:2022年7月20日 下午

java写法,c++的代码一直调不对,不知道怎么了。思路就是自定义一个双向链表的类DLinkedNode,然后一个map<int,DLinkedNode>存key所对应的链表节点。

tips:

使用 2个虚拟头节点和虚拟尾节点会更加方便处理链表节点的删除和插入操作。

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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
class LRUCache {
// 定义双向链表的类:值,前后指针,无参构造器和有参构造器
class DLinkedNode {
int key;
int value;
DLinkedNode prev;
DLinkedNode next;
public DLinkedNode() {}
public DLinkedNode(int k, int v) {key = k; value = v;}
}

// 定义map、大小、容量、和虚拟头尾节点
private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
private int size;
private int capacity;
private DLinkedNode head, tail;

public LRUCache(int capacity) {
// 初始化
this.size = 0; // size记录 放到map和链表中的节点的个数,不能超过capacity
this.capacity = capacity; // 是LRU的容量
// 虚拟头节点和尾节点
head = new DLinkedNode();
tail = new DLinkedNode();
// 初始化双向链表
head.next = tail;
tail.prev = head;
}

// 1 删除 节点
void removeNode(DLinkedNode node)
{
node.next.prev = node.prev;
node.prev.next = node.next;
}

// 2 添加节点到链表首部
void addToHead(DLinkedNode node)
{
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}

// 将 节点 移动到链表首部
void moveToHead(DLinkedNode node)
{
// 1 删除 节点
removeNode(node);
// 2 添加节点到链表首部
addToHead(node);
}

public int get(int key) {
DLinkedNode node = cache.get(key);
// 从map中尝试获取 key 所对应的node,如果node不存在,则返回-1
if (node == null) {
return -1;
}
// 如果key存在,将node移动到链表首部, 最后返回key对应的node的值
moveToHead(node);
return node.value;
}

// 删除尾节点,并返回
DLinkedNode removeTail()
{
// 1 得到尾节点
DLinkedNode node = tail.prev;
// 2 删除节点
removeNode(node);
return node;
}

public void put(int key, int value) {
DLinkedNode node = cache.get(key);
// 如果 key 不存在
if (node == null)
{
// 那就新建 node ,并加入 map 和 链表首部
DLinkedNode newNode = new DLinkedNode(key, value);
cache.put(key, newNode); // 存到cache map中
addToHead(newNode);// 加入到链表首部
++size;// 节点数量+1
// 如果 链表中的数量 大于 capacity,就要删除链表尾节点
if (size > capacity)
{
// 删除尾节点,尾节点就是最近最少使用的节点,删除后并返回该节点,因为在map中也要删除对应的k-v项
DLinkedNode removed = removeTail();
cache.remove(removed.key); //在map中删除对应的key
--size; // 节点数量 - 1
}
}
else {
// 如果key存在,更新value, 并把节点移动到链表首部
node.value = value;
moveToHead(node);
}
}
}

/**
* 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);
*/

c++写法

? size前有int 输出结果就和预期的不一致

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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
struct DLinkedNode {
int key;
int value;
DLinkedNode* prev;
DLinkedNode* next;
DLinkedNode() : key(0), value(0), prev(NULL), next(NULL) {}
DLinkedNode(int k, int v) : key(k), value(v), prev(NULL), next(NULL) {}
}; // 定义双向链表结构体

class LRUCache {
private:
// 定义哈希表
unordered_map<int, DLinkedNode*> cacheLinked;
// 定义虚拟头节点和尾节点
DLinkedNode* dummy_head;
DLinkedNode* dummy_tail;
int size;
int capacity;

public:
LRUCache(int _capacity) {
size = 0; // ? size前有int 输出结果就和预期的不一致
capacity = _capacity;
dummy_head = new DLinkedNode();
dummy_tail = new DLinkedNode();
dummy_head->next = dummy_tail;
// dummy_tail->next 错了,应该是dummy_tail->prev
dummy_tail->prev = dummy_head;

}

void removeNode(DLinkedNode* node)
{
// 删除
node->prev->next = node->next;
node->next->prev = node->prev;
}

void addToHead(DLinkedNode* node)
{
node->prev = dummy_head;
node->next = dummy_head->next;
dummy_head->next->prev = node;
dummy_head->next = node;

}

void moveToHead(DLinkedNode* node)
{
// 删除
removeNode(node);
// 移动到首部
addToHead(node);
}

int get(int key) {
if (!cacheLinked.count(key))
return -1;

// key 存在, 得到node, 并把node移动到链表首部
DLinkedNode* node = cacheLinked[key];
moveToHead(node);
return node->value;
}

// 删除尾部节点
DLinkedNode* removeTail()
{
// 获得尾部节点
DLinkedNode* node = dummy_tail->prev;
// 删除
removeNode(node);
return node;
}

void put(int key, int value) {
// 判断key是否存在, 如果存在, 就把对应节点更新value,并移动到链表首部

if (!cacheLinked.count(key))
{
// 如果key不存在,则创建新的节点,插入到链表首部,再添加到map中
DLinkedNode* node = new DLinkedNode(key, value);

cacheLinked[key] = node;
addToHead(node);
++size; // 双向链表长度+1

// 如果超出容量,就删除双向链表的尾部节点, 再删除map中的项
if (size > capacity)
{
DLinkedNode* removed = removeTail();
cacheLinked.erase(removed->key);

delete removed; // 防止内存泄漏
--size;
}
}
else {
DLinkedNode* node = cacheLinked[key];
node->value = value;
moveToHead(node);
}
}
};

/**
* 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);
*/