双链表实现LRU缓存淘汰策略
Posted 不舍昼夜夫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双链表实现LRU缓存淘汰策略相关的知识,希望对你有一定的参考价值。
1.背景
LRU(Least Recently Used)是一种常用的缓存淘汰策略,即当缓存满了之后,删除最近最少使用的数据。
LRU的实现,常用的编程语言在语言层面都有实现,可以直接使用。为了深入理解LRU,本文介绍一种通过双链表实现LRU方法。
2.双链表实现方法
Java版双链表实现代码。
2.1 定义节点实体类
/**
* 链表节点.
* @author liunan1 .
*/
public class Node {
private int key;
private int value;
private Node next;
private Node prev;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
public int getKey() {
return key;
}
public int getValue() {
return value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
public Node getPrev() {
return prev;
}
public void setPrev(Node prev) {
this.prev = prev;
}
}
2.2 双链实现类
package lewis.test.algorithm.lru.model;
import java.util.Objects;
/**
* 双链表.
* @author liunan1 .
*/
public class IntList {
private int length;
private Node head;
private Node tail;
/**
* 删除最后一个节点.
*/
public void removeLast() {
if (Objects.nonNull(tail) && Objects.nonNull(tail.getPrev())) {
Node prev = tail.getPrev();
prev.setNext(null);
tail = prev;
--length;
}
}
/**
* 查找数据,未找到返回-1.
* @param key
* @return
*/
public int get(int key) {
int i = 1;
Node currentNode = head;
for(; i <= length; i++) {
int findKey = currentNode.getKey();
int value = currentNode.getValue();
Node prev = currentNode.getPrev();
Node next = currentNode.getNext();
if (findKey == key) {
// 将节点移动到链表头部
if (Objects.nonNull(prev)) {
// 1.将节点移除
prev.setNext(next);
if (Objects.nonNull(next)) {
next.setPrev(prev);
} else {
// 节点队尾,更新队尾指针.
tail = prev;
}
// 2. 将节点移动到表头
currentNode.setNext(head);
head.setPrev(currentNode);
currentNode.setPrev(null);
head = currentNode;
}
return value;
}
currentNode = next;
}
// 未找到
return -1;
}
/**
* 头部插入节点.
* @param node node.
*/
public void addHead(Node node) {
head.setPrev(node);
node.setNext(head);
head = node;
++length;
}
/**
* 链表长度.
* @return 长度.
*/
public int size() {
return length;
}
}
2.3 LRU模拟实现类
package lewis.test.algorithm.lru.model;
import java.util.Random;
/**
* LRU缓存淘汰策略实现类.
* @author liunan1 .
*/
public class LeastRecentlyUsedCache {
// 缓存容量
private int capacity;
private IntList list;
public LeastRecentlyUsedCache(int capacity) {
this.capacity = capacity;
}
/**
* 从缓存中获取数据.
* @param key .
* @return
*/
public int get(int key) {
int value = this.list.get(key);
// 未找到,从磁盘读取.
if (-1 == value) {
// 模拟从磁盘读取.
value = new Random().nextInt(100);
// 插入缓存.
put(key, value);
}
return value;
}
/**
* 插入数据.
* @param key key.
* @param value value.
*/
public void put(int key, int value) {
Node node = new Node(key, value);
list.addHead(node);
if (list.size() > capacity) {
list.removeLast();
}
}
}
3. 总结与思考
通过三个Java类,模拟实现了LRU,简单明了,易于理解。用心的读取也许已经发现,该实现查找缓存的时候,性能不够好,时间复杂度是O(n)。后续将对该实现进行优化,将时间复杂度提升到O(1)。
以上是关于双链表实现LRU缓存淘汰策略的主要内容,如果未能解决你的问题,请参考以下文章