LRU算法,最久未被使用算法,有一个固定大小的cache,当装不下任务的时候,就会选取,最久未被使用过的任务,进行淘汰。对于LRU要求有如下:
1,查找和删除都是O1级别的,O1级别立马就想到了hash表结构,满足这个要求。
2,要求把使用过的任务安放起来,用的时候,就去寻找,这个想到了用链表来实现。
实际上java中提供了这两种结构的结合题,这就是LinkedHashMap。用这种结构就能解决力扣上的LRU算法题,代码如下:
class LRUCache {
private int cap;
private Map<Integer, Integer> map = new LinkedHashMap<>(); // 保持插入顺序
public LRUCache(int capacity) {
this.cap = capacity;
}
public int get(int key) {
if (map.keySet().contains(key)) {
int value = map.get(key);
map.remove(key);
// 保证每次查询后,都在末尾
map.put(key, value);
return value;
}
return -1;
}
public void put(int key, int value) {
if (map.keySet().contains(key)) {
map.remove(key);
} else if (map.size() == cap) {
Iterator<Map.Entry<Integer, Integer>> iterator = map.entrySet().iterator();
iterator.next();
iterator.remove();
// int firstKey = map.e***ySet().iterator().next().getValue();
// map.remove(firstKey);
}
map.put(key, value);
}
}
但是一般来说,面试考察的就是你怎么去构建哪两种结构,一般是不会允许这样的,那么就需要手动的创建链表,和hash
- 首先创建链表中的每个元素节点,节点中的属性有,key,value,pre(指向前一个节点),next(指向后一个节点)。
class Node{
int key;
int value;
Node pre;
Node next;
public Node(int key,int value){
this.key=key;
this.value=value;
}
public Node(){
}
}
- 创建双向链表,双向链表里面的属性就少一些,是头节点,和尾节点
class DoubleList{//双链表head<->[key,val]<->tail
//头节点
Node head;
//尾节点
Node tail;
public DoubleList(){//构造方法
head=new Node(0,0);
tail=new Node(0,0);
head.next=tail;
tail.pre=head;
}
public void addFirst(Node n){//头插法
head.next.pre=n;
n.next=head.next;
head.next=n;
n.pre=head;
}
//删除某个节点
public void remove(Node n){
n.pre.next=n.next;
n.next.pre=n.pre;
n.next=null;
n.pre=null;
}
public Node removeLast(){
//删除最后一个并且返回
Node res=tail.pre;
remove(res);
return res;
}
}
- 接下来就是创建put 和get方法,思路是这样的,无论是put还是get后,都相当于操作了这个节点,所以一定要放在链表的头部。对于get方法,通过map可以快速的查到链表里是否含有这个节点,如果含有,就把他获取,删除,在次添加。对于set方法,如果已经有key相同的情况,就修改它的value。删除,放入队头。还要检测是否大于cache,如果大于,就把链表的最后一个删除。实现代码如下:
class LRUCache {
HashMap<Integer,Node> map;
DoubleList cache;
int cap;//容量
public LRUCache(int capacity) {
map = new HashMap<>();
cache = new DoubleList();
this.cap = capacity;
}
public int get(int key) {
if(!map.containsKey(key))//若该节点不存在
return -1;
Node res = map.get(key);
cache.remove(res);
cache.addFirst(res);
return res.val;
}
public void put(int key, int value) {
Node n = new Node(key,value);
if(map.containsKey(key)){//若该节点已经存在
cache.remove(map.get(key));
}else if(map.size()==cap){//若该节点不存在,但是cache已满
Node last = cache.removeLast();
map.remove(last.key);
}
cache.addFirst(n);
map.put(key,n);
}
}
如有错误请指出