Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
如何用Python实现一个LRU缓存?_创想鸟

如何用Python实现一个LRU缓存?

答案:LRU缓存通过字典和双向链表结合实现,字典提供O(1)查找,双向链表维护访问顺序,确保插入、删除和访问更新均为O(1)操作。每次get或put操作都会将对应节点移至链表头部,当缓存满时,尾部节点被移除,从而保证最久未使用项优先淘汰。虚拟头尾节点简化边界处理,而OrderedDict虽可替代实现,但自定义方式更利于理解底层机制。

如何用python实现一个lru缓存?

在Python中实现LRU(Least Recently Used)缓存,核心思路在于巧妙地结合哈希表(Python的字典)和双向链表。字典确保我们能以O(1)的平均时间复杂度快速查找缓存中的任何项,而双向链表则负责维护项的访问顺序,使得最近使用的项总在链表头部,最久未使用的项(即待淘汰项)总在链表尾部,这样无论是更新访问顺序还是进行淘汰,都能保持高效。

解决方案

class Node:    """双向链表节点定义"""    def __init__(self, key, value):        self.key = key        self.value = value        self.prev = None        self.next = Noneclass LRUCache:    """    LRU缓存实现,结合字典和双向链表    """    def __init__(self, capacity: int):        if capacity  int:        """        获取缓存项。如果存在,将其移动到链表头部并返回其值;否则返回-1。        """        if key not in self.cache:            return -1        node = self.cache[key]        self._move_to_head(node)        return node.value    def put(self, key: int, value: int) -> None:        """        放入缓存项。        如果key已存在,更新其值并将其移动到链表头部。        如果key不存在:            如果缓存未满,创建新节点并添加到链表头部。            如果缓存已满,移除链表尾部(最久未使用)的节点,再添加新节点到头部。        """        if key in self.cache:            node = self.cache[key]            node.value = value            self._move_to_head(node)        else:            new_node = Node(key, value)            self.cache[key] = new_node            self._add_node(new_node)            if len(self.cache) > self.capacity:                # 移除最久未使用的节点 (tail.prev)                lru_node = self.tail.prev                self._remove_node(lru_node)                del self.cache[lru_node.key]

LRU缓存为何偏爱双向链表而非普通列表?

在我看来,LRU缓存选择双向链表,这背后是性能和操作复杂度的深思熟虑。我们都知道,Python的

list

在末尾添加(

append

)和删除(

pop

)通常是O(1)操作,但如果在中间或头部进行插入或删除,其时间复杂度就直接飙升到O(N),因为需要移动后续所有元素。对于LRU缓存来说,每次访问一个元素,都需要将其“提升”到“最近使用”的位置,这通常意味着从当前位置删除,再插入到链表头部。如果用普通列表,这个“提升”操作会非常昂贵。

想象一下,我们缓存了1000个项目,突然访问了第500个。如果用普通列表,我们得先找到它(O(N)),然后删除它(O(N)),再把它加到列表开头(又是一个O(N)),这简直是性能灾难。而双向链表就不同了。每个节点都存储了指向前一个和后一个节点的引用。这意味着一旦我们通过字典以O(1)时间找到某个节点,我们就可以在O(1)时间内完成它的删除(只需修改它前后节点的

next

和

prev

指针)和插入(同样是修改几个指针)。这种效率上的巨大差异,正是双向链表在LRU实现中不可或缺的原因。它让我们的缓存操作,特别是“更新访问顺序”这一核心逻辑,保持了极高的效率。

如何处理缓存容量限制和淘汰策略?

处理LRU缓存的容量限制和淘汰策略,是整个实现的关键。我的做法是,在

LRUCache

的

__init__

方法中,我们首先设定一个

capacity

。这个

capacity

就是缓存能容纳的最大项目数。

立即学习“Python免费学习笔记(深入)”;

当

put

方法被调用时,我们首先检查要插入的

key

是否已经存在于

self.cache

字典中。

如果

key

已存在:这表示我们只是更新一个现有项。在这种情况下,我们更新其

value

,然后最关键的一步是调用

_move_to_head

方法,将其对应的节点从链表当前位置移除,再添加到链表的头部。这反映了它刚刚被“使用”了,所以现在是最新的。如果

key

不存在:这是一个全新的项。我们首先创建一个新的

Node

,然后将其添加到

self.cache

字典中,并调用

_add_node

