美文网首页
LRU的Python双向链表实现

LRU的Python双向链表实现

作者: amyhy | 来源:发表于2020-04-07 17:47 被阅读0次

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。

写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

分析
看到题目要我们实现一个可以存储 key-value 形式数据的数据结构,并且可以记录最近访问的 key 值。首先想到的就是用字典来存储 key-value 结构,这样对于查找操作时间复杂度就是 O(1)O(1)。

但是因为字典本身是无序的,所以我们还需要一个类似于队列的结构来记录访问的先后顺序,这个队列需要支持如下几种操作:

在末尾加入一项
去除最前端一项
将队列中某一项移到末尾

考虑单链表。

对于单链表,哈希表的结构类似于 {key: ListNode(value)},即键所对应的是一个节点地址,节点的值是 value。对于链表,遇到上面那种情况时可以在常数的时间内找到对应的节点,但是如果想将它移到尾部则需要从头遍历到该节点才能保证链表不断,对于这种情况需要的时间复杂度也是O(n)

为了解决移到末尾这个问题,需要使用双链表来记录

class ListNode:
    def __init__(self, key=None, val=None):
        self.key = key
        self.val = val
        self.pre = None
        self.next = None


class LRUCache:
    def __init__(self, capacity: int):
        self.capacity = capacity
        self.hashmap = {}
        # 新建两个节点
        self.head = ListNode()
        self.tail = ListNode()
        # 初始化链表为head<->tail
        self.head.next = self.tail
        self.tail.pre = self.head

    # 因为get和put操作都可能将双向链表中的某个节点移到末尾,所以定义一个新的方法
    def move_node_to_tail(self, key):
        node = self.hashmap[key]
        node.pre.next = node.next
        node.next.pre = node.pre
        # 将node插入到尾结点之前
        node.pre = self.tail.pre
        node.next = self.tail
        self.tail.pre.next = node
        self.tail.pre = node

    def get(self, key:int) -> int:
        if key in self.hashmap:
            # 如果已经存在 把该node移到尾部 最新访问
            self.move_node_to_tail(key)
        res = self.hashmap.get(key, -1)
        if res == -1:
            return res
        else:
            return res.val

    def put(self, key: int, val: int) -> None:
        if key in self.hashmap:
            # 如果已经存在 则将原有的直接移动到末尾 需要更新原有的hash值
            self.hashmap[key].val = val
            self.move_node_to_tail(key)
        else:
            if len(self.hashmap) == self.capacity:
                # 去掉hash对应项
                self.hashmap.pop(self.head.next.key)
                # 去掉最久没有被访问过的节点,即头节点之后的节点
                self.head.next = self.head.next.next
                self.head.next.pre = self.head
            # 如果列表没有满 直接插入到尾部
            new = ListNode(key, val)
            new.pre = self.tail.pre
            new.next = self.tail
            self.tail.pre.next = new
            self.tail.pre = new

相关文章

  • leetcode146. LRU缓存机制

    双向链表+哈希表实现LRU

  • LRU缓存算法

    1. LRU缓存可使用一个HashMap和双向链表实现 1.1定义双向链表的节点: 1.2实现:

  • LRU的Python双向链表实现

    运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get...

  • 双向链表python实现

    python 双向链表实现 双向链表实现 链表头部添加 链表尾部添加 插入 删除 查询结点

  • LRU-Swift实现

    双向链表+Map实现,get、put、时间复杂度为O(1).LRU数据结构如下图: LRU LRU(least r...

  • Python数据结构-链表

    自己实现一遍果然感觉不一样 Python实现单链表 Python实现单项循环链表 Python实现双向链表

  • Python实现双向链表

    Python实现双向链表的增删改查,反转链表

  • 如何设计一个内存缓存库

    双向链表 + LRU淘汰算法 + 线程安全 双向链表的设计 用OC来设计双向链表(不是循环链表) 单个节点 整个链...

  • YYMemoryCache刨根问底

    前言 YYMemoryCache缓存内部用双向链表和 NSDictionary 实现了 LRU 淘汰算法,使用pt...

  • LRU 缓存机制实现:哈希表 + 双向链表

    算法详解 LRU 缓存机制可以通过哈希表辅以双向链表实现,我们用一个哈希表和一个双向链表维护所有在缓存中的键值对。...

网友评论

      本文标题:LRU的Python双向链表实现

      本文链接:https://www.haomeiwen.com/subject/ignnphtx.html