今天研究一下LRU算法,上学期学数据结构的时候就应该学一下这个算法,不过后面操作系统也会讲到LRU算法
题目
LRU缓存leetocde146
LRU(Least Recently Used,最近最少使用)算法是一种常见的缓存替换算法,通常用于缓存管理中。它的核心思想是,当缓存空间满时,会优先淘汰最近最少使用的缓存数据,以便为新的数据腾出空间。LRU算法的基本原理是基于时间局部性原理,即最近被访问的数据很可能在未来会被再次访问。。
如何使用数组或者链表来实现,效率比较对,为了实现On的效率,我们可以采用双链表,但是要找到一个值,双链表的查询还是O(n),那么就可以引入hash,不产生碰撞的情况下,hash的效率是O(1);
所以来用双链表+Hash来实现。
分析;
需要有插入和get操作,并且要求事件复杂度都是O1。
思路,对于put操作,如果当前的节点已经存在,修改当前节点的值,再讲节点移动到头节点去。
如果空间已经满了,需要删除最后一个节点,因为是双链表所以事件复杂度为o1,并且将这个节点插入到头部去,再添加进缓存中去。
对于get操作,因为LRU算法遵循的是最近最少使用,每一次使用都会刷新,得到节点的值,并且还需呀将节点的值移动到头部去。
对于moveHead操作,分为两步分为别deleteHead和addHead,都是数据结构双链表之间的操作,插入和删除节点。
package LRU;
import java.util.HashMap;
import java.util.Map;
public class LRUCache {
Entry head, tail;
int capacity;
int size;
Map<Integer, Entry> cache;
public LRUCache(int capacity) {
this.capacity = capacity;
size = 0;
initLinkedList(); //初始化缓存链表
cache = new HashMap<>(capacity + 2); //引入了两个哨兵
}
public void put(int key, int value) {
Entry node = cache.get(key);
if (node !=null) {
node.value = value;
moveHead(node);
return;
}
if (size == capacity) {
//空间满了
Entry lastNode = tail.pre;
deleteHead(lastNode);
cache.remove(lastNode.key);
size--;
}
Entry newNode = new Entry();
newNode.key = key;
newNode.value = value;
addNode(newNode);
cache.put(key, newNode);
size++;
}
public int get(int key) {
Entry node = cache.get(key);
if (node ==null) {
return -1;
}
moveHead(node);
return node.value;
}
private void moveHead(Entry node) {
//删除
deleteHead(node);
addNode(node);
}
private void addNode(Entry node) {
//讲节点插入到头节点去
head.next.pre = node;
node.next = head.next;
node.pre = head;
head.next = node;
}
private void deleteHead(Entry node) {
//双链表删除一个节点
node.pre.next = node.next;
node.next.pre = node.pre;
}
public void initLinkedList() {
head = new Entry();
tail = new Entry();
head.next = tail;
tail.next = head;
}
public static class Entry {
public Entry pre;
public Entry next;
public int key;
public int value;
public Entry(int key,int value) {
this.key=key;this.value=value;
}
public Entry() {
}
}
public static void main(String[] args) {
LRUCache cache=new LRUCache(2);
cache.put(1,1);
cache.put(1,2);
System.out.println(cache.get(1)); //得到现在的缓存2,并且当前的2已经移动到最前面去了
//再加进来3的时候,1就会被删除
cache.put(3,3);
System.out.println(cache.get(2));
}
}