=======================2019.1.18====================
双向链表+hashmap。双向链表存key的先后顺序消息,hashmap快速定位元素。
class LRUCache {
Node first;
Node end;
final int K;
int cap;
HashMap<Integer,Node> map;
public LRUCache(int capacity) {
map=new HashMap<>();
first=new Node(0,0);
end=new Node(0,0);
K=capacity;
first.next=end;
end.pre=first;
}
public int get(int key) {
if(map.get(key)==null) return -1;
Node node=map.get(key);
node.pre.next=node.next;
node.next.pre=node.pre;
node.next=end;
node.pre=end.pre;
end.pre.next=node;
end.pre=node;
return node.val;
}
public void put(int key, int value) {
if(map.get(key)!=null){
map.get(key).val=value;
get(key);
}else{
Node node=new Node(key,value);
map.put(key,node);
node.pre=end.pre;
node.next=end;
end.pre.next=node;
end.pre=node;
if(cap==K){
Node n=first.next;
map.remove(n.key);
first.next=n.next;
n.next.pre=first;
}else{
cap++;
}
}
}
class Node{
int key;
int val;
Node pre;
Node next;
Node(int key,int val){
this.key=key;
this.val=val;
}
}
}
===================================================
双向链表实现LRU Cache
注意1.各种边界条件(改节点位置的时候考虑节点目前的位置)
2.查找到,插入(分update,set)都要考虑找到元素的位置的修改。
复杂度get,set为O(n)
public class LRUCache {
int capacity;
int count=0;
Node begin;//起始结束标记节点,可以简化处理边界条件
Node end;
class Node{
Node pre;
Node next;
int key;
int value;
Node(Node pre,Node next,int key,int value){
this.pre=pre;
this.next=next;
this.key=key;
this.value=value;
}
}
/*
* @param capacity: An integer
*/public LRUCache(int capacity) {
this.capacity=capacity;
begin=new Node(null,null,0,0);
end=new Node(begin,null,0,0);
begin.next=end;
}
/*
* @param key: An integer
* @return: An integer
*/
public int get(int key) {
Node pretemp;
Node nexttemp;
for(Node node=begin.next;node!=end;node=node.next){
pretemp=node.pre;
nexttemp=node.next;
//注意边界条件,它不是begin下一个节点,不然会修改自己!!!!!!
if(node.key==key){
if(node.pre!=begin){
//把此节点放到头部,需要记录他的前一个节点,和后一个节点,并连接
//放到头节点,前面的节点是最近使用过的
begin.next.pre=node;
node.next=begin.next;
node.pre=begin;
begin.next=node;
//连接他的上一个节点和下一个节点
pretemp.next=nexttemp;
nexttemp.pre=pretemp;
}
return node.value;
}
}
return -1;
}
/*
* @param key: An integer
* @param value: An integer
* @return: nothing
*/
public void set(int key, int value) {
//找到的话数据也要移动到最前面
Node pretemp;
Node nexttemp;
for(Node node=begin.next;node!=end;node=node.next){
//坑!!找到key值也要把节点放在前面!!!!!
pretemp=node.pre;
nexttemp=node.next;
if(node.key==key){
if(node.pre!=begin){
//把此节点放到头部,需要记录他的前一个节点,和后一个节点,并连接
//放到头节点,前面的节点是最近使用过的
begin.next.pre=node;
node.next=begin.next;
node.pre=begin;
begin.next=node;
//连接他的上一个节点和下一个节点
pretemp.next=nexttemp;
nexttemp.pre=pretemp;
}
node.value=value;
return;
}
}
//没找到的话,插入到最前面
Node node=new Node(begin,begin.next,key,value);
begin.next.pre=node;
begin.next=node;
count++;
if(count>capacity){
//把最后一项删除
end.pre.pre.next=end;
end.pre=end.pre.pre;
count--;
}
}
}
改进参考:
http://www.bubuko.com/infodetail-430031.html
那就是利用链表和hashmap (Map<Integer, Node>)(时间复杂度O(1),hashMap经常能把复杂度改进到O(1))
1)set(key,value):如果key在hashmap中存在,则先重置对应的value值,然后获取对应的节点cur,将cur节点从链表删除,并移动到链表的头部;若果key在hashmap不存在,则新建一个节点,并将节点放到链表的头部。当Cache存满的时候,将链表最后一个节点删除即可。
2)get(key):如果key在hashmap中存在,则把对应的节点放到链表头部,并返回对应的value值;如果不存在,则返回-1。