复杂度为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

相关文章

MySQL常用字符串函数示例和场景介绍

《MySQL常用字符串函数示例和场景介绍》MySQL提供了丰富的字符串函数帮助我们高效地对字符串进行处理、转换和分析,本文我将全面且深入地介绍MySQL常用的字符串函数,并结合具体示例和场景,帮你熟练... 目录一、字符串函数概述1.1 字符串函数的作用1.2 字符串函数分类二、字符串长度与统计函数2.1

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

Linux系统中查询JDK安装目录的几种常用方法

《Linux系统中查询JDK安装目录的几种常用方法》:本文主要介绍Linux系统中查询JDK安装目录的几种常用方法,方法分别是通过update-alternatives、Java命令、环境变量及目... 目录方法 1:通过update-alternatives查询(推荐)方法 2:检查所有已安装的 JDK方

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使

Apache Ignite缓存基本操作实例详解

《ApacheIgnite缓存基本操作实例详解》文章介绍了ApacheIgnite中IgniteCache的基本操作,涵盖缓存获取、动态创建、销毁、原子及条件更新、异步执行,强调线程池注意事项,避免... 目录一、获取缓存实例(Getting an Instance of a Cache)示例代码:二、动态

MySQL字符串常用函数详解

《MySQL字符串常用函数详解》本文给大家介绍MySQL字符串常用函数,本文结合实例代码给大家介绍的非常详细,对大家学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录mysql字符串常用函数一、获取二、大小写转换三、拼接四、截取五、比较、反转、替换六、去空白、填充MySQL字符串常用函数一、

Java中Arrays类和Collections类常用方法示例详解

《Java中Arrays类和Collections类常用方法示例详解》本文总结了Java中Arrays和Collections类的常用方法,涵盖数组填充、排序、搜索、复制、列表转换等操作,帮助开发者高... 目录Arrays.fill()相关用法Arrays.toString()Arrays.sort()A

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

golang中reflect包的常用方法

《golang中reflect包的常用方法》Go反射reflect包提供类型和值方法,用于获取类型信息、访问字段、调用方法等,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值... 目录reflect包方法总结类型 (Type) 方法值 (Value) 方法reflect包方法总结

C# 比较两个list 之间元素差异的常用方法

《C#比较两个list之间元素差异的常用方法》:本文主要介绍C#比较两个list之间元素差异,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 使用Except方法2. 使用Except的逆操作3. 使用LINQ的Join,GroupJoin