LRU缓存是指在插入新数据时如果超过了该缓存的容量就将最久未使用的数据释放掉,这是leetcode146的题目,题目如下所示:
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache
类:
LRUCache(int capacity)
以 正整数 作为容量capacity
初始化 LRU 缓存int get(int key)
如果关键字key
存在于缓存中,则返回关键字的值,否则返回-1
。void put(int key, int value)
如果关键字key
已经存在,则变更其数据值value
;如果不存在,则向缓存中插入该组key-value
。如果插入操作导致关键字数量超过capacity
,则应该 逐出 最久未使用的关键字。
首先LRU缓存要求要淘汰最久未使用的数据,所以我们存放的数据它有个先后的顺序,这里我想到的数据结构就是链表,又因为需要判断关键字key是否存在于缓存中,如果只是单纯的链表数据结构的话遍历出这个key的时间复杂度是o(n),所以我们考虑给他升个级再给它加一个哈希表,哈希表key存关键字,value存相应的链表节点,这样就能很快的判断缓存中是否有该关键字对应的数据。(最后贴上我年老失修的代码,如果有更简洁的写法可以贴给我^^)
class LRUCache {
class Node {
public int key,val;
public Node next, prev;
public Node( int v,int k) {
this.val = v;
this.key=k;
}
}
//缓存的容量
private int capacity;
private Map<Integer,Node> map=new HashMap<Integer, Node>();
//头节点
private Node head;
//当前已存储的量
private int now=0;
public LRUCache(int capacity) {
this.capacity=capacity;
}
//获取数据
public int get(int key) {
//先看map中是否含有 没有return -1
//有的话 先将该节点移除 再加入到头节点
if(map.containsKey(key)){
Node node = map.get(key);
remove(node);
putH(node);
return node.val;
}
else {
return -1;
}
}
//插入数据
public void put(int key, int value) {
//先看缓存是否含有 1.有则将该节点的值修改,并插入头节点 2.没有则加入到头节点 并判断是否要弹出尾节点
if(map.containsKey(key)){
Node node=map.get(key);
node.val=value;
//如果已经是头节点就不用操作了
if(head!=node){
remove(node);
putH(node);
}
}
else {
Node node=new Node(value,key);
if(head==null){
head=node;
head.next=head;
head.prev=head;
now++;
map.put(key,node);
return;
}
putH(node);
map.put(key,node);
now++;
if(now>capacity){
map.remove(head.prev.key);
remove(head.prev);
}
}
}
//将节点插入到头部
public void putH(Node node){
node.next=head;
node.prev=head.prev;
head.prev.next=node;
head.prev=node;
head=node;
}
//移除当前节点
private void remove(Node node){
node.prev.next=node.next;
node.next.prev=node.prev;
}
}