[原创]LRU算法的简单实现(基于Java链表)
最近最久未使用(LRU,Least Recently Used)算法,是操作系统中一种常用的页面置换策略。
例如下图,对于序列
{1, 8, 1, 7, 8, 2, 7, 2, 1, 8, 3, 8, 2, 1, 3, 1, 7, 1, 3, 7}
最终留在缓存中的页面是2,1,3,7.
今天使用链表简单实现了一下,我的思路是,在页面调度的过程中,维护一个单链表结构,当有新页面出现时,如果链表未达最大缓存容量,将新页面直接挂在链表尾部;如果缓存已满,需要先遍历缓存中的页面,查看新页面是否命中缓存。
如果命中,则将链表中命中的页面删除,并将新页面挂在链表尾部;若未命中,将链表起始结点删除,再将新页面挂在链表尾部。
代码如下:
LRU
class LRU {
private class Node {
Node next;
int val;
public Node(int val) {
this.val = val;
}
}
//缓存容量
private int cap;
//首结点
private Node head;
public LRU(int cap) {
this.cap = cap;
}
//获取链表长度
public int getLength() {
int length = 0;
Node temp = head;
while (temp != null) {
temp = temp.next;
length++;
}
return length;
}
//插入节点
public void put(int e) {
Node node = new Node(e);
Node temp = head;
//空结点,直接插入
if (head == null) {
head = node;
//结点未满时,插入到末尾
} else if (this.getLength() < cap) {
while (temp.next != null) {
temp = temp.next;
}
temp.next = node;
//结点(页面)满时,分两种情况:1,新结点未命中,删除头结点,增加尾结点;2,新结点命中,将命中结点删除,并将命中结点添加在末尾
} else {
int count = 0;
//命中页面的序号
int index = -1;
//是否命中
boolean flag = false;
while (temp != null) {
if (temp.val == e) {
flag = true;
index = count;
break;
}
count++;
temp = temp.next;
}
//情况1
if (flag) {
//头结点为命中的结点
if (index == 0) {
head = head.next;
//否则,查找命中结点并删除
} else {
int i = 0;
Node temp2 = head;
while (temp2 != null) {
if (i == index - 1) {
temp2.next = temp2.next.next;
break;
}
i++;
temp2 = temp2.next;
}
}
}
//情况2
else {
//删除头结点
head = head.next;
}
//添加尾结点
Node temp1 = head;
while (temp1.next != null) {
temp1 = temp1.next;
}
temp1.next = node;
}
}
//打印缓存中的页面
public void printList() {
if (head == null) {
System.out.println("空");
} else {
Node temp = head;
while (temp != null) {
System.out.print(temp.val + " ");
temp = temp.next;
}
}
}
}
public class Main {
public static void main(String[] args) {
LRU lru = new LRU(4);
int[] input = new int[]{1, 8, 1, 7, 8, 2, 7, 2, 1, 8, 3, 8, 2, 1, 3, 1, 7, 1, 3, 7};
for (int e : input) {
lru.put(e);
}
lru.printList();
}
}
打印结果:
如果想要提高访问效率,可以采用HashMap等结构辅助记录结点所在位置。