linux页面置换的存储,操作系统-1-存储管理之LFU页面置换算法(leetcode460)

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 {

public LFUCache(int capacity) {

}

public int get(int key) {

}

public void put(int key, int value) {

}

}

/**

* Your LFUCache object will be instantiated and called as such:

* LFUCache obj = new LFUCache(capacity);

* int param_1 = obj.get(key);

* obj.put(key,value);

*/

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

原理:

选择到当前时间为止被访问次数最少的页面被置换;

每页设置访问计数器,每当页面被访问时,该页面的访问计数器加1;

发生缺页中断时,淘汰计数值最小的页面,并将所有计数清零;

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

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

821079d1d489482e36c71dd5c06e5954.png

解题思路(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{

private int Key;//键

private int Value;//值

private int Times;//访问计数器

private int Id;//自然入队顺序标记,若访问计数器值相同,则先淘汰id小的那个

node() {}

node(int key, int value, int id) {

this.Key = key;

this.Value = value;

this.Id = id;

this.Times = 1;

}

public int getKey() {

return Key;

}

public void setKey(int Key) {

this.Key = Key;

}

public int getValue() {

return Value;

}

public void setValue(int Value) {

this.Value = Value;

}

public int getTimes() {

return Times;

}

public void setTimes(int Times) {

this.Times = Times;

}

public int getId() {

return Id;

}

public void setId(int id) {

this.Id = id;

}

@Override

public int compareTo(node o) {

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

int Timessub = Times - o.Times;

return Timessub == 0 ? this.Id - o.Id: Timessub;

}

}

class LFUCache {

PriorityQueue KeyValueTimes = new PriorityQueue();//用于实现优先级顺序

Map nodeset;//用于O(1)取出某个具体的node

public int Capacity = 0;//我的cache中最大容量

public int nownum = 0;//cache的实时元素个数

public int id = 0;//每个node的入队自然顺序标记

public LFUCache(int capacity) {

this.Capacity = capacity;//设置cache容量

nodeset = new HashMap(capacity);//用于O(1)取出某个具体的node,容量依然设置为capacity

}

public int get(int key) {

if(this.Capacity == 0)//判断容量是否为空,为空则直接返回-1

return -1;

node nownode = nodeset.get(key);//通过HashMap,快速通过key键快速得到node

if (nownode == null) {//如果key这个键没在队列中,则返回-1

return -1;

}else{

KeyValueTimes.remove(nownode);//移除队列中当前的这个node

nownode.setTimes(nownode.getTimes()+1);//更新当前这个node的访问次数

nownode.setId(id++);//更新自然入队顺序

KeyValueTimes.offer(nownode);//再把它放回去

}

return nownode.getValue();

}

public void put(int key, int value) {

if(this.Capacity == 0)//判断容量是否为空,为空则不进行put

return;

node thisnode = new node(key,value,id++);

node oldnode = nodeset.get(key);

if(oldnode == null){//队列里不存在这个key

if(nownum < this.Capacity){//没装满

KeyValueTimes.offer(thisnode);//在队列里添加新node

nodeset.put(key,thisnode);//在HashMap里添加新node

nownum++;//更新当前cache的元素个数

}

else{//装满了,需要LRU,最近最先被移除

nodeset.remove(KeyValueTimes.poll().getKey());//移除队列里的队头,移除HashMap对应的那个node

KeyValueTimes.offer(thisnode);//在队列里添加新node

nodeset.put(key,thisnode);//在HashMap里添加新node

}

}

else{//队列里存在这个key

thisnode.setTimes(oldnode.getTimes()+1);//将原来键为key的访问次数复制给新的node

KeyValueTimes.remove(oldnode);//移除队列里键为key的node,移除HashMap对应的那个node

nodeset.remove(oldnode.getKey());

KeyValueTimes.offer(thisnode);//在队列里添加新node,这里新的node的value值可能会不一样,所以更新了value

nodeset.put(key,thisnode);//在队列里添加新node,这里新的node的value值可能会不一样,所以更新了value

}

}

}

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[操作系统-1-存储管理之LFU页面置换算法(leetcode460)]http://www.zyiz.net/tech/detail-125790.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值