手写 LRU (Least Recently Used)

栏目: IT技术 · 发布时间: 4年前

内容简介:我有一个朋友面试的时候被问到过,要手撸一个LRU算法,所以我也准备一下好了。在进程运行过程中,若其所要访问的页面不在内存而需把它们调入内存,但内存这里通常把选择换出页面的算法称为

前言

我有一个朋友面试的时候被问到过,要手撸一个LRU算法,所以我也准备一下好了。

页面置换算法

在进程运行过程中,若其所要访问的页面不在内存而需把它们调入内存,但内存 「 已无空闲空间 」 时,为了保证该进程能正常运行,系统必须从内存中调出一页程序或数据送磁盘的对换区中。但应将哪个页面调出,须根据一定的算法来确定。

这里通常把选择换出页面的算法称为 「 页面置换算法 」 (Page-Replacement Algorithms)。置换算法的好坏, 将直接影响到系统的性能。

一个好的页面置换算法,应具有 「 较低的页面更换频率 」 。从理论上讲,应将那些以后不再会访问的页面换出,或把那些在较长时间内不会再访问的页面调出。存在着许多种置换算法,它们都试图更接近于理论上的目标。

LRU

LRU是Least Recently Used的缩写,即 「 最近最少使用 」 ,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。

该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

简单来说 如果一个数据在 「 最近一段时间 」「 使用次数很少 」 ,那么在将来一段时间内被使用的可能性也很小 ,所以我如果 「 内存到了一定限制 」 ,可以先把它淘汰掉这样。

伪代码「其实这就够了」

这里的话我选择用 双向链表 + HashMap 的写法:

  1. 首先定义一下Node节点


public class Node {

private int key;

private int val;

private Node pre;

private Node next;

public Node(int key, int val) {

this.key = key;

this.val = val;

this.pre = null;

this.next = null;

}

}

  1. 定义双向链表

// 这里的链表只存头和尾,主要是控制最近最少使用「head」,和最新使用的「tail」

public class LinkedList {

private Node head;

private Node tail;

// 最新使用的数据的话就需要把数据移动到尾

public void moveToTail(Node n) {

// 将已存在的n移到尾部

}

// 最新使用的新数据就加入到尾

public void addToTail(Node n) {

// 将n加入到tail后面

}

// 到达限制要移除头部

public Node removeHead() {

// 移除头部然后返回

}

}

  1. LRUCache

public class LRUCache {

private HashMap<Integer, Node> map;

private LinkedList list;

private capacity;

public int get(int key) {

// 获取Node

// 刚用完,移到尾部

// 返回

}

public void put(int key, int val) {

// 查看一下map原来有没有

// 有 -> 修改val并移到尾部(刚用完)

// 无 -> 1. 加入尾部,放进map

// 无 -> 2. 比较map的大小跟限制的长度capacity,大了就移除最近最少使用的head,小了不管就ok。

}

}

完整代码及分析

import java.util.HashMap;



/**

* LRUCache

* @author tonghua

* @create 2020-03-14 16:53

*/

public class LRUCache {

// 双向链表控制头尾

private LinkedList list;

// hashmap保存数据

private HashMap<Integer, Node> map;

// capacity限制LRUCache的大小

private int capacity;


public LRUCache(int capacity) {

this.map = new HashMap<>();

this.list = new LinkedList();

this.capacity = capacity;

}


public class Node {

public int key;

public int val;

Node pre;

Node next;


public Node(int key, int val) {

this.key = key;

this.val = val;

this.pre = null;

this.next = null;

}

}


// head为最近最少使用的

public class LinkedList {

public Node head;

public Node tail;


public LinkedList() {

this.head = null;

this.tail = null;

}

// 最新使用的数据的话就需要把数据移动到尾

public void moveToTail(Node n) {


// 如果用的是头,那么把头往后移一个

if (n == head) {

head = n.next;

head.next = null;

} else {

n.pre.next = n.next;

n.next.pre = n.pre;

}

// 把对应的n移动到尾部

tail.next = n;

n.pre = tail;

n.next = null;

tail = n;

}


// 最新使用的新数据就加入到尾

public void addToTail(Node n) {

// 如果是第一个,头跟尾都是n

if (head == null) {

head = n;

tail = n;

} else {

// 不是第一个就往尾后加n,尾后移一个

tail.next = n;

n.pre = tail;

tail = tail.next;

}

}


// 移除最近最少使用元素

public Node removeHead() {

Node n = head;

// 这种情况只会出现在capacity=1的情况

if (head == tail) {

head = null;

tail = null;

} else {

// 正常应该是把头移除,然后返回头(给hashMap移除用的)

head = head.next;

head.pre = null;

}

return n;

}

}


public int get(int key) {

if (!map.containsKey(key)) {

return -1;

} else {

Node n = map.get(key);

list.moveToTail(n);

return n.val;

}

}


public void put(int key, int val) {

if (map.containsKey(key)) {

Node n = map.get(key);

n.val = val;

list.moveToTail(n);

} else {

Node n = new Node(key, val);

map.put(key, n);

list.addToTail(n);


if (map.size() > capacity) {

map.remove(list.removeHead().key);

}


}

}

}


PS

都结合网上资料加上自己的一些理解,如果有影响到人的地方,可以联系我: fzfz2007@163.com


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算机程序设计艺术(第1卷)

计算机程序设计艺术(第1卷)

[美] Donald E. Knuth / 清华大学出版社 / 2002-9 / 80.00元

第1卷首先介绍编程的基本概念和技术,然后详细讲解信息结构方面的内容,包括信息在计算机内部的表示方法、数据元素之间的结构关系,以及有效的信息处理方法。此外,书中还描述了编程在模拟、数值方法、符号计算、软件与系统设计等方面的初级应用。此第3版增加了数十项简单但重要的算法和技术,并根据当前研究发展趋势在数学预备知识方面做了大量修改。一起来看看 《计算机程序设计艺术(第1卷)》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具