带TTL的LRU缓存的实现-字节手撕-26/10/19

1.普通LRU实现

原题链接:LRU 缓存

python 复制代码
class Node:
    __slots__ = "prev", "next", "key", "value"
    def __init__(self, key = 0, value = None):
        self.key = key
        self.value = value

class LRUCache:
    def __init__(self, c):
        self.c = c
        self.h = {}
        self.dummy = Node()
        self.dummy.next = self.dummy
        self.dummy.prev = self.dummy

    def _remove(self, x):
        x.prev.next = x.next
        x.next.prev = x.prev

    def _put_front(self, x):
        x.next = self.dummy.next
        x.prev = self.dummy
        self.dummy.next.prev = x
        self.dummy.next = x

    def _get_node(self, key):
        if key not in self.h:   return None
        x = self.h[key]
        self._remove(x)
        self._put_front(x)
        return x
    
    def get(self, key):
        x = self._get_node(key)
        return x.value if x else -1

    def put(self, key, value):
        x = self._get_node(key)
        if x is not None:
            x.value = value
            self._remove(x)
            self._put_front(x)
        else:
            x = Node(key, value)
            self.h[key] = x
            self._put_front(x)
            if len(self.h) > self.c:
                back = self.dummy.prev
                del self.h[back.key]
                self._remove(back)

对于实现的方法,我一般采取记忆方式防止漏写(比如_get_node中漏写return x等),下面数字代表几行代码哈哈哈哈。

  • 复杂的方法共两个,_get_node()和_put()
  • _get_node():要记住 1(不在的情况) + 4 (在的情况)
  • put(): 要记住3(不在的情况) + 3(在的情况) + 3(超容量的情况)

2.带TTL的LRU缓存

python 复制代码
import time
class Node:
    __slots__ = "prev", "next", "key", "value", "expire_time"
    def __init__(self, key = 0, value = None, expire_time = 0):
        self.key = key
        self.value = value
        self.expire_time = expire_time

class LRUCache:
    def __init__(self, c, ttl):
        self.c = c
        self.ttl = ttl
        self.h = {}
        self.dummy = Node()
        self.dummy.next = self.dummy
        self.dummy.prev = self.dummy

    def _remove(self, x):
        x.prev.next = x.next
        x.next.prev = x.prev

    def _put_front(self, x):
        x.next = self.dummy.next
        x.prev = self.dummy
        self.dummy.next.prev = x
        self.dummy.next = x
    # 新增一个函数
    def _is_expired(self, x):
        return time.time() > x.expire_time

    def _get_node(self, key):
        if key not in self.h:
            return None
        x = self.h[key]
        if self._is_expired(x):
            del self.h[key]
            self._remove(x)
            return None
        self._remove(x)
        self._put_front(x)
        return x

    def get(self, key):
        x = self._get_node(key)
        return x.value if x else -1
    # 直接踢出末端的实现,几乎和普通LRU一致
    def put(self, key, value):
        x = self._get_node(key)
        if x:
            x.value = value
            x.expire_time = time.time() + self.ttl  # 就多了这一行
            self._remove(x)
            self._put_front(x)
        else:
            x = Node(key, value, time.time() + self.ttl)
            self.h[key] = x
            self._put_front(x)
            if len(self.h) > self.c:
                back = self.dummy.prev
                del self.h[back.key]
                self._remove(back)
                
    # 先踢出过期的,如果没有踢出末端
    def put(self, key, value):
        x = self._get_node(key)
        if x:
            x.value = value
            x.expire_time = time.time() + self.ttl
            self._remove(x)
            self._put_front(x)
        else:
            x = Node(key, value, time.time() + self.ttl)
            self.h[key] = x
            self._put_front(x)
            if len(self.h) > self.c:
                cur = self.dummy.prev
                flag = False
                while cur != self.dummy:
                    if self._is_expired(cur):
                        del self.h[cur.key]
                        self._remove(cur)
                        flag = True
                        break
                    cur = cur.prev
                if not flag:
                    back = self.dummy.prev
                    del self.h[back.key]
                    self._remove(back)

同理,只要我们学会了普通LRU

  • _get_node():要记住 1(不在的情况) + 4 (在的情况) + 4(处理过期的情况)
  • 第1个put(): 要记住4(不在的情况) + 3(在的情况) + 3(超容量的情况)
  • 第2个put():要记住4(在的情况,多一个过期) + 3(不在的情况) + 3(超容量的情况2) + 超容量的情况1
相关推荐
Pniubi9 分钟前
力扣73 矩阵置零
算法·leetcode·矩阵
布莱克60510 小时前
C++ 中 map 的 insert 与 emplace:key 已存在时会覆盖吗?
开发语言·数据结构·c++·算法·map
D e re k ZH13 小时前
C++ 系统学习手记:从语法细节到工程实践
开发语言·数据结构·c++·算法
石小石Orz14 小时前
AI 正在蚕食我们的编码能力
前端·后端·算法
民乐团扒谱机16 小时前
【微实验】NSGA-II(非支配排序遗传算法)——解决多目标优化问题的“自然选择模拟器”
linux·人工智能·算法
青少儿编程课堂16 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:中缀表达式求值解析
c++·python·算法·bfs·信息学竞赛
武子康18 小时前
Qwen-Drive 到底是什么:4B 级 VLM 如何成为驾驶策略底座
人工智能·算法·机器学习
zh_xuan19 小时前
LeeCode 496. 下一个更大元素I
数据结构·算法·栈·单调栈
机 _ 长19 小时前
05 智算运维|8 张卡怎么才算「捆成一张」:NCCL 实测与拓扑
运维·人工智能·算法·智算运维