LRU可以算是书本中比较熟悉的算法了,有缓存存在的场景下,基本都会有它的身影。它的作用就是在空间一定的缓存中,淘汰掉最近最少使用的数据,这样就有空间容纳新的数据。
那么假如需要设计一个类似LRU的算法,要支持获取数据get和插入数据put,并且要求时间复杂度在O(1)。
如果get返回-1,代表这个值不在缓存中,否则返回对应的值。
put(k,v)的操作,如果k在缓存中,那就更新。如果不存在就插入,如果缓存容量满了,就把最近没有使用过的数据删掉,再插入。
要求时间复杂度O(1),说明查找的速度和插入的速度都必须很快。
我们还要维护一个最近最久未使用的数据
,但是这个数据一旦被访问过,就不再是最近最久未使用的数据了。
结合这几个要求,链表应该是最符合的数据结构了,但是链表存在一个问题,查找的速度不是O(1)。那就再加一个Map,把所有的链表节点都放到Map中,这样查找的速度就是O(1)。
链表还必须是带尾指针的双向链表,这样删除的操作就会更加的方便。
class LRUCache {
//实现一个双向链表
public class DList{
private Node ret;
private int size;
private Node tail;
public DList(){
this.ret = new Node(-1,-1);
this.size=0;
}
public void addFirst(Node node){
if(ret.next==null){
ret.next = node;
node.prev = ret;
tail = node;
size++;
return;
}
Node p = ret.next;
node.next =p;
ret.next = node;
p.prev = node;
node.prev = ret;
size++;
return;
}
public void remove(Node node){
if(node==tail){
tail = tail.prev ;
}
Node p = node.prev;
Node q = node.next;
p.next = q;
if(q!=null){
q.prev = p;
}
size--;
}
public Node removeLast(){
Node res = tail;
remove(tail);
return res;
}
public int size(){
return this.size;
}
}
public class Node {
public int key, val;
public Node next, prev;
public Node(int k, int v) {
this.key = k;
this.val = v;
}
}
private HashMap<Integer, Node> map;
private int cap;
private DList cache;
public LRUCache(int capacity) {
this.cap = capacity;
this.map = new HashMap<>();
this.cache = new DList();
}
public int get(int key) {
if(!map.containsKey(key)){
return -1;
}
Node node = map.get(key);
int val = node.val;
put(key,val);
return val;
}
public void put(int key, int value) {
Node x = new Node(key, value);
if(map.containsKey(key)){
cache.remove(map.get(key));
cache.addFirst(x);
map.put(key,x);
}
else{
if(cap == cache.size()){
Node last = cache.removeLast();
map.remove(last.key);
}
cache.addFirst(x);
map.put(key,x);
}
}
}
design
LRU
【数据结构】算法设计 LRU Least Recently Used 最近最少使用算法
原文:https://www.cnblogs.com/dreamtaker/p/14854881.html