方法将其添加到链表的头部。紧接着,我们就需要检查缓存是否“超载”了。我们通过

len(self.cache) > self.capacity

来判断当前缓存中的项目数量是否超过了设定的

capacity

。如果超载了,这意味着我们必须淘汰一个项目来为新项目腾出空间。LRU的策略是淘汰“最久未使用的”项目。在我们的双向链表中,这个项目就是紧挨着虚拟尾节点

self.tail

的前一个节点(即

self.tail.prev

)。我们称之为

lru_node

。我们调用

_remove_node(lru_node)

将其从链表中移除,然后通过

del self.cache[lru_node.key]

将其从字典中也删除,完成彻底的淘汰。

这种机制确保了缓存始终在容量限制内运行,并且每次淘汰都严格遵循了“最久未使用”的原则。虚拟头尾节点的设计,更是简化了链表边缘情况的处理,让代码逻辑更清晰。

Python内置的

OrderedDict

能否替代自定义LRU实现?

当然可以,而且在很多简单场景下,使用Python标准库

collections

模块中的

OrderedDict

来实现LRU缓存会显得非常简洁高效。

OrderedDict

本身就维护了键值对的插入顺序。它的

move_to_end

方法和在插入时检查容量并删除最老项的机制,与LRU缓存的逻辑高度契合。

一个基于

OrderedDict

的LRU实现大致会是这样:

from collections import OrderedDictclass LRUCacheOrderedDict:    def __init__(self, capacity: int):        self.capacity = capacity        self.cache = OrderedDict()    def get(self, key: int) -> int:        if key not in self.cache:            return -1        self.cache.move_to_end(key) # 将key移动到末尾,表示最近使用        return self.cache[key]    def put(self, key: int, value: int) -> None:        if key in self.cache:            self.cache.move_to_end(key) # 存在则移动到末尾        self.cache[key] = value # 更新或添加        if len(self.cache) > self.capacity:            self.cache.popitem(last=False) # 移除最老(最久未使用)的项

这种实现方式确实非常优雅,代码量大大减少,并且由于

OrderedDict

是用C实现的,其内部操作通常效率很高。

不过,话说回来,尽管

OrderedDict

能很好地完成任务,但它也隐藏了LRU缓存底层双向链表的精妙机制。对于初学者或者需要深入理解数据结构和算法的开发者来说,自己动手实现一个基于字典和双向链表的LRU缓存,就像我们前面做的那样,其教育价值是

OrderedDict

无法替代的。它能让我们更清晰地看到每个操作是如何影响底层数据结构的,以及为什么这些数据结构的选择如此关键。在面试或者需要对性能有极致掌控的场景下,理解并能手写底层逻辑,往往比仅仅会用库函数更能体现技术深度。所以,选择哪种方式,最终还是取决于具体的需求:追求简洁快速就用

OrderedDict

,追求深入理解和精细控制则倾向于自定义实现。

以上就是如何用Python实现一个LRU缓存?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1370166.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
使用BeautifulSoup在HTML中提取带高亮标记的文本并维护其原始顺序
上一篇 2025年12月14日 10:18:14
Python BeautifulSoup:按序提取HTML文本及高亮标识
下一篇 2025年12月14日 10:18:28

