复杂度为O(1)的最不常用[LFU]缓存算法

2024-02-24 06:58

本文主要是介绍复杂度为O(1)的最不常用[LFU]缓存算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考链接:http://python.jobbole.com/82424/

这篇文章描述了怎么用 Python 实现复杂度为 O(1) 的「最不常用」(Least Frequently Used, LFU)缓存回收算法。在 Ketan Shah、Anirban Mitra 和 Dhruv Matani的论文中有算法描述。实现中的命名是按照论文中的命名。

LFU 缓存回收机制对于 HTTP 缓存网络代理是非常有用的,我们可以从缓存中移除那些最不常使用的条目。
本文旨在设计一个其所有操作的时间复杂度都只有 O(1)的 LFU 缓存算法,这些操作包括了插入、访问和删除(回收)。

这个算法中用了双向链表。其一是用于访问频率,链表中的每个结点都包含一个链表,其中的元素有相同的访问频率。假设缓存中有5个元素。有两个元素被访问了一次,三个元素被访问了两次。在这个例子中,访问频率列表有两个结点(频率为1和2)。第一个频率结点的链表中有两个结点,第二个频率结点的链表中有三个结点。


相关的python代码如下:

class Node(object):def __init__(self,data):self.data= dataself.prev = Noneself.next = Noneclass DoublyLinkedList(object):def __init__(self):self.head = Noneself.tail = Noneself.count= 0def add_node(self,cls,data):return self.insert_node(cls,data,self.tail,None)def insert_node(self,cls,data,prev,next):node = cls(data)node.prev = prevnode.next = nextif prev:prev.next = nodeif next:next.prev = nodeif not self.head or next is self.head:self.head = nodeif not self.tail or prev is self.tail:self.tail = nodeself.count +=1return nodedef remove_node(self,node):if node is self.head:self.head = node.nextelse:node.prev.next = node.nextif node is self.tail:self.tail = node.prevelse:node.next.prev = node.prevself.count -=1;def get_nodes_data(self):data=[]node = self.headwhile node:data.append(node.data)
#print "asd"node = node.nextreturn data
class FreqNode(DoublyLinkedList,Node):def __init__(self,data):DoublyLinkedList.__init__(self)Node.__init__(self,data)def add_item_node(self,data):node = self.add_node(ItemNode,data)node.parent= selfreturn nodedef insert_item_node(self,data,prev,next):self.insert_node(ItemNode,data,prev,next)node.parent = selfreturn nodedef remove_item_node(self,node):self.remove_node(node)
class ItemNode(Node):def __init__(self,data):Node.__init__(self,data)self.parent = None
class LfuItem(object):def __init__(self,data,parent,node):self.data = dataself.parent = parentself.node = node
class Cache(DoublyLinkedList):def __init__(self):DoublyLinkedList.__init__(self)self.items = {}def insert_freq_node(self,data,prev,next):return self.insert_node(FreqNode,data,prev,next)def remove_freq_node(self,node):self.remove_node(node)def insert(self,key,value):if key in self.items:raise DuplicateException('key exists')freq_node = self.headif not freq_node or freq_node.data != 1:
#print "adassd"freq_node = self.insert_freq_node(1,None,freq_node)item_node = freq_node.add_item_node(key)self.items[key] = LfuItem(value,freq_node,item_node)def access(self,key):try:tmp_node = self.items[key]except KeyError:raise NotFoundException('key not found')freq_node = tmp_node.parentnext_freq_node = freq_node.nextif not next_freq_node or next_freq_node.data != freq_node.data+1:next_freq_node = self.insert_freq_node(freq_node.data+1,freq_node,next_freq_node)item_node = next_freq_node.add_item_node(key)tmp_node.parent = next_freq_nodefreq_node.remove_item_node(tmp_node.node)if(freq_node.count == 0):self.remove_freq_node(freq_node)tmp_node.node = item_nodereturn tmp_node.datadef delete_lfu(self):if not self.head:raise NotFoundException('No frequency nodes found')freq_node = self.headitem_node = freq_node.headdel self.items[item_node.data]freq_node.remove_item_node(item_node)if freq_node.count == 0:self.remove_freq_node(freq_node)				 def funcs(da):for d in da:print d
if __name__ == '__main__':ca = Cache()ca.insert(1,"123")ca.insert(2,"122")ca.insert(3,"322")da = ca.get_nodes_data()print	ca.access(1)print ca.access(2)print ca.access(3)print ca.access(3)		funcs(ca.get_nodes_data())


