一,LRU算法介绍

LRU是内存分配中“离散分配方式”之分页存储管理方式中用到的一个算法。每个进程都有自己的页表,进程只将自己的一部分页面加载到内存的物理块中,当进程在运行过程中,发现某页面不在物理内存块中(发生缺页异常)就需要从磁盘把相应的页面调入内存。而若内存已经满了的情况下,需要将内存中暂时不用的物理块页面 换出到磁盘(交换空间)中,那到底换出哪一页呢?LRU算法就是用来解决到底换出哪一页 的这个问题。

LRU算法是最近最少未使用算法。当内存缺页时,总是优先选出距离当前最久未使用的页面换出,并把当前的缺页换入。该算法可用栈模拟实现。

栈顶总是保存当前最近访问的页面号,栈底则总是保存最久未访问的页面号。对于下一个页面,有两种情况:

①命中,则需要:更新栈顶元素。即将当前命中的页面号放到栈顶。

②未命中,这里还需要考虑栈是否满了。1)若栈未满,直接将未命中的页面号放到栈顶即可。为什么要放到栈顶(LinkedList表头)呢?

因为,LRU每次总是选取最近最久未被访问的页面淘汰。某页面刚刚被访问,需要放到栈顶,以表示它不是“最近最久 未访问的页面”

2)栈已经满了,则需要选中一页换出(栈底元素是最久未访问的页面),然后再将新页面放入栈顶

二,代码实现

import java.util.LinkedList;

public class LRU {

    private LinkedList<Integer> stack;//模拟页面'寄存器'
private int size;//寄存器大小,表示一共可装入多少页面 public LRU(int size) {
stack = new LinkedList<>();
this.size = size;
} //LRU算法简单实现,返回一共未命中的次数
public int lru(int[] pageNumbers)
{
if(size <= 0 || pageNumbers == null)
throw new IllegalArgumentException("illegal arugments"); if(pageNumbers.length <= size)
return pageNumbers.length; int unhit = 0; for(int i = 0; i < pageNumbers.length; i++)
{
int index = isHit(pageNumbers[i]);
if(index == -1)
unhit = processUnHit(pageNumbers[i], unhit);
else
{
processHit(pageNumbers[i], index);
}
}
return unhit;
} /**
*
* @param pageNumber 判断 pageNumber是否hit
* @return -1 表示 unhit, 其他表示hit
*/
private int isHit(int pageNumber){
return stack.indexOf(pageNumber);
} /**
* 当栈未满时,未命中的页面号直接入栈;栈满时,需要替换页面,先选中一个页面(栈底)删除,然后Push新页面
* @param pageNumber 未命中的页面号
* @param count 当前未命中次数
* @return 更新后的未命中的次数
*/
private int processUnHit(int pageNumber, int count){
if(isFull())
stack.removeLast();//删除最久未访问的页面
stack.push(pageNumber);//放入最近访问的页面
count++;//未命中的次数加1
return count;
} //处理命中的情况
private void processHit(int pageNumber, int index){
stack.push(stack.remove(index));
} //判断'寄存器'栈是否已经满了
private boolean isFull()
{
if(stack.size() < size)
return false;
else
return true;
} //test
public static void main(String[] args) {
int[] pageNumbers = {4,7,1,1,7,2,1};
int size = 2;
LRU lru = new LRU(size);
System.out.println(lru.lru(pageNumbers));
}
}

三,复杂度分析

由于java.util.LinkedList 实现了栈的功能。push()方法总是将元素放到表头,pop()方法总是从链表的表头删除元素。在这里,链表的表头代表栈顶。

因此,当某页面号命中时,需要从链表中找到该页面的位置(index),然后删除该页面,并将它push到链表的表头。---processHit()方法

由于是链表,故寻找某页面的时间复杂度为O(N),最坏情况下扫描整个链表。

当页面未命中的,需要将页面号push到链表表头。push之前,先检查栈是否已经满了。若未满,直接push入栈,时间复杂度为O(1);如果栈已经满了,需要删除链表的表尾元素(相当于栈底元素--removeLast()时间复杂度也为O(1),因为LinkedList本质上是一个双向链表。)然后,再将该删除的元素push到栈顶--时间复杂度为O(1)