相关推荐

  • [WPF自定义控件库]排序、筛选以及高亮

    [WPF自定义控件库]排序、筛选以及高亮[WPF自定义控件库]排序、筛选以及高亮[WPF自定义控件库]排序、筛选以及高亮[WPF自定义控件库]排序、筛选以及高亮

    要让列表的内容更容易查找,我们可以通过排序、筛选和高亮功能来优化列表。假设有一个本地数据源的列表,由于内容太多,查找特定数据会比较困难。通过改造后的列表,可以看到这些优化后的效果。 在WPF中实现数据排序的常规方法是使用CollectionViewSource。CollectionViewSourc…

    2026年10月2日 • 用户投稿
    100
  • sublime写完代码怎么运行

    sublime写完代码怎么运行sublime写完代码怎么运行sublime写完代码怎么运行sublime写完代码怎么运行

    在 Sublime Text 中运行代码的方法取决于代码语言,可通过以下方法实现:Python:使用 SublimeREPL 插件或 Cmd/Ctrl + B。JavaScript/Node.js:使用 SublimeREPL 插件或 Cmd/Ctrl + B。其他语言:安装特定插件以获得运行代码功…

    2026年10月2日 • 用户投稿
    000
  • 高德外卖订单被取消_高德外卖订单被取消原因分析

    高德外卖订单被取消_高德外卖订单被取消原因分析高德外卖订单被取消_高德外卖订单被取消原因分析高德外卖订单被取消_高德外卖订单被取消原因分析高德外卖订单被取消_高德外卖订单被取消原因分析

    订单被取消可能因骑手未确认取餐或主动取消、商家出餐延迟、库存不同步、平台策略调整如系统自动取消低优先级订单,或用户支付失败、账户异常等原因导致。 如果您在高德平台上下单外卖后,订单被突然取消,这可能会影响您的用餐计划。此类问题通常与骑手、商家或系统策略有关。以下是可能导致订单被取消的具体原因及分析。…

    2026年10月2日 • 用户投稿
    300
  • JavaFX动态绑定:如何高效管理可变依赖集合

    JavaFX动态绑定:如何高效管理可变依赖集合JavaFX动态绑定:如何高效管理可变依赖集合JavaFX动态绑定:如何高效管理可变依赖集合JavaFX动态绑定:如何高效管理可变依赖集合

    在JavaFX中,数据绑定是实现UI与数据模型同步的关键机制。然而,在处理某些复杂场景,特别是当绑定的依赖项本身是一个动态变化的集合时,传统的绑定方式可能会遇到挑战。例如,在图可视化应用中,一个顶点的某些属性(如自环的优选角度)可能依赖于其所有邻居节点的位置。当图结构动态变化,即邻居列表增删时,如何…

    2026年10月2日 • 用户投稿
    000
  • 如何在Elser AI Comics中修改和优化AI生成的漫画角色形象?

    如何在Elser AI Comics中修改和优化AI生成的漫画角色形象?如何在Elser AI Comics中修改和优化AI生成的漫画角色形象?如何在Elser AI Comics中修改和优化AI生成的漫画角色形象?如何在Elser AI Comics中修改和优化AI生成的漫画角色形象?

    文章主要探讨了如何提高团队协作效率,并提出了三个关键策略:一是明确分工与责任,确保每位成员清楚自身任务;二是加强沟通机制,定期召开会议并使用协作工具提升信息共享效率;三是建立反馈文化,鼓励成员提出意见并及时调整工作方式。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 Deep…

    2026年10月2日 • 用户投稿
    100
  • CentOS 7安装fail2ban + Firewalld防止爆破与CC攻击

    fail2ban可以监控系统日志,并根据日志中的错误信息执行相应的屏蔽操作。大多数在线教程都介绍了fail2ban与iptables的组合,但考虑到centos 7自带firewalld,并且使用firewalld作为网络防火墙更为简便,本文将介绍如何结合fail2ban和firewalld来防范暴…

    2026年10月2日
    100
  • Effidit的”智能扩写”功能如何让短文变得更丰富?有哪些技巧?

    Effidit的”智能扩写”功能如何让短文变得更丰富?有哪些技巧?Effidit的”智能扩写”功能如何让短文变得更丰富?有哪些技巧?Effidit的”智能扩写”功能如何让短文变得更丰富?有哪些技巧?Effidit的”智能扩写”功能如何让短文变得更丰富?有哪些技巧?

    effidit智能扩写后文章质量不高时,可采取以下方法提升效果:1. 调整输入内容,确保原文清晰具体;2. 分段扩写以控制方向;3. 人工修改冗余与不连贯部分;4. 更换提示词引导ai方向;5. 持续学习积累使用经验。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepS…

    2026年10月2日 • 用户投稿
    1000
  • 苹果Safari浏览器删了怎么找回来_Safari应用恢复与重新下载

    苹果Safari浏览器删了怎么找回来_Safari应用恢复与重新下载苹果Safari浏览器删了怎么找回来_Safari应用恢复与重新下载苹果Safari浏览器删了怎么找回来_Safari应用恢复与重新下载苹果Safari浏览器删了怎么找回来_Safari应用恢复与重新下载

    答案:可通过摇动设备、iCloud同步、第三方工具、iTunes备份或检查网站数据恢复Safari书签及历史记录。首先尝试摇动iPhone撤销删除操作,若开启iCloud同步可跨设备找回数据,也可通过专业软件扫描残留文件,或从iTunes备份还原整机数据,最后检查Safari高级设置中“网站数据”是…

    2026年10月2日 • 用户投稿
    900
  • 解决Jackson反序列化时布尔字段默认值失效问题

    解决Jackson反序列化时布尔字段默认值失效问题解决Jackson反序列化时布尔字段默认值失效问题解决Jackson反序列化时布尔字段默认值失效问题解决Jackson反序列化时布尔字段默认值失效问题

    本文深入探讨了在使用Lombok和Jackson进行数据序列化与反序列化时,Boolean包装类型字段的默认值可能无法正确生效的问题。通过分析Boolean与boolean两种类型的特性差异,揭示了导致NullPointerException的根本原因。文章提供了将字段类型从Boolean更改为bo…

    2026年10月2日 • 用户投稿
    900
  • 加速迈向智能世界华为即将亮相2025中国国际信息通信展

    加速迈向智能世界华为即将亮相2025中国国际信息通信展加速迈向智能世界华为即将亮相2025中国国际信息通信展加速迈向智能世界华为即将亮相2025中国国际信息通信展加速迈向智能世界华为即将亮相2025中国国际信息通信展

    2025中国国际信息通信展将于2025年9月24日-26日在北京举行,华为将以“加速迈向智能世界”为主题参展,联合客户与合作伙伴全面呈现其在5g-a、f5g-a、ai、专线+x、adn等领域的最新成果与解决方案。展会期间,华为还将重点呈现ai技术在个人、家庭及行业场景中带来的创新业务与全新体验。 9…

    2026年10月2日 • 用户投稿
    000
  • 为什么网上的评测数据和你实际使用有差距?

    评测数据与实际体验差异源于测试环境理想化、侧重极限性能、个体使用习惯及心理预期不同,加上软件更新影响,导致真实表现偏离实验室结果。 网上评测数据和实际使用体验存在差距,是很多用户都遇到过的问题。这并不是某个平台或评测者故意误导,而是由多个客观因素共同导致的。下面从几个关键角度来解释这种差异的来源。 …

    2026年10月2日
    100
  • 豆包AI编程助手用法 豆包AI代码编写教程

    豆包AI编程助手用法 豆包AI代码编写教程豆包AI编程助手用法 豆包AI代码编写教程豆包AI编程助手用法 豆包AI代码编写教程豆包AI编程助手用法 豆包AI代码编写教程

    豆包ai编程助手的核心使用方法包括代码补全、错误排查、代码优化和学习辅助。在代码补全时,应明确输入意图并配合注释提示ai生成准确代码;遇到报错可将完整错误信息交给ai分析原因;已有代码可通过ai建议优化为更高效写法;还可用于实时学习语法和库用法。关键在于清晰表达需求以获得有效帮助。 ☞☞☞AI 智能…

    2026年10月2日 • 用户投稿
    100
  • Jackson与Lombok布尔类型默认值陷阱与最佳实践

    Jackson与Lombok布尔类型默认值陷阱与最佳实践Jackson与Lombok布尔类型默认值陷阱与最佳实践Jackson与Lombok布尔类型默认值陷阱与最佳实践Jackson与Lombok布尔类型默认值陷阱与最佳实践

    本文深入探讨了在使用Jackson进行JSON反序列化时,Lombok注解修饰的Java类中Boolean包装类型字段默认值失效的问题。当JSON中缺少该字段时,Boolean字段会被反序列化为null而非预设的默认值。文章阐明了将字段类型从Boolean改为boolean(基本数据类型)是解决此问…

    2026年10月2日 • 用户投稿
    000
  • Jackson反序列化:Lombok与布尔类型字段默认值处理指南

    Jackson反序列化:Lombok与布尔类型字段默认值处理指南Jackson反序列化:Lombok与布尔类型字段默认值处理指南Jackson反序列化:Lombok与布尔类型字段默认值处理指南Jackson反序列化:Lombok与布尔类型字段默认值处理指南

    本文深入探讨了在使用Lombok注解的Java类中,Jackson进行JSON反序列化时,布尔类型字段默认值失效导致NullPointerException的问题。核心问题在于Boolean包装类型在JSON字段缺失时会被反序列化为null,而解决方法是推荐使用Java原始类型boolean,它在字…

    2026年10月2日 • 用户投稿
    100
  • OpenAI 发布新编程模型 GPT‑5‑Codex,优化 Agentic Coding 能力

    OpenAI 发布新编程模型 GPT‑5‑Codex,优化 Agentic Coding 能力OpenAI 发布新编程模型 GPT‑5‑Codex,优化 Agentic Coding 能力OpenAI 发布新编程模型 GPT‑5‑Codex,优化 Agentic Coding 能力OpenAI 发布新编程模型 GPT‑5‑Codex,优化 Agentic Coding 能力

    openai 今日凌晨推出全新升级的新模型 gpt‑5‑codex,这是其在gpt-5基础上专门为软件工程优化的模型版本,进一步提升了codex中的智能体编程(agentic coding)能力。 官方表示,该版本在代码审查、功能开发、大规模重构等场景中表现显著提升,并且“在测试中可连续独立工作超过…

    2026年10月2日 • 用户投稿
    000
  • 用豆包AI生成Python文本分析代码

    用豆包AI生成Python文本分析代码用豆包AI生成Python文本分析代码用豆包AI生成Python文本分析代码用豆包AI生成Python文本分析代码

    想用豆包ai写python文本分析代码的关键在于给出清晰指令。1. 首先明确分析内容,如处理中英文、分词、词频统计或情感分析,并具体说明是否去停用词等细节;2. 可让豆包推荐适用库和结构,如jieba、collections.counter、re或textblob,并提供基本代码框架;3. 也可直接…

    2026年10月2日 • 用户投稿
    100
  • Safari浏览器怎么查看下载的软件_Safari下载文件管理与查找

    Safari浏览器怎么查看下载的软件_Safari下载文件管理与查找Safari浏览器怎么查看下载的软件_Safari下载文件管理与查找Safari浏览器怎么查看下载的软件_Safari下载文件管理与查找Safari浏览器怎么查看下载的软件_Safari下载文件管理与查找

    首先通过Safari浏览器书签图标进入“下载项”查看最近文件,再前往“文件”App的“下载”文件夹查找所有内容,最后可在设置中更改默认下载位置至指定文件夹以便管理。 如果您在使用Safari浏览器下载文件后,无法找到已下载的软件或文件,可能是由于iOS系统对文件存储位置的管理机制所致。以下是查看和管…

    2026年10月2日 • 用户投稿
    200
  • Java字符串压缩实战:优化重复字符计数与末尾处理

    本教程深入探讨Java中字符串压缩(如abbbccccc压缩为ab3c4)的实现方法。我们将重点解析常见的循环计数逻辑,并着重解决在处理字符串末尾连续字符时容易出现的计数遗漏问题。通过提供优化后的代码示例和详细解释,帮助开发者构建健壮高效的字符串压缩功能。 什么是字符串压缩? 字符串压缩是一种常见的…

    2026年10月2日
    200
  • bilibili客户端如何下载视频_bilibili客户端视频下载的实用指南

    bilibili客户端如何下载视频_bilibili客户端视频下载的实用指南bilibili客户端如何下载视频_bilibili客户端视频下载的实用指南bilibili客户端如何下载视频_bilibili客户端视频下载的实用指南bilibili客户端如何下载视频_bilibili客户端视频下载的实用指南

    首先使用B站客户端缓存视频,登录后点击播放页的“缓存”按钮选择清晰度下载,完成后在“我的-下载”中查看;缓存文件为加密格式,仅限App内播放。若需通用MP4格式,可进入缓存目录找到视频和音频的m4s文件,删除各自开头9个“0”后,用视频合并工具将两者合并并输出为MP4。此外,也可使用“哔哩缓存助手”…

    2026年10月2日 • 用户投稿
    000
  • Jackson与Lombok:解决布尔类型字段默认值反序列化为Null的问题

    Jackson与Lombok:解决布尔类型字段默认值反序列化为Null的问题Jackson与Lombok:解决布尔类型字段默认值反序列化为Null的问题Jackson与Lombok:解决布尔类型字段默认值反序列化为Null的问题Jackson与Lombok:解决布尔类型字段默认值反序列化为Null的问题

    在使用Jackson和Lombok时,布尔类型字段在JSON反序列化过程中默认值失效导致NullPointerException是一个常见问题。本文深入探讨了将包装类型Boolean改为基本类型boolean是解决此问题的有效方法。当JSON中缺少该字段时,基本类型boolean会自动初始化为fal…

    2026年10月2日 • 用户投稿
    000

发表回复

登录后才能评论
关注微信