问题
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
思路
使用哈希表、双向链表
使用哈希表保证时间复杂度为O(1),查找效率高
使用双向链表模拟LRU的队列,最近访问的放在队尾
双向链表的意义在于为哈希表指定了达到容量之后的淘汰策略
哈希表的意义在于返回节点的引用便于双向链表的删除和插入
分别使用
- C++实现
- java原生实现
- 基于LinkedHashMap
代码
C++实现
typedef struct DoubleListNode{
int key;
int value;
struct DoubleListNode* prev;
struct DoubleListNode* next;
DoubleListNode():key(0),value(0),prev(nullptr),next(nullptr){};
DoubleListNode(int _key,int _value):key(_key),value(_value),prev(nullptr),next(nullptr){}
}Node;
class LRUCache {
public:
int capacity;
unordered_map<int,Node*> mp;
Node* head;
Node* tail;
void removeNode(Node* p){
p->next->prev=p->prev;
p->prev->next=p->next;
p->prev=nullptr;
p->next=nullptr;
}
void addNode(Node* p){
head->next->prev=p;
p->next=head->next;
p->prev=head;
head->next=p;
}
LRUCache(int capacity) {
this->capacity=capacity;
head=new Node();
tail=new Node();
head->next=tail;
tail->prev=head;
}
int get(int key) {
if(!mp.count(key)){
return -1;
}else{
Node* p=mp[key];
removeNode(p);
addNode(p);
return p->value;
}
}
void put(int key, int value) {
if(mp.count(key)){
Node* p=mp[key];
p->value=value;
mp[key]=p;
removeNode(p);
addNode(p);
}else{
if(mp.size()==capacity){
Node* last=tail->prev;
removeNode(last);
mp.erase(last->key);
}
Node* p=new Node(key,value);
mp[key]=p;
addNode(p);
}
}
};
Java原生实现
class LRUCache {
class Node<K,V>{
K key;
V value;
Node<K,V> prev;
Node<K,V> next;
public Node(){
this.prev=this.next=null;
}
public Node(K key,V value){
this.key=key;
this.value=value;
this.prev=this.next=null;
}
}
class DoubleLinkedList<K,V>{
Node<K,V> head;
Node<K,V> tail;
public DoubleLinkedList(){
head=new Node<>();
tail=new Node<>();
head.next=tail;
tail.prev=head;
}
public void addHead(Node<K,V> node){
head.next.prev=node;
node.next=head.next;
node.prev=head;
head.next=node;
}
public void removeNode(Node<K,V> node){
node.prev.next=node.next;
node.next.prev=node.prev;
node.next=null;
node.prev=null;
}
public Node getLast(){
return tail.prev;
}
}
private int capacity;
Map<Integer,Node<Integer,Integer>> map;
DoubleLinkedList<Integer,Integer> doubleLinkedList;
public LRUCache(int capacity) {
this.capacity=capacity;
map=new HashMap<>();
doubleLinkedList=new DoubleLinkedList<>();
}
public int get(int key) {
if(!map.containsKey(key)){
return -1;
}
Node<Integer,Integer> node=map.get(key);
doubleLinkedList.removeNode(node); // 队列中间删除
doubleLinkedList.addHead(node); // 添加到队尾
return node.value;
}
public void put(int key, int value) {
if(map.containsKey(key)){
Node<Integer, Integer> node = map.get(key);
node.value=value;
map.put(key,node); // 更新
doubleLinkedList.removeNode(node);
doubleLinkedList.addHead(node); // 更新添加到队尾
}else{
if(map.size()==capacity){ // 根据底层的DoubleLinkedList进行淘汰
Node<Integer,Integer> node = doubleLinkedList.getLast();
map.remove(node.key);
doubleLinkedList.removeNode(node);
}
Node<Integer, Integer> node = new Node<>(key, value);
map.put(key,node);
doubleLinkedList.addHead(node);
}
}
}
基于LinkedHashMap
class LRUCache {
int capacity;
LinkedHashMap<Integer,Integer> map;
public LRUCache(int capacity){
this.capacity=capacity;
map=new LinkedHashMap<Integer,Integer>(capacity,0.75f,true){
@Override
protected boolean removeEldestEntry(Map.Entry eldest){
return map.size()>capacity;
}
};
}
public int get(int key){
if(map.containsKey(key)){
return map.get(key);
}else
return -1;
}
public void put(int key,int value){
map.put(key,value);
}
}