lru python实现

129 阅读3分钟

你提到的是一种**高效实现 LRU Cache(最近最少使用缓存)**的思路:使用一个 双向链表(或双端队列) 来维护访问顺序,同时用一个哈希表(map)来记录 key 到链表节点的映射。

在 Python 中,你可以使用:

  • collections.OrderedDict(已封装好的有序字典)
  • 或者自己使用 collections.deque + dict 模拟
  • 或者完全自定义一个双向链表 + 哈希表

下面我将详细讲解并给出代码示例,展示如何用 双向链表 + 哈希表 实现 LRU 缓存。


✅ 一、LRU 缓存的核心需求

  1. 插入新元素时,将其放在链表头部。
  2. 访问已有元素时,也要将其移动到链表头部(表示最近使用过)。
  3. 当缓存满时,删除链表尾部的元素(最久未使用的那个)。
  4. 所有操作的时间复杂度应为 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

📌 总结对比

实现方式时间复杂度易读性推荐程度
OrderedDictO(1)✅ 高✅ 推荐(开发快)
deque + dictget/put 不是 O(1)(因为 remove)✅ 中等❌ 不推荐
自定义双向链表✅ 真正 O(1)❌ 较低✅ 推荐(学习/高性能)