Python - 深夜数据结构与算法之 LRUCache

news2025/1/11 23:51:33

目录

一.引言

二.LRU Cache 简介

1.实现特性

2.工作流程

三.LRU Cache 实战

1.HashMap + ListNode

2.OrderedDict

四.总结


一.引言

LRU 即 Least Recently Used 意为最近使用,它是一种局部 Cache 的缓存方法,用于存储最近使用的元素,随着 Cache 中元素的增加,LRU Cache 会逐步挪去结尾的近期未使用的元素。

二.LRU Cache 简介

1.实现特性

LRU Cache 一般由两个要素决定,大小与替换策略。

- 大小 即 Cache 的容量,如果 Cache 非常大,像内存一样,那我们直接一直存就可以了 

- 替换 由于 Cache 一般不会无限制的增加,所以达到容量时,就需要根据策略进行替换删除元素

其实现一般通过 HashMap + Double LinkedList 即 Map + 双端链表实现。

2.工作流程

假设 Cache 的容量为 5,前面 A-E 正常记录 Cache 缓存,而当 F 插入时,根据 LRU 即最近最少使用的原则,排在最早且未被再次使用的 A 会被移出 Cache,而当 C 再次插入时,其会从 -2 的索引提到最前方,此时不涉及元素出链表,只是修改其顺序,后面以此类推。

除了 LRU 外,还有 LFU 其全称为 Least Frequently Used 代表最近使用频次最小,此时需要维护 Cache 内每个元素的使用频次,这里我们介绍 LRU,所以 LFU 就简单带过一下。完整的替换算法大家有兴趣可以 🪜 看一下 Wiki: Cache_replacement_policies。

三.LRU Cache 实战

实现: https://leetcode.cn/problems/lru-cache/description/

◆ 题目分析

实现容量为 Capacity 的 LRU Cache,基于前面的简介,下面我们分别使用 Python 库函数和手动双端队列实现。

1.HashMap + ListNode

class ListNode:
    # 双向链表
    def __init__(self, key=None, value=None):
        self.key = key
        self.value = value
        self.pre = None
        self.next = None

class LRUCache(object):

    def __init__(self, capacity):
        self.capacity = capacity
        self.hashmap = {}

        # 新建 head/tail 节点
        self.head = ListNode()
        self.tail = ListNode()
        
        # 初始化
        self.head.next = self.tail
        self.tail.pre = self.head

    # get put 都可能需要把元素一到末尾,所以添加辅助方法
    def move_node_to_end(self, key):

        # 获取当前节点
        node = self.hashmap[key]

        # Pre -> Node -> Next  =>  Pre <-> Next
        node.pre.next = node.next
        node.next.pre = node.pre

        # pre -> tail  => pre <-> node <-> tail
        node.pre = self.tail.pre
        node.next = self.tail
        self.tail.pre.next = node
        self.tail.pre = node


    def get(self, key):
        """
        :type key: int
        :rtype: int
        """
        # 在链表就移到末尾
        if key in self.hashmap:
            self.move_node_to_end(key)

        res = self.hashmap.get(key, -1)
        if res == -1:
            return res
        else:
            return res.value 
    

    def put(self, key, value):
        """
        :type key: int
        :type value: int
        :rtype: None
        """
        if key in self.hashmap:
            # 无需添加元素,但是需要更新 value 并移动
            self.hashmap[key].value = value
            self.move_node_to_end(key)
        else:
            cur_capacity = len(self.hashmap)
            if cur_capacity == self.capacity:
                self.hashmap.pop(self.head.next.key)
                # 更新前面的元素前后指针
                self.head.next = self.head.next.next
                self.head.next.pre = self.head

            # 容量支持插入新元素
            new = ListNode(key, value)
            self.hashmap[key] = new
        
            new.pre = self.tail.pre
            new.next = self.tail
            self.tail.pre.next = new
            self.tail.pre = new



# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)

代码比较长,但是都是基础的双端链表增删节点的操作,大家可以画示意图查看,更加直观。

2.OrderedDict

class LRUCache(collections.OrderedDict):

    def __init__(self, capacity: int):
        super().__init__()
        self.capacity = capacity


    def get(self, key: int) -> int:
        if key not in self:
            return -1
        self.move_to_end(key)
        return self[key]

    def put(self, key: int, value: int) -> None:
        if key in self:
            self.move_to_end(key)
        self[key] = value
        if len(self) > self.capacity:
            self.popitem(last=False)

