你提到的是一种**高效实现 LRU Cache(最近最少使用缓存)**的思路:使用一个 双向链表(或双端队列) 来维护访问顺序,同时用一个哈希表(map)来记录 key 到链表节点的映射。
在 Python 中,你可以使用:
collections.OrderedDict(已封装好的有序字典)- 或者自己使用
collections.deque+dict模拟 - 或者完全自定义一个双向链表 + 哈希表
下面我将详细讲解并给出代码示例,展示如何用 双向链表 + 哈希表 实现 LRU 缓存。
✅ 一、LRU 缓存的核心需求
- 插入新元素时,将其放在链表头部。
- 访问已有元素时,也要将其移动到链表头部(表示最近使用过)。
- 当缓存满时,删除链表尾部的元素(最久未使用的那个)。
- 所有操作的时间复杂度应为 O(1) 。
🧠 二、数据结构选择
| 数据结构 | 作用 |
|---|---|
双向链表(可以用 deque 或自定义类) | 维护访问顺序,支持 O(1) 的头插和尾删 |
哈希表(Python 中是 dict) | 快速查找 key 是否存在,并定位其在链表中的位置 |
✅ 三、完整 Python 实现(使用 OrderedDict)
这是最简单的方式,因为 OrderedDict 内置了“插入顺序”和“移动到最后”的功能。
python
深色版本
from collections import OrderedDict
class LRUCache:
def __init__(self, capacity: int):
self.cache = OrderedDict()
self.capacity = capacity
def get(self, key: int) -> int:
if key in self.cache:
# 将该键值对移到末尾,表示最近使用过
self.cache.move_to_end(key)
return self.cache[key]
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
# 删除旧位置
self.cache.pop(key)
elif len(self.cache) >= self.capacity:
# 删除最久未使用的项(第一个)
self.cache.popitem(last=False)
# 插入新项到末尾
self.cache[key] = value
示例:
python
深色版本
cache = LRUCache(2)
cache.put(1, 1)
cache.put(2, 2)
print(cache.get(1)) # 返回 1
cache.put(3, 3) # 容量满,移除 (2)
print(cache.get(2)) # 返回 -1(已被移除)
✅ 四、使用 deque + dict 模拟 LRU(更接近底层原理)
虽然不如 OrderedDict 简洁,但这种方式能帮助理解 LRU 的本质逻辑。
python
深色版本
from collections import deque
class LRUCache:
def __init__(self, capacity: int):
self.cache = {}
self.order = deque()
self.capacity = capacity
self.key_count = {}
def get(self, key: int) -> int:
if key in self.cache:
# 移除原有位置
self.order.remove(key)
# 添加到头部
self.order.appendleft(key)
return self.cache[key]
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
# 更新值并调整顺序
self.order.remove(key)
elif len(self.cache) >= self.capacity:
# 删除尾部元素(最近最少使用的)
lru_key = self.order.pop()
del self.cache[lru_key]
# 插入新元素到头部
self.cache[key] = value
self.order.appendleft(key)
⚠️ 注意:deque.remove() 是 O(n) 时间复杂度,所以这不是真正的 O(1) 实现。要真正实现 O(1),需要使用自定义双向链表。
✅ 五、真正的 O(1) 实现(自定义双向链表 + 哈希表)
这是一个完整的 LRU 缓存实现,基于双向链表 + 字典:
python
深色版本
class Node:
def __init__(self, key=None, val=None):
self.key = key
self.val = val
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.cache = {}
# 使用伪头尾节点简化边界处理
self.head = Node()
self.tail = Node()
self.head.next = self.tail
self.tail.prev = self.head
def _add_node(self, node):
"""总是添加到头部"""
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def _remove_node(self, node):
"""从链表中删除节点"""
prev = node.prev
nxt = node.next
prev.next = nxt
nxt.prev = prev
def _move_to_head(self, node):
"""将节点移动到头部"""
self._remove_node(node)
self._add_node(node)
def _pop_tail(self):
"""弹出尾部节点"""
node = self.tail.prev
self._remove_node(node)
return node
def get(self, key: int) -> int:
if key in self.cache:
node = self.cache[key]
self._move_to_head(node)
return node.val
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
node = self.cache[key]
node.val = value
self._move_to_head(node)
else:
if len(self.cache) == self.capacity:
tail = self._pop_tail()
del self.cache[tail.key]
new_node = Node(key, value)
self.cache[key] = new_node
self._add_node(new_node)
示例:
python
深色版本
lru = LRUCache(2)
lru.put(1, 1)
lru.put(2, 2)
print(lru.get(1)) # 返回 1
lru.put(3, 3) # 移除 (2)
print(lru.get(2)) # 返回 -1
📌 总结对比
| 实现方式 | 时间复杂度 | 易读性 | 推荐程度 |
|---|---|---|---|
OrderedDict | O(1) | ✅ 高 | ✅ 推荐(开发快) |
deque + dict | get/put 不是 O(1)(因为 remove) | ✅ 中等 | ❌ 不推荐 |
| 自定义双向链表 | ✅ 真正 O(1) | ❌ 较低 | ✅ 推荐(学习/高性能) |