思路:HashMap + 双向链表的数据结构实现一个LRU缓存
tai节点指向最近访问过的节点,head指向最久未被访问过的节点,因此,put(int key, int val)的流程
- 如果key已存在,修改对应的节点的value值,并将此节点移动至tail所指向的位置处
- 如果key不存在
- 如果当前集合大小超过了capacity,则删除head所指向的节点和map集合中指定的key, 并将新创建的节点同时存入haspmap 集合中,和插入双向链表之中。
- 如果不存在,将新创建的节点同时存入haspmap集合中,和插入双向链表之中。
注意:再删除和插入的过程中,集合的链表的操作要保持同步
实现代码
class LRUCache {
//定义双向链表的节点
class DLinkedNode{
int key;
int val;
DLinkedNode prev;
DLinkedNode next;
public DLinkedNode(){
this.key = -1;
this.val = -1;
this.prev = null;
this.next = null;
}
public DLinkedNode(int key, int val){
this.key = key;
this.val = val;
}
}
private int capacity;
private Map<Integer, DLinkedNode> cache;
private DLinkedNode head;
private DLinkedNode tail;
public LRUCache(int capacity) {
this.capacity = capacity;
this.head = new DLinkedNode(-1, -1);
this.tail = new DLinkedNode(-1, -1);
this.cache = new HashMap<>();
this.head.next = tail;
this.tail.prev = head;
}
public int get(int key) {
DLinkedNode node = cache.getOrDefault(key, null);
if(node == null){
return -1;
}
int ret = node.val;
//讲节点移动到双向链表的尾部
node.prev.next = node.next;
node.next.prev = node.prev;
tail.prev.next = node;
node.prev = tail.prev;
node.next = tail;
tail.prev = node;
return ret;
}
public void put(int key, int value) {
//如果key已存在
DLinkedNode targetNode = cache.getOrDefault(key, null);
//直接覆盖原来的值
if(targetNode != null){
targetNode.val = value;
//移动至tail所指向的位置处(最近访问过的节点)
targetNode.prev.next = targetNode.next;
targetNode.next.prev = targetNode.prev;
tail.prev.next = targetNode;
targetNode.prev = tail.prev;
targetNode.next = tail;
tail.prev = targetNode;
return;
}
//新插入
//容量达到最大值
if(cache.size() >= this.capacity){
DLinkedNode toBeDelete = head.next;
cache.remove(toBeDelete.key);//删除hash集合中的指针,所以DLinkedNode里面也需要有保存key的字段
// //删除头节点位置处的指针
head.next = toBeDelete.next;
toBeDelete.next.prev = head;
}
//插在链表尾部
DLinkedNode node = new DLinkedNode(key, value);
tail.prev.next = node;
node.prev = tail.prev;
node.next = tail;
tail.prev = node;
//往hash集合中添加
cache.put(key, node);
}
}
/**
* 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);
*/