故未命中时,处理的总的时间复杂度还是O(1)

使用java.util.LinkedList模拟实现内存页面置换算法--LRU算法的更多相关文章

  1. JDK1.8源码(六)——java.util.LinkedList 类

    上一篇博客我们介绍了List集合的一种典型实现 ArrayList,我们知道 ArrayList 是由数组构成的,本篇博客我们介绍 List 集合的另一种典型实现 LinkedList,这是一个有链表 ...

  2. java.util.ArrayList、java.util.vector和java.util.LinkedList (JDK 1.8.0_111)

    一.java.util.ArrayList 1.1 ArrayList 继承结构 ArrayList实现了RandomAccess,可以随机访问(其实就是通过数组下标访问):实现了Cloneable, ...

  3. 内功心法 -- java.util.LinkedList<E> (3)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------下文主要对java.util ...

  4. 内功心法 -- java.util.LinkedList<E> (4)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------下文主要对java.util ...

  5. 内功心法 -- java.util.LinkedList<E> (5)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------下文主要对java.util ...

  6. 内功心法 -- java.util.LinkedList<E> (6)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------下文主要对java.util ...

  7. 内功心法 -- java.util.LinkedList<E> (7)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------下文主要对java.util ...

  8. 内功心法 -- java.util.LinkedList<E> (8)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------下文主要对java.util ...

  9. 内功心法 -- java.util.LinkedList<E> (1)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------下文主要对java.util ...

随机推荐

  1. Linux下安装oracle的过程

    1. Linux 安装 主要不要将home分区设置的特别大 2. 安装必须的一些包. yum install -y \ binutils.x86_64 \ elfutils-libelf-devel. ...

  2. 周刷题第二期总结(Longest Substring Without Repeating Characters and Median of Two Sorted Arrays)

    这周前面刷题倒是蛮开心,后面出了很多别的事情和问题就去忙其他的,结果又只完成了最低目标. Lonest Substring Without Repeating Characters: Given a ...

  3. maven 聚合的含义是父类打包 ,清理等 则子类自动打包;也就是一键打包 方便服务

    maven 聚合的含义是父类打包 ,清理等 则子类自动打包:也就是一键打包 方便服务

  4. HDU-3746-KMP理解失配

    这个有点意思,要理解失配数组 题意是要计算出需要构造成循环节相连的最小个数 利用失配构造函数求出单个循环节,然后计算出需要的加上的珠子个数 #include <cstdio> #inclu ...

  5. Django实现websocket完成实时通讯,聊天室,在线客服等

    一 什么是Websocket WebSocket是一种在单个TCP连接上进行全双工通信的协议 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据.在WebS ...

  6. Dominator Tree & Lengauer-Tarjan Algorithm

    问题描述 给出一张有向图,可能存在环,对于所有的i,求出从1号点到i点的所有路径上的必经点集合. 什么是支配树 两个简单的小性质—— 1.如果i是j的必经点,而j又是k的必经点,则i也是k的必经点. ...

  7. 【BZOJ2424】[HAOI2010]订货(费用流)

    [BZOJ2424][HAOI2010]订货(费用流) 题面 BZOJ 洛谷 题解 傻逼费用流吧... 一开始理解错意思了,仓库大小为\(m\)的含义是留到下个月最多为\(m\),而不是任意时刻的容量 ...

  8. CRM 2013 批量更新two options的缺省值

    1: string entNames = "new_print_plan,new_radio_plan,new_bill_board,new_tv_plan,new_btl_posm,new ...

  9. 小trick总结

    一个圆上的整点数量不会很多.(Cf AIM TR 5 F) 二分图完美匹配求字典序最小的方案:先一遍匈牙利求出任意一组完美匹配.再跑一遍逐位确定,要求不能修改编号比它小的匹配.(LG 4100) 如果 ...

  10. 树莓派上使用Pi-FM-RDS工具打造FM调频电台

    安装Pi-FM-RDS 安装依赖.sudo apt-get install libsndfile1-dev 克隆Pi-FM-RDS到本地.git clone https://github.com/Ch ...