在Leetcode上遇到了两个有趣的题目,分别是利用LRU和LFU算法实现两个缓存。缓存支持和字典一样的get和put操作,且要求两个操作的时间复杂度均为O(1)。

  首先说一下如何在O(1)时间复杂度内实现get方法。据鄙人所知,对于没有限定数据范围的数据,唯一拥有O(1)时间复杂度的get的数据结构就是哈希表,尽管其时间复杂度是通过概率来推算出来的。因此毋庸质疑,LRU和LFU的get方法中必定使用了哈希表的取值,相应的put方法中也必定调用了哈希表的赋值操作。

  由于LRU和LFU都涉及到了选择被淘汰记录和淘汰操作。能在O(1)时间内选择被淘汰记录的数据结构非常类似于队列,队列中的元素按插入时间的先后顺序进行排序,这样在插入最新记录和删除最老记录上都能获得O(1)的时间复杂度。但是这还远远不够,因为存在更新操作,即当使用get方法访问一条记录,其最后访问时间将被更新到现在。这也意味着必须从队列中删除某个元素并将其加入到队列尾部这种操作的存在,使用一般的数组队列是无法在O(1)时间复杂度内完成这个操作的。这样显然必须考虑另外一个数据结构,链表,链表能在O(1)时间复杂度内删除和加入任意记录。

   LRU是least recently used的缩写,即最近最久未使用。在缓存数据量溢出时,必须淘汰某一项记录才能插入新的记录,而LRU算法则选择淘汰上一次使用时间距离现在最久的那条记录。只需要同时维护一个链表和一个哈希表,下面说明各个操作的具体流程:

  get:

    如果哈希表中存在对应记录,则将其从链表中移除并加入到链表尾部。

  put:

    调用get方法获取对应的记录,如果记录非空,则直接修改值。否则执行下一步。

    同时从链表和哈希表中移除链表头部记录(淘汰操作),并向链表尾部和哈希表中加入新的记录。

  LFU是least frequently used的缩写,即最少被使用。在缓存已满且需要加入新的记录时,选择缓存中被使用次数最少的记录(如果有多条,则选择其中使用时间距离现在最久的记录)。

  如果LRU是简洁美好的,那么LFU就要费力的多了。LFU的实现的难点在于,要保证记录按照使用次数,和最后访问时间双项指标进行排序。由于记录被访问而修正记录的使用次数和最后访问时间,需要找到合适的插入位置,这无法通过一个链表实现。我的做法是使用一个保存链表的链表(二维链表)以及一个哈希表,二维链表中每一个保存的链表中所有记录都有相同的访问次数,且按照最后访问时间先后排序。下面说明各个操作的具体流程:

  move(N, L):

    如果链表L为null,则新建一个链表加入到二维链表尾部。之后进行下一步。

    如果L为空或者L所有元素的访问次数与N的访问次数一致,则将N加入到L的尾部并结束流程。

    否则创建一个新的链表newL,并将newL插入到二维链表中,插入位置是L的前面。将N加入到newL中并结束流程。

  get:

    如果哈希表中有对应记录R,则将R先从自己所在的链表L中移除。并调用move方法移动R到L在二维链表中的后面一个兄弟中。

  put:

    调用get方法取关键字对应的记录,如果存在则更新值并返回。否则进行下一步。

    先选择二维链表中为首的链表中的第一条记录,进行淘汰(分别从链表和哈希表中移除)。

    之后调用move方法将新的记录R移动到二维链表为首的链表中。并将R加入到哈希表中。

  注意从一个链表中移除一条记录可能会导致链表为空(即链表原先只有一个记录),则链表本身的存在就失去了意义(链表存在的意义是组织拥有相同访问次数的记录),因此这时候可以回收空链表,这样同时可以将LFU的空间复杂度限制到O(capacity)内,capacity是缓存的容量。

  下面说明LRU和LFU的时空复杂度。LRU和LFU的所有操作均只涉及常数次链表操作和常数次哈希表操作,因此时间复杂度均为O(1)。而空间复杂度,LRU使用了链表和哈希表,二者的空间复杂度均为O(capacity),因此总的空间复杂度为O(capacity)。而LFU算法的空间复杂度则取决于二维链表的长度,由于前面保证了每个二维链表中的链表都非空,也就是说每个链表都至少对应一条记录,而总记录数不超过capacity,故链表数也被限制到了O(capacity)内,因此LFU算法的空间复杂度为O(capacity)。

