Skip to content

Commit 4305860

Browse files
committed
【update】数据结构-LRU缓存
1 parent 2492f6b commit 4305860

File tree

2 files changed

+124
-130
lines changed

2 files changed

+124
-130
lines changed

Diff for: C-算法/专题-A-数据结构_Advanced.md

+124-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
专题-高级数据结构
1+
专题-数据结构_Advanced
22
===
33

44
Index
55
---
66
<!-- TOC -->
77

88
- [树状数组](#树状数组)
9-
- [树状数组的构建(以区间和问题为例)](#树状数组的构建以区间和问题为例)
10-
- [树状数组的特点](#树状数组的特点)
11-
- [相关问题](#相关问题)
12-
- [相关阅读](#相关阅读)
9+
- [树状数组的构建(以区间和问题为例)](#树状数组的构建以区间和问题为例)
10+
- [树状数组的特点](#树状数组的特点)
11+
- [相关问题](#相关问题)
12+
- [相关阅读](#相关阅读)
1313
- [线段树](#线段树)
1414
- [字典树(Trie)](#字典树trie)
15+
- [数据结构设计](#数据结构设计)
16+
- [LRU 缓存](#lru-缓存)
1517

1618
<!-- /TOC -->
1719

@@ -151,6 +153,122 @@ void solve() {
151153
### 相关阅读
152154
- [夜深人静写算法(三)- 树状数组](https://blog.csdn.net/WhereIsHeroFrom/article/details/78922383) - CSDN博客
153155
156+
<!--
154157
## 线段树
155158
156-
## 字典树(Trie)
159+
## 字典树(Trie)
160+
-->
161+
162+
## 数据结构设计
163+
164+
### LRU 缓存
165+
> LeetCode/[146. LRU缓存机制](https://leetcode-cn.com/problems/lru-cache/description/)
166+
167+
**思路**
168+
- **双向链表** + haspmap
169+
- 数据除了被保存在链表中,同时也保存在 map 中;前者用于记录数据的顺序结构,后者以实现 `O(1)` 的访问。
170+
- **更新过程**:
171+
- 新数据插入到链表头部
172+
- 每当缓存命中(即缓存数据被访问),则将数据移到链表头部
173+
- 当链表满的时候,将链表尾部的数据丢弃
174+
- **操作**:
175+
- `put(key, value)`:如果 key 在 hash_map 中存在,则先**重置对应的 value 值**,然后获取对应的节点,将节点从链表移除,并移动到链表的头部;若果 key 在 hash_map 不存在,则新建一个节点,并将节点放到链表的头部。当 Cache 存满的时候,将链表最后一个节点删除。
176+
- `get(key)`:如果 key 在 hash_map 中存在,则把对应的节点放到链表头部,并返回对应的value值;如果不存在,则返回-1。
177+
178+
**C++**(AC)
179+
```C++
180+
// 缓存节点(双端队列)
181+
struct CacheNode {
182+
int key;
183+
int value;
184+
CacheNode *pre, *next;
185+
CacheNode(int k, int v) : key(k), value(v), pre(nullptr), next(nullptr) {}
186+
};
187+
188+
class LRUCache {
189+
int size = 0;
190+
CacheNode* head = nullptr;
191+
CacheNode* tail = nullptr;
192+
unordered_map<int, CacheNode*> dp; // hash_map
193+
194+
void remove(CacheNode *node) {
195+
if (node != head) { // 修改后序节点是需判断是否头结点
196+
node->pre->next = node->next;
197+
}
198+
else {
199+
head = node->next;
200+
}
201+
202+
if (node != tail) { // 修改前序节点是需判断是否尾结点
203+
node->next->pre = node->pre;
204+
}
205+
else {
206+
tail = node->pre;
207+
}
208+
209+
// remove 时不销毁该节点
210+
//delete node;
211+
//node = nullptr;
212+
}
213+
214+
void setHead(CacheNode *node) {
215+
node->next = head;
216+
node->pre = nullptr;
217+
218+
if (head != nullptr) {
219+
head->pre = node;
220+
}
221+
head = node;
222+
223+
if (tail == nullptr) {
224+
tail = head;
225+
}
226+
}
227+
public:
228+
LRUCache(int capacity) : size(capacity) { }
229+
230+
int get(int key) {
231+
auto it = dp.find(key);
232+
if (it != dp.end()) {
233+
auto node = dp[key];
234+
235+
// 如果命中了,把该节点移动到头部
236+
remove(node);
237+
setHead(node);
238+
239+
return node->value;
240+
}
241+
242+
return -1;
243+
}
244+
245+
void put(int key, int value) {
246+
auto it = dp.find(key);
247+
if (it != dp.end()) {
248+
auto node = dp[key];
249+
250+
node->value = value; // 更新
251+
remove(node);
252+
setHead(node);
253+
}
254+
else {
255+
auto node = new CacheNode(key, value);
256+
setHead(node);
257+
dp[key] = node;
258+
259+
// 关键:判断容量
260+
//if (dp.size() >= size) { // 若先删除节点,则为 >=
261+
if (dp.size() > size) { // 若先存入 dp,则为 >
262+
auto it = dp.find(tail->key);
263+
remove(tail);
264+
265+
// 这里才销毁内存(即使不销毁也能过 LeetCode)
266+
delete it->second;
267+
it->second = nullptr;
268+
269+
dp.erase(it); // 先销毁,在移除
270+
}
271+
}
272+
}
273+
};
274+
```

Diff for: C-算法/专题-A-数据结构_设计.md

-124
This file was deleted.

0 commit comments

Comments
 (0)