缓存算法(页面置换算法)-FIFO. LFU. LRU

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

1.FIFO算法

  FIFO(First in First out),先进先出. 其实在操作系统的设计理念中很多地方都利用到了先进先出的思想,比如作业调度(先来先服务),为什么这个原则在很多地方都会用到呢?因为这个原则简单. 且符合人们的惯性思维,具备公平性,并且实现起来简单,直接使用数据结构中的队列即可实现.

  在FIFO Cache设计中,核心原则就是:如果一个数据最先进入缓存中,则应该最早淘汰掉. 也就是说,当缓存满的时候,应当把最先进入缓存的数据给淘汰掉. 在FIFO Cache中应该支持以下操作;

  get(key):如果Cache中存在该key,则返回对应的value值,否则,返回-1;

  set(key,value):如果Cache中存在该key,则重置value值;如果不存在该key,则将该key插入到到Cache中,若Cache已满,则淘汰最早进入Cache的数据.

  举个例子:假如Cache大小为3,访问数据序列为set(1,1),set(2,2),set(3,3),set(4,4),get(2),set(5,5)

  则Cache中的数据变化为:

  (1,1) set(1,1)

  (1,1) (2,2) set(2,2)

  (1,1) (2,2) (3,3) set(3,3)

  (2,2) (3,3) (4,4) set(4,4)

  (2,2) (3,3) (4,4) get(2)

  (3,3) (4,4) (5,5) set(5,5)

  那么利用什么数据结构来实现呢?

  下面提供一种实现思路:

  利用一个双向链表保存数据,当来了新的数据之后便添加到链表末尾,如果Cache存满数据,则把链表头部数据删除,然后把新的数据添加到链表末尾. 在访问数据的时候,如果在Cache中存在该数据的话,则返回对应的value值;否则返回-1. 如果想提高访问效率,可以利用hashmap来保存每个key在链表中对应的位置.

#include <bits/stdc++.h>
using namespace std;

// FIFO 先进先出原则
class Solution
{
public:
   Solution(int si)
   {
       _size=si;
       top_idx=0; // 队列top的下标
       cache.clear();
       exist.clear();
   }
   int check_page(int k)
   {
       if(exist.count(k)>=1) //hit the target
           return k;

// not exist on cache
       if(cache.size()<_size)
       {
           cache.push_back(k);
           exist.insert(k);
       }
       else // replace
       {
           exist.erase(cache[top_idx]);
           exist.insert(k);
           cache[top_idx]=k;
           ++top_idx;
           top_idx%=_size;
       }
       return -1;
   }

private:
   int _size,top_idx;
   vector<int> cache;// 模拟队列
   set<int> exist;
};

/**<
改进:
1.如果页面驻留集(cache)的大小很小的话,没必要使用set来判断是否存在于驻留集中,直接扫一遍来查找,节约了空间
*/

int main()
{
   freopen("H:\\Code_Fantasy\\in.txt","r",stdin);
   int n,page_number;
   while(cin>>n)
   {
       int miss=0;
       Solution solution(3); // set the cache size
       for(int i=0;i<n;++i)
       {
           cin>>page_number;
           if(solution.check_page(page_number)==-1)
               ++miss;
       }
       cout<<"Total missing page: "<<miss<<endl;
       cout<<"The shooting rate is: "<<1.0-(1.*miss/n)<<endl;
       cout<<"=====================================End."<<endl;
   }
   return 0;
}
/*
12
1 2 3 4 1 2 5 1 2 3 4 5

17
7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1
*/