Leetcode:LRU Cache,LFU Cache的更多相关文章

  1. leetcode 146. LRU Cache 、460. LFU Cache

    LRU算法是首先淘汰最长时间未被使用的页面,而LFU是先淘汰一定时间内被访问次数最少的页面,如果存在使用频度相同的多个项目,则移除最近最少使用(Least Recently Used)的项目. LFU ...

  2. [LeetCode] LFU Cache 最近最不常用页面置换缓存器

    Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...

  3. [LeetCode] LRU Cache 最近最少使用页面置换缓存器

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...

  4. LeetCode LFU Cache

    原题链接在这里:https://leetcode.com/problems/lfu-cache/?tab=Description 题目: Design and implement a data str ...

  5. [LeetCode] 460. LFU Cache 最近最不常用页面置换缓存器

    Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...

  6. Leetcode: LFU Cache && Summary of various Sets: HashSet, TreeSet, LinkedHashSet

    Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...

  7. LFU Cache

    2018-11-06 20:06:04 LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”. ...

  8. 内存淘汰机制——LRU与LFU

    内存淘汰机制之LRU与LFU LRU(Least Recently Used):淘汰 近期最不会访问的数据 LFU(Least Frequently Used):淘汰 最不经常使用(访问次数少) 所谓 ...

  9. 缓存算法(FIFO 、LRU、LFU三种算法的区别)

    FIFO算法 FIFO 算法是一种比较容易实现的算法.它的思想是先进先出(FIFO,队列),这是最简单.最公平的一种思想,即如果一个数据是最先进入的,那么可以认为在将来它被访问的可能性很小.空间满的时 ...

随机推荐

  1. PHPutf-8转码。

    $str = 'jiaoqing.': echo mb_convert_encoding($str,"gbk","utf-8");

  2. python大法好——字典、集合

    字典 前面我们说过列表,它适合于将值组织到一个结构中并且通过编号对其进行引用.字典则是通过名字来引用值的数据结构,并且把这种数据结构称为映射,字典中的值没有特殊的顺序,都存储在一个特定的键(key)下 ...

  3. 20165304 实验二 Java面向对象程序设计

    一.面向对象程序设计1--单元测试和TDD 实验要求 1.参考 http://www.cnblogs.com/rocedu/p/6371315.html#SECUNITTEST 完成单元测试的学习 2 ...

  4. scala 爬虫 去除不能存储的特殊字符

    scala 爬虫 去除不能存储的特殊字符 /** * 去除不能存储的特殊字符 */ def zifuChange(str: String): String = { var bo = true var ...

  5. ABAP-定时-异步

    *&---------------------------------------------------------------------* *& Report ZRICO_TES ...

  6. 如何让cxgrid自动调整列宽

    1.选中cxgridview,在属性中找OptionsView--->ColumAutoWidth,把这个属性设为True; 2.在FDMemtable的open之后加上如下代码即可 [delp ...

  7. App.js实现使用js开发app的应用,此文是中文文档

    在阅读前,在此说明下,本人英文一直不好,所以该文档是借助翻译工具翻译的,阅读起来可能有点不好,请各位谅解,哪位大神有标准的中文文档请分享下 Github下载地址:https://github.com/ ...

  8. 两台openwrt 间的免登陆ssh

    参考文档: http://www.360doc.com/content/13/1013/21/3884271_321222563.shtml http://blog.csdn.net/u0110079 ...

  9. Idea使用Maven异常 --- Maven网络代理设置

    在conf/setting.xml和m2/repository/setting.xml中加入: <proxies> <!-- proxy | Specification for on ...

  10. delphi控制本计算机和远程计算机关机等

    unit mainunit; {远程关机源码} interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Con ...