这篇关于复杂度为O(1)的最不常用[LFU]缓存算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/741304

相关文章

gitlab安装及邮箱配置和常用使用方式

《gitlab安装及邮箱配置和常用使用方式》:本文主要介绍gitlab安装及邮箱配置和常用使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1.安装GitLab2.配置GitLab邮件服务3.GitLab的账号注册邮箱验证及其分组4.gitlab分支和标签的

Python常用命令提示符使用方法详解

《Python常用命令提示符使用方法详解》在学习python的过程中,我们需要用到命令提示符(CMD)进行环境的配置,:本文主要介绍Python常用命令提示符使用方法的相关资料,文中通过代码介绍的... 目录一、python环境基础命令【Windows】1、检查Python是否安装2、 查看Python的安

python判断文件是否存在常用的几种方式

《python判断文件是否存在常用的几种方式》在Python中我们在读写文件之前,首先要做的事情就是判断文件是否存在,否则很容易发生错误的情况,:本文主要介绍python判断文件是否存在常用的几种... 目录1. 使用 os.path.exists()2. 使用 os.path.isfile()3. 使用

Java实现本地缓存的常用方案介绍

《Java实现本地缓存的常用方案介绍》本地缓存的代表技术主要有HashMap,GuavaCache,Caffeine和Encahche,这篇文章主要来和大家聊聊java利用这些技术分别实现本地缓存的方... 目录本地缓存实现方式HashMapConcurrentHashMapGuava CacheCaffe

如何更改pycharm缓存路径和虚拟内存分页文件位置(c盘爆红)

《如何更改pycharm缓存路径和虚拟内存分页文件位置(c盘爆红)》:本文主要介绍如何更改pycharm缓存路径和虚拟内存分页文件位置(c盘爆红)问题,具有很好的参考价值,希望对大家有所帮助,如有... 目录先在你打算存放的地方建四个文件夹更改这四个路径就可以修改默认虚拟内存分页js文件的位置接下来从高级-

PyCharm如何更改缓存位置

《PyCharm如何更改缓存位置》:本文主要介绍PyCharm如何更改缓存位置的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录PyCharm更改缓存位置1.打开PyCharm的安装编程目录2.将config、sjsystem、plugins和log的路径

JSR-107缓存规范介绍

《JSR-107缓存规范介绍》JSR是JavaSpecificationRequests的缩写,意思是Java规范提案,下面给大家介绍JSR-107缓存规范的相关知识,感兴趣的朋友一起看看吧... 目录1.什么是jsR-1072.应用调用缓存图示3.JSR-107规范使用4.Spring 缓存机制缓存是每一

Spring 缓存在项目中的使用详解

《Spring缓存在项目中的使用详解》Spring缓存机制,Cache接口为缓存的组件规范定义,包扩缓存的各种操作(添加缓存、删除缓存、修改缓存等),本文给大家介绍Spring缓存在项目中的使用... 目录1.Spring 缓存机制介绍2.Spring 缓存用到的概念Ⅰ.两个接口Ⅱ.三个注解(方法层次)Ⅲ.

Spring Boot 整合 Redis 实现数据缓存案例详解

《SpringBoot整合Redis实现数据缓存案例详解》Springboot缓存,默认使用的是ConcurrentMap的方式来实现的,然而我们在项目中并不会这么使用,本文介绍SpringB... 目录1.添加 Maven 依赖2.配置Redis属性3.创建 redisCacheManager4.使用Sp

springboot项目redis缓存异常实战案例详解(提供解决方案)

《springboot项目redis缓存异常实战案例详解(提供解决方案)》redis基本上是高并发场景上会用到的一个高性能的key-value数据库,属于nosql类型,一般用作于缓存,一般是结合数据... 目录缓存异常实践案例缓存穿透问题缓存击穿问题(其中也解决了穿透问题)完整代码缓存异常实践案例Red