class DLinkNode {
key = '';
value = null;
pre = null;
next = null;
constructor(key,value) {
this.key = key;
this.value = value;
}
}
/**
*
* LRU 缓存
*
*/
class LRUCache {
/** LRU缓存容量 */
capacity = 3;
/** 内部维护一个map */
map = new Map();
/** 键值队列 */
keyList = [];
// 至于为什么不使用对象数组存储就是为了减少时间复杂度,数组的话就需要遍历而链表就
/** 双向链表头节点 哑结点 避免空节点判断 */
head;
/** 双向链表尾结点 哑结点 避免空节点判断 */
tail;
size = 0;
constructor(capacity) {
if(typeof capacity !== 'number') return;
this.capacity = capacity;
this.head = new DLinkNode();
this.tail = new DLinkNode();
this.head.next = this.tail;
this.tail.pre = this.head;
}
get(key) {
const node = this.map.get(key);
if(!node) return -1;
// 将最近访问的数据移动到头部
this.moveToHead(node);
return node.value;
}
put(key,value) {
let node = this.map.get(key);
if(!node) {
let newNode = new DLinkNode(key,value);
// 添加到哈希表
this.map.set(key,newNode);
this.addToHead(newNode);
++this.size;
// 当超过容量的时候将链表尾部的数据移除
if(this.size > this.capacity) {
// 链表头部是最新的记录,越靠后数据越旧
let tail = this.removeTail();
this.map.delete(tail.key);
--this.size;
}
} else {
// 如果key存在,先通过哈希表定位,再修改value,并移动到头部
node.value = value;
this.moveToHead(node);
}
}
/** 将链表上的节点移动到头部 */
moveToHead(node) {
this.removeNode(node);
this.addToHead(node);
}
removeNode(node) {
node.pre.next = node.next;
node.next.pre = node.pre;
}
addToHead(node) {
node.pre = this.head;
node.next = this.head.next;
this.head.next.pre = node;
this.head.next = node;
}
removeTail() {
let res = this.tail.pre;
this.removeNode(res);
return res;
}
}
const lruCache = new LRUCache(3);
lruCache.put('1','hello');
lruCache.put('2','asdf');
lruCache.put('3','asdfasdf');
lruCache.put('4','4');
console.log(lruCache.get('4'));
console.log(lruCache.get('1'));