LFU缓存

题目:请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。它应该支持以下操作:get 和 put。
    get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1。
    put(key, value) - 如果键不存在,请设置或插入值。当缓存达到其容量时,则应该在插入新项之前,使最不经常使用的项无效。

            在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近 最少使用的键。
    「项的使用次数」就是自插入该项以来对其调用 get 和 put 函数的次数之和。使用次数会在对应项被移除后置为 0 。

示例:  
   LFUCache cache = new LFUCache( 2 /* capacity (缓存容量) */ );

     cache.put(1, 1);
     cache.put(2, 2);
     cache.get(1);       // 返回 1
     cache.put(3, 3);    // 去除 key 2
     cache.get(2);       // 返回 -1 (未找到key 2)  
     cache.get(3);       // 返回 3
     cache.put(4, 4);    // 去除 key 1
     cache.get(1);       // 返回 -1 (未找到 key 1)
     cache.get(3);       // 返回 3
     cache.get(4);       // 返回 4

代码:

  1. class LFUCache {
  2.  
  3. public LFUCache(int capacity) {
  4.  
  5. }
  6.  
  7. public int get(int key) {
  8.  
  9. }
  10.  
  11. public void put(int key, int value) {
  12.  
  13. }
  14. }
  15.  
  16. /**
  17. * Your LFUCache object will be instantiated and called as such:
  18. * LFUCache obj = new LFUCache(capacity);
  19. * int param_1 = obj.get(key);
  20. * obj.put(key,value);
  21. */

LFU页面置换算法(最不经常使用算法)

  原理:

    选择到当前时间为止被访问次数最少的页面被置换;
    每页设置访问计数器,每当页面被访问时,该页面的访问计数器加1;
    发生缺页中断时,淘汰计数值最小的页面,并将所有计数清零;

    如图:图中的页面为三页,依次向存储中加入432143543215这些数字。

       而存储空间只能存储三个页面,所以会按照上述规则不断淘汰已经存储在页面中的数字。

    

解题思路(logN的思路):

    知道了LFU的置换规则后,由于此题需要存储的是key和value,所以

      首先,需要建一个类node,存放四样东西,key,value,times(访问计数器),id(进入存储空间的自然顺序)

      其次,选择一种合适的数据结构来解决存储优先级问题,此处我们采用内部是小顶堆的PriorityQueue优先级队列用来

         实现times最小的元素在队头,如果times相等,则比较先后入队的自然顺序id

         但是我们会在让新元素入队之前可能会删除队列中指定元素,当然可以去遍历队列,但是这样太慢了

         我们可以再用一种HashMap的数据集合用来存储节点,以便快速通过node的key来得到整个node。

      最后,便是处理逻辑关系,写题目要求的get,put方法了

