LRU缓存
题目描述:
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
思路:
get函数需要时间复杂度为o(1),那必然需要使用hash值来存取,可以联想到使用map来存储,但是如果想实现lru,那所有(key,value)应该是按照新旧程度排序的,而map中的元素是无序的。要想同时满足有序且hash值存取,可以采用map+链表,map格式为(Integer,node),一个个node再组成链表。链表尾部是最新使用的关键字,头部为最旧。
当作get,我们查询map中是否存在key,若存在,直接返回相应node.value,并将这个node的位置改到链表尾端。
当作put,查询map中是否存在key,若存在,修改对应node的value,并将node移至链表尾端,若不存在,链表size小于capacity则直接加入map和链表的尾端,size大于capacity,则移除链表的第一个节点以及map中对应的元素,然后将新key加入map和链表。
代码:
class LRUCache {
int capacity;
Map<Integer,Node> map ;
DoubleList doubleList;
public LRUCache(int capacity) {
this.capacity = capacity;
this.map = new HashMap<>();
this.doubleList = new DoubleList();
}
public int get(int key) {
Node node = map.get(key);
if(node==null)return -1;
else {
doubleList.removeNode(node);
doubleList.add(node);
return node.value;
}
}
public void put(int key, int value) {
if(map.containsKey(key)){
Node node = map.get(key);
node.value = value;
doubleList.removeNode(node);
doubleList.add(node);
return;
}
if(doubleList.size<capacity){
Node node = new Node(key, value);
doubleList.add(node);
map.put(key,node);
return;
}
int k = doubleList.removeHead();
Node node = new Node(key, value);
doubleList.add(node);
map.remove(k);
map.put(key,node);
}
}
class Node{
int key;
int value;
Node prev;
Node next;
public Node(){}
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
class DoubleList{
Node head;
Node tail;
int size;
public DoubleList() {
head = new Node();
tail = new Node();
head.next=tail;
tail.prev =head;
size = 0;
}
public void add(Node node){
tail.prev.next = node;
node.prev =tail.prev;
node.next = tail;
tail.prev = node;
size++;
}
public int removeHead(){
Node node = head.next;
head.next = node.next;
node.next.prev = head;
size--;
return node.key;
}
public void removeNode(Node node){
node.prev.next = node.next;
node.next.prev = node.prev;
size--;
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/