描述
为最近最少使用(LRU)缓存策略设计一个数据结构,它应该支持以下操作:获取数据(get)和写入数据(set)。
获取数据get(key):如果缓存中存在key,则获取其数据值(通常是正数),否则返回-1。
写入数据set(key, value):如果key还没有在缓存中,则写入其数据值。当缓存达到上限,它应该在写入新数据之前删除最近最少使用的数据用来腾出空闲位置。
分析
可以定义一个双向链表来实现元素Node的存储,Node有成员变量key和value。采用key作为hashmap表中的key属性,value属性则存放Node。
假设双链表的尾端表示最近最常用,头端表示最近最少用。
调用get()方法,若元素存在,则将该元素移动到尾端,并返回该元素值,否则返回-1;
调用set()方法,首先检查该元素是否存在,若存在,则把该元素放置尾端,并赋新的value值;如果此时hashmap中的元素个数已超过capcality,则需要删除头结点的下一个结点(最近最少使用结点)。然后,通过新建Node元素来把新的元素放在hashmap中,并把元素放至尾端。
代码
public class LRUCache {
private class Node{
Node prev;
Node next;
int key;
int value;
public Node(int key,int value){
this.key=key;
this.value=value;
this.next=next;
this.prev=prev;
}
}
public HashMap<Integer,Node> hashMap=new HashMap<>();
private int capacity;
public Node head=new Node(-1,-1);
public Node tail=new Node(-1,-1);
/*
* @param capacity: An integer
*/public LRUCache(int capacity) {
// do intialization if necessary
this.capacity=capacity;
//构成双向链表,便于添加删除
head.next=tail;
tail.prev=head;
}
/*
* @param key: An integer
* @return: An integer
*/
public int get(int key) {
// write your code here
if(!hashMap.containsKey(key)){
return -1;
}
//先把该节点拿出来
Node current=hashMap.get(key);
current.next.prev=current.prev;
current.prev.next=current.next;
//把查找的结点移到尾端,尾端为最近用的这一端
move_to_tail(current);
return current.value;
}
/*
* @param key: An integer
* @param value: An integer
* @return: nothing
*/
public void set(int key, int value) {
// write your code here
//set时先会从hashmap中检查key是否存在,如果存在,就相当于使用了key,就需要往后移,但get()会自动移到tail端
if(get(key)!=-1){
//存在,则需要赋新值
hashMap.get(key).value=value;
return;
}
//如果超出容量,把链表头的下一个结点即最近最久未使用从链表中删除
if(hashMap.size()==capacity){
hashMap.remove(head.next.key);
head.next=head.next.next;
head.next.prev=head;
}
Node newnode=new Node(key,value);
hashMap.put(key,newnode);
//把新节点移动到尾端
move_to_tail(newnode);
}
public void move_to_tail(Node current){
current.prev=tail.prev;
tail.prev.next=current;
current.next=tail;
tail.prev=current;
}
}