2.LFU算法

  LFU(Least Frequently Used)最近最少使用算法. 它是基于“如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小”的思路.

  注意LFU和LRU算法的不同之处,LRU的淘汰规则是基于访问时间,而LFU是基于访问次数的. 举个简单的例子:

  假设缓存大小为3,数据访问序列为set(2,2),set(1,1),get(2),get(1),get(2),set(3,3),set(4,4),

  则在set(4,4)时对于LFU算法应该淘汰(3,3),而LRU应该淘汰(1,1).

  那么LFU Cache应该支持的操作为:

  get(key):如果Cache中存在该key,则返回对应的value值,否则,返回-1;

  set(key,value):如果Cache中存在该key,则重置value值;如果不存在该key,则将该key插入到到Cache中,若Cache已满,则淘汰最少访问的数据.

  为了能够淘汰最少使用的数据,因此LFU算法最简单的一种设计思路就是:利用一个数组存储数据项,用hashmap存储每个数据项在数组中对应的位置,然后为每个数据项设计一个访问频次,当数据项被命中时,访问频次自增,在淘汰的时候淘汰访问频次最少的数据. 这样一来的话,在插入数据和访问数据的时候都能达到O(1)的时间复杂度,在淘汰数据的时候,通过选择算法得到应该淘汰的数据项在数组中的索引,并将该索引位置的内容替换为新来的数据内容即可,这样的话,淘汰数据的操作时间复杂度为O(n).

  另外还有一种实现思路就是利用小顶堆+hashmap,小顶堆插入. 删除操作都能达到O(logn)时间复杂度,因此效率相比第一种实现方法更加高效.

  如果哪位朋友有更高效的实现方式(比如O(1)时间复杂度),不妨探讨一下,不胜感激.

3.LRU算法

  LRU算法的原理以及实现在前一篇博文中已经谈到,在此不进行赘述:

  http://www.cnblogs.com/dolphin0520/p/3741519.html

  参考链接:http://blog.csdn.net/hexinuaa/article/details/6630384

       http://blog.csdn.net/beiyetengqing/article/details/7855933

       http://blog.csdn.net/alexander_xfl/article/details/12993565

       http://outofmemory.cn/wr/?u=http%3A%2F%2Fblog.csdn.net%2Fyunhua_lee%2Farticle%2Fdetails%2F7648549 

/**
* -----------------------------------------------------------------
* Copyright (c) 2016 crazyacking.All rights reserved.
* -----------------------------------------------------------------
*       Author: crazyacking
*       Date  : 2016-03-15-20.01
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long(LL);
typedef unsigned long long(ULL);
const double eps(1e-8);

struct Node
{
   int key,value;
   Node(int k,int v):key(k),value(v){}
};

class LRUCache
{
private:
   int max_size;
   list<Node> cacheList;
   unordered_map<int,list<Node>::iterator> mp;
public:
   LRUCache(int capacity) {max_size=capacity;}

int get(int key)
   {
       if(mp.find(key)==mp.end()) // 未命中
           return -1;
       else
       {
           auto list_it=mp[key];
           Node node(key,list_it->value);
           cacheList.erase(list_it);
           cacheList.push_front(node);
           mp[key]=cacheList.begin();
           return node.value;
       }
   }

void set(int key, int value)
   {
       auto it=mp.find(key);
       if(it==mp.end()) // 未命中
       {
           if(cacheList.size()>=max_size) // 驻留集已满
           {
               mp.erase(cacheList.back().key);
               cacheList.pop_back();
           }
           Node node(key,value);
           cacheList.push_front(node);
           mp[key]=cacheList.begin();
       }
       else // 命中,将加入的结点置于链表头部,表示最近一次使用
       {
           cacheList.erase(mp[key]);
           Node node(key,value);
           cacheList.push_front(node);
           mp[key]=cacheList.begin();
       }
   }
};

int main()
{
   LRUCache cache(3);
   cache.set(1,1);
   cache.set(2,2);
   cache.set(3,3);
   cache.set(4,4);

cout<<cache.get(4)<<endl;
   cout<<cache.get(3)<<endl;
   cout<<cache.get(2)<<endl;
   cout<<cache.get(1)<<endl;

cache.set(5,5);

cout<<cache.get(1)<<endl;
   cout<<cache.get(2)<<endl;
   cout<<cache.get(3)<<endl;
   cout<<cache.get(4)<<endl;
   cout<<cache.get(5)<<endl;

return 0;
}
/*

*/

--------------------------------------------------------- End.

转载请注明:http://www.cnblogs.com/crazyacking/