解题代码详解(logN):

  1. public class node implements Comparable<node>{
  2. private int Key;//键
  3. private int Value;//值
  4. private int Times;//访问计数器
  5. private int Id;//自然入队顺序标记,若访问计数器值相同,则先淘汰id小的那个
  6. node() {}
  7. node(int key, int value, int id) {
  8. this.Key = key;
  9. this.Value = value;
  10. this.Id = id;
  11. this.Times = 1;
  12. }
  13. public int getKey() {
  14. return Key;
  15. }
  16.  
  17. public void setKey(int Key) {
  18. this.Key = Key;
  19. }
  20.  
  21. public int getValue() {
  22. return Value;
  23. }
  24.  
  25. public void setValue(int Value) {
  26. this.Value = Value;
  27. }
  28.  
  29. public int getTimes() {
  30. return Times;
  31. }
  32.  
  33. public void setTimes(int Times) {
  34. this.Times = Times;
  35. }
  36. public int getId() {
  37. return Id;
  38. }
  39.  
  40. public void setId(int id) {
  41. this.Id = id;
  42. }
  43.  
  44. @Override
  45. public int compareTo(node o) {
  46. //实现times最小的元素在队头,如果times相等,则比较先后入队顺序
  47. int Timessub = Times - o.Times;
  48. return Timessub == 0 ? this.Id - o.Id: Timessub;
  49. }
  50. }
  51.  
  52. class LFUCache {
  53. PriorityQueue<node> KeyValueTimes = new PriorityQueue();//用于实现优先级顺序
  54. Map<Integer, node> nodeset;//用于O(1)取出某个具体的node
  55. public int Capacity = 0;//我的cache中最大容量
  56. public int nownum = 0;//cache的实时元素个数
  57. public int id = 0;//每个node的入队自然顺序标记
  58.  
  59. public LFUCache(int capacity) {
  60. this.Capacity = capacity;//设置cache容量
  61. nodeset = new HashMap<Integer, node>(capacity);//用于O(1)取出某个具体的node,容量依然设置为capacity
  62. }
  63.  
  64. public int get(int key) {
  65. if(this.Capacity == 0)//判断容量是否为空,为空则直接返回-1
  66. return -1;
  67. node nownode = nodeset.get(key);//通过HashMap,快速通过key键快速得到node
  68. if (nownode == null) {//如果key这个键没在队列中,则返回-1
  69. return -1;
  70. }else{
  71. KeyValueTimes.remove(nownode);//移除队列中当前的这个node
  72. nownode.setTimes(nownode.getTimes()+1);//更新当前这个node的访问次数
  73. nownode.setId(id++);//更新自然入队顺序
  74. KeyValueTimes.offer(nownode);//再把它放回去
  75. }
  76. return nownode.getValue();
  77. }
  78.  
  79. public void put(int key, int value) {
  80. if(this.Capacity == 0)//判断容量是否为空,为空则不进行put
  81. return;
  82. node thisnode = new node(key,value,id++);
  83. node oldnode = nodeset.get(key);
  84. if(oldnode == null){//队列里不存在这个key
  85. if(nownum < this.Capacity){//没装满
  86. KeyValueTimes.offer(thisnode);//在队列里添加新node
  87. nodeset.put(key,thisnode);//在HashMap里添加新node
  88. nownum++;//更新当前cache的元素个数
  89. }
  90. else{//装满了,需要LFU,最不经常使用被移除
  91. nodeset.remove(KeyValueTimes.poll().getKey());//移除队列里的队头,移除HashMap对应的那个node
  92. KeyValueTimes.offer(thisnode);//在队列里添加新node
  93. nodeset.put(key,thisnode);//在HashMap里添加新node
  94. }
  95. }
  96. else{//队列里存在这个key
  97. thisnode.setTimes(oldnode.getTimes()+1);//将原来键为key的访问次数复制给新的node
  98. KeyValueTimes.remove(oldnode);//移除队列里键为key的node,移除HashMap对应的那个node
  99. nodeset.remove(oldnode.getKey());
  100. KeyValueTimes.offer(thisnode);//在队列里添加新node,这里新的node的value值可能会不一样,所以更新了value
  101. nodeset.put(key,thisnode);//在队列里添加新node,这里新的node的value值可能会不一样,所以更新了value
  102. }
  103. }
  104. }