Collections 的 OrderedDict 默认包含了上面的功能,如果是在工作中可以这么调用。 

四.总结

上面介绍了 Python 中 LRU Cache 的特性与简单实现,在大数据场景下,除了 LRU Cache 外,还有基于 Time、Freq 等多元的 Cache 方案,我们可以直接调用 Google 的 guava 库,快速上手相关 Cache,提高元素搜索访问的效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1388183.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023.1.15 关于 Redis 持久化 RDB 策略详解

目录 Redis 持久化 Redis 实现持久化的两大策略 RDB 策略 手动触发 save 命令 bgsave 命令 bgsave 命令执行流程 自动触发 rdb 文件 实例演示一 实例演示二 实例演示三 实例演示四 RDB 策略的优缺点 Redis 持久化 什么是持久化&#xff1f; 回答&#xff1a; 将数据存…

高效视频剪辑:视频合并让视频焕然一新,添加背景音乐更动听

随着社交媒体和数字内容的普及&#xff0c;视频剪辑已成为一项常用的技能。除了基本的剪辑技巧外&#xff0c;添加合适的背景音乐也是提升视频质量的方法。下面来看云炫AI智剪的高效视频剪辑技巧——如何批量合并视频&#xff0c;添加动听的背景音乐。 视频合并后的效果展示&a…

Jenkins之pipeline