页面置换算法 - FIFO、LFU、LRU相关推荐

  1. Cache与页面置换算法FIFO、LRU等

    1 Cache与存储结构 (1) 定义 狭义的Cache指的是位于CPU和主存间的快速RAM, 通常它不像系统主存那样使用动态随机存取存储器(Dynamic Random Access Memory, ...

  2. 操作系统 页面置换算法FIFO与LRU的实现

    FIFO FIFO算法是最早出现的置换算法.该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰. LRU 最近最久未使用(LRU)的页面置换算法是根据页面调入内存后的使用情况做 ...

  3. 页面置换算法 FIFO和LRU 及各自的命中率

    (1) 先进先出算法FIFO:该算法的实质是选择作业中在主存驻留时间最长的一页淘汰,这种算法容易实现,例如分配一个作业的存储块数为m,则只需建立一张m个元素的队列表Q(0).Q(1).-.Q(m-1) ...

  4. 操作系统实验--存储管理--页面置换算法--FIFO and LRU c++实现

    #include<iostream> #include <stdio.h> #include <stdlib.h> #include <time.h> ...

  5. 最近最久未使用页面置换算法C语言,LRU页面置换算法模拟-最近最久未使用置换算法...

    LRU页面置换算法模拟-最近最久未使用置换算法 LRU页面置换算法模拟-最近最久未使用置换算法|课程设计|计算机数据库课程设计 一.设计目的 1.用C语言实现最近最久未使用(LRU)置换算法. 2.了 ...

  6. 请求分页系统中的置换算法(FIFO、LRU、Optimal)

    操作系统实验导航 实验一:银行家算法 https://blog.csdn.net/weixin_46291251/article/details/115384510 实验二:多级队列调度和多级反馈队列 ...

  7. 7-1 页面置换算法--FIFO (50 分)(思路详解)

    一:题目 先初始化页面大小,和物理块数.连续输入页面的逻辑地址,以"-1"作为结束标志,采用FIFO页面置换算法.固定分配局部置换分配策略.输出该页面的页号和页内位移,若该页不在内 ...

  8. OS 页面置换算法(OPT,FIFO,LRU)颠簸/抖动

    介绍 置换算法 置换算法(replacement algorithm)又称为淘汰算法.替换算法,用于确定页面的调出原则. 在地址映射过程中,若在页面中发现所要访问的页面不在内存中,则产生缺页中断.当发 ...

  9. 页面置换算法(FIFO、第二次机会、LRU)

    页面置换算法 文章目录 页面置换算法 前言 一.最近未使用页面置换算法 二.先进先出页面置换算法 三.第二次机会页面置换算法 四.时钟页面置换算法 四.最近最少使用页面置换算法 四.最不常用算法 总结 ...

最新文章

  1. Android博客文章整理
  2. 如何花钱让2000元的月收入工资价值最大化?
  3. 如何求两个向交矩形的交集的面积?
  4. drop table中cascade的含义及用法
  5. Kafka Producer拦截器
  6. mysql update修改数据_MySQL UPDATE:修改数据(更新数据)
  7. 压缩和解压文件:tar gzip bzip2 compress(转)
  8. php ascii art,ASCII art (简体中文)
  9. linux rsync 目录同步,Linux rsync网站目录同步功能的实现
  10. 解决微信小程序Video 某些属性设置不起作用问题
  11. 四张照片合成一张怎么弄_教你5种照片创意手工,简单好看实用
  12. 加盟店 -- 祖坟刨干记
  13. Java常用API——学习笔记(7)
  14. python总结(数据类型、逻辑控制、函数、类与对象、推导式、解包、类型转换、异常、上下文、jsonpath、定时器)
  15. 爬楼梯当中的递归简化计算
  16. python 可执行文件大_python – 如何使用pyinstaller创建最小大小的可执行文件?
  17. Java web:基于jieba分词器(或ansj分词器)的文章关键词字符云(词云图)
  18. 基于keepalived的mysql_【实用】基于keepalived的mysql双主高可用系统
  19. ALNS求MDHVRPTW问题 python实现
  20. CH340有线USB转串与CH9140无线蓝牙转串

热门文章

  1. 重识设计模式-建造者模式(Builder Pattern)
  2. 理解jmeter聚合报告
  3. (二)Thymeleaf标准表达式之——简单表达式
  4. centos6.7x86_64安装nginx (good)
  5. Linux查看程序端口占用情况【转】
  6. 移植uboot第六步:支持NANDFlash
  7. hadoop 依赖式job_Hadoop Job使用第三方依赖jar文件
  8. pte模拟考试_【PTE懒人攻略】如何在7天内通过PTE考试
  9. 二进制地址的伙伴地址
  10. [转]数据库性能优化(老Key)