操作系统-1-存储管理之LFU页面置换算法(leetcode460)的更多相关文章

  1. 操作系统笔记(六)页面置换算法 FIFO法 LRU最近最久未使用法 CLOCK法 二次机会法

    前篇在此: 操作系统笔记(五) 虚拟内存,覆盖和交换技术 操作系统 笔记(三)计算机体系结构,地址空间.连续内存分配(四)非连续内存分配:分段,分页 内容不多,就不做index了. 功能:当缺页中断发 ...

  2. [Operate System & Algorithm] 页面置换算法

    页面置换算法是什么?我们看一下百度百科对页面置换算法给出的定义:在地址映射过程中,若在页面中发现所要访问的页面不在内存中,则产生缺页中断.当发生缺页中断时,如果操作系统内存中没有空闲页面,则操作系统必 ...

  3. 页面置换算法(最佳置换算法、FIFO置换算法、LRU置换算法、LFU置换算法)

    页面置换产生的原因是:分页请求式存储管理(它是实现虚拟存储管理的方法之一,其中一个特性是多次性-->多次将页面换入或换出内存) 效果最好的页面置换算法:最佳置换算法 比较常用的页面置换算法有:F ...

  4. 操作系统页面置换算法(opt,lru,fifo,clock)实现

    选择调出页面的算法就称为页面置换算法.好的页面置换算法应有较低的页面更换频率,也就是说,应将以后不会再访问或者以后较长时间内不会再访问的页面先调出. 常见的置换算法有以下四种(以下来自操作系统课本). ...

  5. 操作系统 页面置换算法LRU和FIFO

    LRU(Least Recently Used)最少使用页面置换算法,顾名思义,就是替换掉最少使用的页面. FIFO(first in first out,先进先出)页面置换算法,这是的最早出现的置换 ...

  6. 页面置换算法 - FIFO、LFU、LRU

    缓存算法(页面置换算法)-FIFO. LFU. LRU 在前一篇文章中通过leetcode的一道题目了解了LRU算法的具体设计思路,下面继续来探讨一下另外两种常见的Cache算法:FIFO. LFU ...

  7. 操作系统-2-存储管理之LRU页面置换算法(LeetCode146)

    LRU缓存机制 题目:运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制. 它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...

  8. 【操作系统】页面置换算法(最佳置换算法)(C语言实现)

    [操作系统]页面置换算法(最佳置换算法)(C语言实现) (编码水平较菜,写博客也只是为了个人知识的总结和督促自己学习,如果有错误,希望可以指出) 1.页面置换算法: 在地址映射过程中,若在页面中发现所 ...

  9. (待续)C#语言中的动态数组(ArrayList)模拟常用页面置换算法(FIFO、LRU、Optimal)

    目录 00 简介 01 算法概述 02 公用方法与变量解释 03 先进先出置换算法(FIFO) 04 最近最久未使用(LRU)算法 05 最佳置换算法(OPT) 00 简介 页面置换算法主要是记录内存 ...

随机推荐

  1. 新建eclipse工作空间的常用设置

    1.设置字体: Window->Preferences->(可以直接搜索font)General -> Appearance ->Colors and Fonts --> ...

  2. 实验二——Linux系统简单文件操作命令

    项目 内容 这个作业属于那个课程 这里是链接 作业要求在哪里 这里是链接 学号-姓名 17041506-张政 作业学习目标 学习在Linux系统终端下进行命令行操作,掌握常用命令行操作并能通过命令行操 ...

  3. requests.exceptions.SSLError报错

    requests.exceptions.SSLError: HTTPSConnectionPool(host='www.baidu.com', port=443): Max retries excee ...

  4. 【翻译】.NET 5 Preview 1 发布

    .NET 5 Preview 1 发布 去年年底,我们发布了.NET Core 3.0和3.1.这些版本添加了桌面应用程序模型Windows Forms(WinForms)和WPF,ASP.NET B ...

  5. throttle工具函数

    // fn是我们需要包装的事件回调, delay是时间间隔的阈值 export function throttle(fn, delay) { // last为上一次触发回调的时间, timer是定时器 ...

  6. async,await怎么用

    async声明一个函数是异步的,await用于等待异步完成,并且await只能在async中使用. 使用async,await并行处理请求,速度减半: 将多个promise直接发起请求,先执行asyn ...

  7. 用原生JS实现爱奇艺首页导航栏

    以下是爱奇艺首页的一个导航栏,用原生js写的,静态页面效果如下: 代码如下: <html> <head> <title>爱奇艺</title> < ...

  8. ASP.net 简单ajax实现

    <script type="text/javascript"> $(function () { var t=$("txt1").val(); $.a ...

  9. Nginx配置Web项目(多页面应用,单页面应用)

    目前前端项目 可分两种: 多页面应用,单页面应用. 单页面应用 入口是一个html文件,页面路由由js控制,动态往html页面插入DOM. 多页面应用 是由多个html文件组成,浏览器访问的是对应服务 ...

  10. PyQt5UI文件转换为对应版本的py文件

    PyQt5 UI文件转换为对应版本的py文件 #coding=utf-8 ''' PyQt5 UI文件转换为对应版本的py文件 python -m PyQt5.uic.pyuic untitled.u ...