安装插件 Pipeline Pipeline: Stage View Plugin 创建任务 配置 demo 开始实践 拉取git仓库代码 checkout scmGit(branches: [[name: */main]], extensions: [], userRemoteConfigs: [[url: http://178.119.30.133:8929/root/mytest.git]])通过SonarQube做质量检测 sh …

MAC iterm 显示git分支名

要在Mac上的iTerm中显示Git分支名&#xff0c;您需要使用一个名为“Oh My Zsh”的插件。Oh My Zsh是一个流行的Zsh框架&#xff0c;它提供了许多有用的功能和插件&#xff0c;包括在终端中显示Git分支名。 以下是在iTerm中显示Git分支名的步骤&#xff1a; 1、安装Oh My Zsh&…

芯片烧写工具

问题描述 最近出了一个机器变砖的问题&#xff0c;一些用户使用的设备&#xff0c;头一天晚上用的好好的&#xff0c;第二天来一上电开机就起不来了。 然后就寄回来&#xff0c;返厂维修。一些是因为部分电子器件坏了&#xff0c;还有一些是文件系统问题&#xff0c;重新升级一…

基于Redis+Lua的分布式限流

本文已收录至我的个人网站&#xff1a;程序员波特&#xff0c;主要记录Java相关技术系列教程&#xff0c;共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源&#xff0c;让想要学习的你&#xff0c;不再迷茫。 前面我们了解了如何利用Nginx做网关层限流&#xf…

XSS漏洞:xss-labs靶场通关

xss系列往期文章&#xff1a; 初识XSS漏洞-CSDN博客 利用XSS漏洞打cookie-CSDN博客 目录 第一关 第二关 第三关 第四关 第五关 第六关 第七关 第八关 第九关 第十关 第十一关 第十二关 第十三关 第十四关 第十五关 第十六关 第十七关 第十八关 第十九关 …

概率论与数理统计————古典概型、几何概型和条件概率

一、古典概型 特点 &#xff08;1&#xff09;有限性&#xff1a;试验S的样本空间的有限集合 &#xff08;2&#xff09; 等可能性&#xff1a;每个样本点发生的概率是相等的 公式&#xff1a;P&#xff08;A&#xff09; A为随机事件的样本点数&#xff1b;S是样本…

深度学习笔记(四)——使用TF2构建基础网络的常用函数+简单ML分类实现

文中程序以Tensorflow-2.6.0为例 部分概念包含笔者个人理解&#xff0c;如有遗漏或错误&#xff0c;欢迎评论或私信指正。 截图和程序部分引用自北京大学机器学习公开课 TF2基础常用函数 1、张量处理类 强制数据类型转换&#xff1a; a1 tf.constant([1,2,3], dtypetf.floa…

Docker部署Jira、Confluence、Bitbucket、Bamboo、Crowd,Atlassian全家桶

文章目录 省流&#xff1a;注意&#xff1a;1.docker-compose文件2.其他服务都正常启动&#xff0c;唯独Bitbucket不行。日志错误刚启动时候重启后查询分析原因再针对第一点排查看样子是安装的bitbucket和系统环境有冲突问题&#xff1f; 结论&#xff1a; 省流&#xff1a; b…

Flink-SQL——时态表(Temporal Table)

时态表(Temporal Table) 文章目录 时态表(Temporal Table)数据库时态表的实现逻辑时态表的实现原理时态表的查询实现时态表的意义 Flink中的时态表设计初衷产品价格的例子——时态表汇率的例子——普通表 声明版本表声明版本视图声明普通表 一个完整的例子测试数据代码实现测试…

MATLAB - 使用 TOPP-RA 求解器生成带约束条件的时间最优轨迹

系列文章目录 前言 本例演示如何生成满足速度和加速度限制的轨迹。该示例使用了 contopptraj 函数&#xff0c;该函数使用可达性分析 (RA) 求解受约束的时间最优路径参数化 (TOPP) 轨迹。 一、示例背景 本例解决的是 TOPP 问题&#xff0c;这是一个机器人问题&#xff0c;其目…

vue3+vite项目构建时报错npm ERR! code EPERMnpm ERR! syscall mkdir...

vscode终端中输入npm create vitelatest vueviteproject1 -- --vue命令后报错 具体报错如下&#xff1a; PS D:\project> npm create vitelatest vueviteproject1 -- --vue >> npm ERR! code EPERM npm ERR! syscall mkdir npm ERR! path D:\node\node_cache\_cac…

磁盘raid1降级后,mdxxx rota发生变化

背景 虚拟机系统盘vda后端使用宿主机ssd盘lvm组raid1,虚拟机内部查看vda磁盘类型(rota=1):机械硬盘,vda后端raid1降级导致磁盘类型降级:rota 0---->1,vda磁盘类型显示不正确,应该是ssd类型(rota=0); 分析 1.基础 1.1 linux磁盘类型 Rota表示磁盘类型:(1)0,表…

收银系统源码-智慧新零售系统框架

智慧新零售系统是一套线下线上打通的收银系统&#xff0c;主要给门店提供含线下收银、线上小程序商城、ERP进销存、精细化会员管理、丰富营销插件等为一体的智慧行业解决方案。智慧新零售系统有合伙人、代理商、商户、门店、收银员/导购员等角色&#xff0c;每个角色有相应的权…

从物联网到数字孪生:智慧社区的未来之路

一、物联网在智慧社区中的应用与挑战 随着科技的飞速发展&#xff0c;物联网技术已经深入到我们生活的方方面面&#xff0c;尤其在智慧社区的建设中发挥着举足轻重的作用。物联网通过连接各种设备和系统&#xff0c;为社区居民提供了更便捷、高效的生活方式&#xff0c;同时也…

TortoiseGit 2.15.0.0 安装与配置(图文详细教程)

TortoiseGit的安装与配置 TortoiseGit是Tortoise为Git提供的版本可视化工具&#xff0c;简化了记忆Git命令行的过程&#xff0c;将命令行可视化。 确保自己电脑中已经下载好了git 官网下载TortoiseGit Download – TortoiseGit – Windows Shell Interface to Git 选择64-bi…

net8 rdl rdlc ssrs报表设计器表头合并单元格(垂直合并)

报表设计器下载地址 https://www.microsoft.com/zh-cn/download/details.aspx?id53613 或者从vs扩展插件安装 打开报表设计器&#xff0c;插入矩阵表格&#xff08;只有这个才能支持表头单元格合并&#xff09; 在列单元右建&#xff0c;插入行&#xff0c;根据实际需要添加…

【安全策略】前端 JS 安全对抗浏览器调试方法

一、概念解析 1.1 什么是接口加密 如今这个时代&#xff0c;数据已经变得越来越重要&#xff0c;网页和APP是主流的数据载体。而如果获取数据的接口没有设置任何的保护措施&#xff0c;那么数据的安全性将面临极大的威胁。不仅可能造成数据的轻易窃取和篡改&#xff0c;还可能…

LiveGBS流媒体平台GB/T28181功能-基础配置接入控制白名单黑名单配置控制设备安全接入设备单独配置接入密码

LiveGBS基础配置接入控制白名单黑名单配置控制设备安全接入设备单独配置接入密码 1、白名单配置应用场景2、接入控制2.1、白名单2.2、黑名单 3、搭建GB28181视频直播平台 1、白名单配置应用场景 LiveGBS国标流媒体服务&#xff0c;支持白名单配置。 可在设备注册前&#xff0…