题目:
例子:
思想:
双向链表+哈希表的使用
思路:
定义一个双向链表,通过双向链表来达到时间复杂度为O(1)的操作。
- 定义双向链表,向前指针和向后指针。
- 初始化数据结构时,构造虚拟头节点和虚拟尾节点。
- 对于get操作时,若不存在,返回-1;若存在,返回值,并在链表中先删除该节点,再将该节点放在虚拟头节点之后。
- 对于put操作,若存在键,更新值,移动操作同上步;若不存在键,在哈希表中存新的节点并将其放在头节点之后。
- 判断是否超过我们所定义的容量大小,若超过,则删除虚拟尾节点之前的节点。
代码:
class LRUCache {
class DoubleList {
int key;
int value;
DoubleList next;
DoubleList prev;
public DoubleList() {}
public DoubleList(int key, int value) {
this.key = key;
this.value = value;
}
}
HashMap<Integer, DoubleList> map = new HashMap<>();
DoubleList head, tail;
int capacity;
int size;
public LRUCache(int capacity) {
this.capacity = capacity;
head = new DoubleList();
tail = new DoubleList();
head.next = tail;
tail.prev = head;
this.size = 0;
}
public int get(int key) {
if (map.get(key) == null) return -1;
moveToHead(key);
return map.get(key).value;
}
public void put(int key, int value) {
if (map.get(key) != null) {
DoubleList doubleList = map.get(key);
doubleList.value = value;
map.put(key,doubleList);
moveToHead(key);
} else {
DoubleList doubleList = new DoubleList(key, value);
//加入新值
map.put(key, doubleList);
addToHead(key);
size++;
//超出
if (size > capacity) {
//删除tail
DoubleList tailDouble = removeTail();
map.remove(tailDouble.key);
size--;
}
}
}
public void addToHead(int key) {
DoubleList doubleList = map.get(key);
//更新头节点
doubleList.prev = head;
doubleList.next = head.next;
head.next.prev = doubleList;
head.next = doubleList;
}
public void removeNode(int key) {
DoubleList doubleList = map.get(key);
//删除结果
doubleList.prev.next = doubleList.next;
doubleList.next.prev = doubleList.prev;
}
public void moveToHead(int key) {
DoubleList doubleList = map.get(key);
removeNode(key);
addToHead(key);
}
public DoubleList removeTail() {
DoubleList result = tail.prev;
result.prev.next = tail;
tail.prev = result.prev;
return result;
}
}