小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
题目
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。 实现 LRUCache 类:
LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存 int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。 void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
来源:力扣(LeetCode)
难度:medium
思路
1.一个双向链表节点存储key和value
2.一个map集合存储key和双向链表节点的映射
3.一个辅助头节点一个辅助尾节点,更新或者添加时将节点加到辅助头节点后面,删除时删除辅助尾节点后面的元素
代码
class LRUCache {
int capacity; //缓存的最大容量
int size; //当前使用的容量
//创建一个辅助头节点
DListNode head;
//创建一个辅助尾节点
DListNode tail;
Map<Integer, DListNode> map; //记录key和对应的双向链表节点的映射
class DListNode {
DListNode pre;
DListNode next;
int key;
int value;
public DListNode(int key, int value) {
this.key = key;
this.value = value;
}
}
public LRUCache(int capacity) {
this.capacity = capacity;
this.head = new DListNode(-1, -1);
this.tail = new DListNode(-1, -1);
head.next = tail;
tail.pre = head;
map = new HashMap<>();
}
public int get(int key) {
if (map.get(key) == null) return -1;
addToHead(map.get(key));
return map.get(key).value;
}
public void put(int key, int value) {
if (map.get(key) != null) {
map.get(key).value = value; //更新值
addToHead(map.get(key));
return;
}
DListNode node = new DListNode(key, value);
addToHead(node);
map.put(key, node);
size++;
if (size > capacity) {
removeTail();
}
}
public void addToHead(DListNode node) {
if (node.pre != null && node.next != null) { //判断这个是新节点加入还是老节点更新
node.next.pre = node.pre;
node.pre.next = node.next;
}
node.pre = head;
node.next = head.next;
head.next.pre = node;
head.next = node;
}
public void removeTail() { //删除尾节点
map.remove(tail.pre.key);
tail.pre.pre.next = tail;
tail.pre = tail.pre.pre;
size--; //删除之后使用的容量变少了
}
}