热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python实现LRU算法的2种方法

这篇文章主要介绍了Python实现LRU算法的2种方法,本文分别给出了用OrderedDict实现、用dict+list实现两种方法,需要的朋友可以参考下
LRU:least recently used,最近最少使用算法。它的使用场景是:在有限的空间中存储对象时,当空间满时,会按一定的原则删除原有的对象,常用的原则(算法)有LRU,FIFO,LFU等。在计算机的Cache硬件,以及主存到虚拟内存的页面置换,还有Redis缓存系统中都用到了该算法。我在一次面试和一个笔试时,也遇到过这个问题。

LRU的算法是比较简单的,当对key进行访问时(一般有查询,更新,增加,在get()和set()两个方法中实现即可)时,将该key放到队列的最前端(或最后端)就行了,这样就实现了对key按其最后一次访问的时间降序(或升序)排列,当向空间中增加新对象时,如果空间满了,删除队尾(或队首)的对象。

在Python中,可以使用collections.OrderedDict很方便的实现LRU算法,当然,如果你想不到用OrderedDict,那可以用dict+list来实现。本文主要参考了LRU CACHE IN PYTHON,写的非常好,既实现了功能,又简洁易读。方法一的代码与参考文章基本相同,方法二是我自己想出来的,比较繁琐一些,其实OrderedDict本身也是类似的这种机制来实现的有序。

不过,下面的实现是有问题的,这个cache的key:value键值对中,value只能是不可变类型。因为,如果value是可变类型,那对于同一个key,所有调用get(key)方法返回的value都是指向同一个可变对象的,当修改其中一个value时,那所有的value都会被修改了,即使你没有调用set()方法也会这样。这是我们不希望看到的。解决方法我想到了两种,一是可变对象序列化后再存储,即将可变对象转为不可变对象;二是仍存储可变对象,但get()时,返回一个深拷贝,这样每个get()调用返回的对象就不会相互影响了。推荐第一种方法。另外,对于key,推荐使用str/unicode类型。

当并发时,还会存在一个问题,因为这涉及到对公共资源的写操作,所以必须要对set()加锁。其实,在并发情况下,所有对公共资源的写操作都要加锁。如果不存在并发的情况,只有单线程,那可以不加锁。

方法一:用OrderedDict实现(推荐)

代码如下:


from collections import OrderedDict


class LRUCache(OrderedDict):
'''不能存储可变类型对象,不能并发访问set()'''

def __init__(self,capacity):
self.capacity = capacity
self.cache = OrderedDict()

def get(self,key):
if self.cache.has_key(key):
value = self.cache.pop(key)
self.cache[key] = value
else:
value = None

return value

def set(self,key,value):
if self.cache.has_key(key):
value = self.cache.pop(key)
self.cache[key] = value
else:
if len(self.cache) == self.capacity:
self.cache.popitem(last = False) #pop出第一个item
self.cache[key] = value
else:
self.cache[key] = value


测试代码如下

代码如下:


c = LRUCache(5)

for i in range(5,10):
c.set(i,10*i)


print c.cache, c.cache.keys()

c.get(5)
c.get(7)

print c.cache, c.cache.keys()

c.set(10,100)
print c.cache, c.cache.keys()

c.set(9,44)
print c.cache, c.cache.keys()

输出如下

代码如下:


OrderedDict([(5, 50), (6, 60), (7, 70), (8, 80), (9, 90)]) [5, 6, 7, 8, 9]
OrderedDict([(6, 60), (8, 80), (9, 90), (5, 50), (7, 70)]) [6, 8, 9, 5, 7]
OrderedDict([(8, 80), (9, 90), (5, 50), (7, 70), (10, 100)]) [8, 9, 5, 7, 10]
OrderedDict([(8, 80), (5, 50), (7, 70), (10, 100), (9, 90)]) [8, 5, 7, 10, 9]


方法二:用dict+list实现(不推荐)

代码如下:


class LRUCache(object):
'''不能存储可变类型对象,不能并发访问set()'''

def __init__(self,capacity):
self.l = []
self.d = {}
self.capacity = capacity

def get(self,key):
if self.d.has_key(key):
value = self.d[key]
self.l.remove(key)
self.l.insert(0,key)
else:
value = None

return value

def set(self,key,value):
if self.d.has_key(key):
self.l.remove(key)
elif len(self.d) == self.capacity:
oldest_key = self.l.pop()
self.d.pop(oldest_key)

self.d[key] = value
self.l.insert(0, key)


测试代码如下

代码如下:


c = LRUCache(5)

for i in range(5,10):
c.set(i,10*i)


print c.d,c.l

c.get(5)
c.get(7)

print c.d,c.l

c.set(10,100)
print c.d,c.l

