Python实现可自定义更新策略的LRU Cache
来源:互联网 发布:mac版迅雷没速度 编辑:程序博客网 时间:2024/04/30 10:29
LRU Cache
LRU(Least Recently Used),直译为“最近最少使用”,其实称“最久未被使用”更为恰当。这是一个非常重要的算法,在学操作系统的时候第一次遇见,在做leetcode的时候再次遇见,知道是用于做缓存的页面置换。但是LRU不仅仅用于这一个用途,凡是有数据更新策略的应用,LRU都可以是候选算法。比如redis、memcached、oracle等缓存和数据库、或在其它应用场景方面也有类似的需求。总之要达到的目的是:保持新鲜,剔除陈旧,减少交换。
- 算法原理
需求描述:
实现LRU算法,主要工作是实现LRU Cache的数据结构,或者说实现这种类。lru缓存的主要操作有两个,一个是get,获取数据是否在cache中,如果在,则把该数据放到缓存最前面;另一个的主要操作是set,在缓存中存放某个值,并且存放到最前面,如果缓存中有这个值,则更新,如果缓存满了,则删除缓存中最后面的值。总之,缓存中最前面的值是最近被使用过的,缓存有大小限制,超出要删除最久未被使用的值。要求所有操作时间复杂度均为o(1)。
分析:
直觉看上去,数据从近到远以此排列,这是一个线性结构,列表(顺序线性表/数组),链表,队列,栈?
先考虑目的要求,要求最近使用的在最前,最久未使用的在最后,队列是FIFO的结构,栈是FILO的结构,都不符合要求。
再考虑数据更新,要求o(1)复杂度下,把数据更新到最前面。列表被排除,无法满足要求。只有链式结构才可以在o(1)下完成更新。
最后考虑数据查找,链式结构下,数据查找复杂度为o(n),又不能满足o(1)的复杂度。看来必须依赖其它数据结构的辅助。
用列表完成o(1)的更新,不可能啊,想想看,将数组中一个位置的数挪到最前面,那这个位置之前的数据都要后移一位,怎样都不能实现o(1)的开销。那就考虑链式结构下如果实现o(1)的查找吧。通常情况下,查找链表中一个位置上的值,需要从头结点开始,依次后移查找。如果有尾结点也一样依次向前移动,时间复杂度为o(n)。那么我们能不能将每个结点的位置记下来,直接去存放结点的那个位置查找呢?哈希表派上了用场。哈希表存放结点位置的对应关系,能够满足o(1)下的数据查找,同时链表能够实现o(1)的数据更新,符合预想的要求。
总结:在Cache结构中,需要一个hash table,用于存放位置关系,需要一个链表,用于更新数据,链表我们使用双向链表。大体结构为:
class LRU: var table = {} var linklist = TwoWayLinkList() // 双向链表 var function get() var function set()
- 自定义更新策略
有时候,我们可能会有这种场景:
我们需要LRU这种更新策略,同时,我们还想自定义的控制一下这种策略。比如我们的数据中有时间戳的信息,我们想按照时间先后来控制是否更新cache中的值,如果一个新值的时间戳大于cache中该值的时间戳,则更新,否则不更新,怎么办?
我在自己实现的LRU Cache中实现了这种需求,而且把自定义更新的选择权给了客户端自己实现,默认情况下是按照原有方式控制更新,如果客户端想控制更新行为,则可以通过在自己定义的node节点中添加__lt__方法,自定义替换新旧数据的策略,实现自定义控制LRU的更新。
- 代码实现
首先实现Node结点,用于存放数据;然后实现双向链表结构;最后在双向链表基础上,实现LRU Cache。以下是一个简短版本的LRU实现,没有实现自定义更新控制,并且双向链表实现功能较少,仅满足了LRU的使用。
class Node(object): def __init__(self, key, value): self.key = key self.value = value self.prev = None self.next = Noneclass TwoWayLinkedList(object): def __init__(self): self.head = None self.tail = None self._length = 0 def isEmpty(self): return self._length == 0 @property def length(self): return self._length def insert_head(self, node): head = self.head self._length += 1 if head: node.next = head head.prev = node self.head = node node.prev = None else: self.head = self.tail = node node.prev = node.next = None return def pop(self): tail = self.tail if tail: self._length -= 1 prev = tail.prev self.tail = prev tail.prev = None if prev: prev.next = None else: self.head = None return tail else: return None def remove_node(self, node): if not node: return if node == self.head and node == self.tail: self.head = self.tail = None elif node == self.head: next = node.next self.head = next next.prev = None node.next = None return elif node == self.tail: prev = node.prev self.tail = prev prev.next = None node.prev = None else: node.prev.next = node.next node.next.prev = node.prevclass LRU_Cache(object): def __init__(self, capacity): self.capacity = capacity self.size = 0 self.table = {} self.linklist = TwoWayLinkedList() def get(self, node): key = node.key if key in self.table: node = self.table[key] self.linklist.remove_node(node) self.linklist.insert_head(node) return node else: return None def set(self, node): key = node.key if key in self.table: _node = self.table[key] self.table[key] = node self.linklist.remove_node(_node) self.linklist.insert_head(node) else: if self.size == self.capacity: _node = self.linklist.pop() del self.table[_node.key] self.size -= 1 self.table[key] = node self.linklist.insert_head(node) self.size += 1
完整的LRU代码,我放到了Github上了,丰富了双向链表结构及功能,增加了自定义控制,可让用户自定义控制更新策略,增加了使用方法说明。
代码地址:https://github.com/wangyibo360/LRU_Cache
- Python实现可自定义更新策略的LRU Cache
- Python 实现LRU Cache
- 【链表】实现LRU缓存策略LRU Cache
- LRU cache的实现
- LRU Cache的实现
- LRU Cache的实现
- LRU Cache的实现
- LRU的cache的实现
- LRU cache的简单实现
- LRU Cache的一种实现
- LRU cache的另一种实现
- LRU Cache的C++实现
- LRU Cache的简单实现
- LRU cache 算法的实现
- Cache的设计和实现 LRU Cache
- Cache的设计和实现 LRU Cache
- [leetcode]LRU Cache (python)
- 用LinkedHashMap实现的简单LRU Cache
- linux下的几种关机方式
- 国外程序员整理的机器学习领域和资料
- iOS开发之窥探UICollectionViewController(四) --一款功能强大的自定义瀑布流
- Android 5.X新特性
- 数据保存成功后,需要刷新页面,但是刷新后还是老数据
- Python实现可自定义更新策略的LRU Cache
- python代码优化
- $(function(){}) document.ready 区别
- Android中MVC设计模式的构成
- visualSVN配置限制客户端提交时输入message最少字符数
- iOS开发之窥探UICollectionViewController(五) --一款炫酷的图片浏览组件
- Hibernate处理一个实体映射多张相同结构的数据表--动态映射
- Navigator对象详解
- 崩溃日志分析