双向链表
LRU
js
class DListNode {
constructor(key, val, prev, next) {
this.key = key ?? 0;
this.val = val ?? 0;
this.prev = prev ?? null;
this.next = next ?? null;
}
}
class LRUCache {
map = new Map();
head = new DListNode();
tail = new DListNode();
constructor(capacity) {
this.capacity = capacity;
this.head.next = this.tail;
this.tail.prev = this.head;
}
get(key) {
if (!this.map.has(key)) {
return -1;
}
const node = this.map.get(key);
this.moveToHead(node);
return node.val;
}
put(key, val) {
if (this.map.has(key)) {
const node = this.map.get(key);
node.val = val;
this.moveToHead(node);
return;
}
if (this.map.size === this.capacity) {
const node = this.tail.prev;
this.deleteNode(node);
this.map.delete(node.key);
}
const node = new DListNode(key, val);
this.insertHead(node);
this.map.set(key, node);
}
moveToHead(node) {
this.deleteNode(node);
this.insertHead(node);
}
deleteNode(node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
insertHead(node) {
node.next = this.head.next;
this.head.next.prev = node;
this.head.next = node;
node.prev = this.head;
}
}扩展:支持过期时间
- 链表节点新增过期时间
expiredAt get获取时判断节点是否过期put支持传入过期时间、默认永不过期put判断是否已满前清理过期节点
js
class DListNode {
constructor(key, val, expiredAt, prev, next) {
this.key = key ?? 0;
this.val = val ?? 0;
// 新增过期时间
this.expiredAt = expiredAt ?? -1;
this.prev = prev ?? null;
this.next = next ?? null;
}
// 新增判断是否过期的方法
isExpired() {
return this.expiredAt !== -1 && this.expiredAt < Date.now();
}
}
class LRUCache {
map = new Map();
head = new DListNode();
tail = new DListNode();
constructor(capacity) {
this.capacity = capacity;
this.head.next = this.tail;
this.tail.prev = this.head;
}
get(key) {
if (!this.map.has(key)) {
return -1;
}
const node = this.map.get(key);
// 新增判断是否过期
if (node.isExpired()) {
this.deleteNode(node);
this.map.delete(key);
return -1;
}
this.moveToHead(node);
return node.val;
}
put(key, val, expiredAt) {
if (this.map.has(key)) {
const node = this.map.get(key);
node.val = val;
// 更新过期时间
node.expiredAt = expiredAt ?? -1;
this.moveToHead(node);
return;
}
// 新增清理过期节点
if (this.map.size === this.capacity) {
this.clearExpiredNodes();
}
if (this.map.size === this.capacity) {
const node = this.tail.prev;
this.deleteNode(node);
this.map.delete(node.key);
}
// 传入过期时间
const node = new DListNode(key, val, expiredAt);
this.insertHead(node);
this.map.set(key, node);
}
moveToHead(node) {
this.deleteNode(node);
this.insertHead(node);
}
deleteNode(node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
insertHead(node) {
node.next = this.head.next;
this.head.next.prev = node;
this.head.next = node;
node.prev = this.head;
}
clearExpiredNodes() {
let curr = this.tail.prev;
while (curr !== this.head) {
if (curr.isExpired()) {
this.deleteNode(curr);
this.map.delete(curr.key);
}
curr = curr.prev;
}
}
}