c.set(9,44)
print c.d,c.l

输出为

代码如下:


{8: 80, 9: 90, 5: 50, 6: 60, 7: 70} [9, 8, 7, 6, 5]
{8: 80, 9: 90, 5: 50, 6: 60, 7: 70} [7, 5, 9, 8, 6]
{5: 50, 7: 70, 8: 80, 9: 90, 10: 100} [10, 7, 5, 9, 8]
{5: 50, 7: 70, 8: 80, 9: 44, 10: 100} [9, 10, 7, 5, 8]

推荐阅读
  • 本文介绍了数据库体系的基础知识,涵盖关系型数据库(如MySQL)和非关系型数据库(如MongoDB)的基本操作及高级功能。通过三个阶段的学习路径——基础、优化和部署,帮助读者全面掌握数据库的使用和管理。 ... [详细]
  • 二维几何变换矩阵解析
    本文详细介绍了二维平面上的三种常见几何变换:平移、缩放和旋转。通过引入齐次坐标系,使得这些变换可以通过统一的矩阵乘法实现,从而简化了计算过程。文中不仅提供了理论推导,还附有Python代码示例,帮助读者更好地理解这些概念。 ... [详细]
  • Coursera ML 机器学习
    2019独角兽企业重金招聘Python工程师标准线性回归算法计算过程CostFunction梯度下降算法多变量回归![选择特征](https:static.oschina.n ... [详细]
  • Java 实现二维极点算法
    本文介绍了一种使用 Java 编程语言实现的二维极点算法。该算法用于从一组二维坐标中筛选出极点,适用于需要处理几何图形和空间数据的应用场景。文章不仅详细解释了算法的工作原理,还提供了完整的代码示例。 ... [详细]
  • 随着生活节奏的加快和压力的增加,越来越多的人感到不快乐。本文探讨了现代社会中导致人们幸福感下降的各种因素,并提供了一些改善建议。 ... [详细]
  • Python中HOG图像特征提取与应用
    本文介绍如何在Python中使用HOG(Histogram of Oriented Gradients)算法进行图像特征提取,探讨其在目标检测中的应用,并详细解释实现步骤。 ... [详细]
  • Python 工具推荐 | PyHubWeekly 第二十一期:提升命令行体验的五大工具
    本期 PyHubWeekly 为大家精选了 GitHub 上五个优秀的 Python 工具,涵盖金融数据可视化、终端美化、国际化支持、图像增强和远程 Shell 环境配置。欢迎关注并参与项目。 ... [详细]
  • 在项目中使用 Redis 时,了解其不同架构模式(如单节点、主从复制、哨兵模式和集群)对于确保系统的高可用性和扩展性至关重要。本文将详细探讨这些模式的特点和应用场景。 ... [详细]
  • 深入解析Spring Cloud微服务架构与分布式系统实战
    本文详细介绍了Spring Cloud在微服务架构和分布式系统中的应用,结合实际案例和最新技术,帮助读者全面掌握微服务的实现与优化。 ... [详细]
  • 前言无论是对于刚入行工作还是已经工作几年的java开发者来说,面试求职始终是你需要直面的一件事情。首先梳理自己的知识体系,针对性准备,会有事半功倍的效果。我们往往会把重点放在技术上 ... [详细]
  • 本文探讨了大型服务端开发过程中常见的几个误区,包括异步任务处理不当、日志同步模式使用、网络操作未设置超时、缓存命中率及响应时间未统计、单一缓存模式、分布式缓存加锁不当以及团队管理上的误区,旨在帮助开发者避免这些常见错误。 ... [详细]
  • 字节跳动夏季招聘面试经验分享
    本文详细记录了字节跳动夏季招聘的面试经历,涵盖了一、二、三轮面试的技术问题及项目讨论,旨在为准备类似面试的求职者提供参考。 ... [详细]
  • 本文详细介绍了如何将 Python 3.6.3 程序转换为 Windows 可执行文件(.exe),并解决了使用 py2exe 和 cx_Freeze 时遇到的问题。推荐使用 PyInstaller 进行打包,提供完整的安装和打包步骤。 ... [详细]
  • 你根本不会用百度
    本文转载自第2大脑,详情可以扫描下方二维码关注该公众号摘要:教你正确使用百度。想必你的朋友圈这两天应该被《搜索引擎百度已死》这篇文章刷屏了吧࿰ ... [详细]
  • Python + Pytest 接口自动化测试中 Token 关联登录的实现方法
    本文将深入探讨 Python 和 Pytest 在接口自动化测试中如何实现 Token 关联登录,内容详尽、逻辑清晰,旨在帮助读者掌握这一关键技能。 ... [详细]
author-avatar
玫瑰编辑1轶事
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有