@jyeontu/structure-jyeontu
Version:
javascript实现各种数据结构:堆、优先队列、字典树、LFU缓存……
139 lines (136 loc) • 3.8 kB
JavaScript
const LFUNode = function (
key = "",
val = "",
freq = 0,
pre = null,
next = null
) {
this.key = key;
this.val = val;
this.freq = freq;
this.pre = pre;
this.next = next;
};
class LFULinkLine{
constructor(node){
this.init(node);
}
init(node){
let head = new LFUNode("head");
let tail = new LFUNode("tail");
head.next = node;
tail.pre = node;
node.pre = head;
node.next = tail;
this.head = head;
this.tail = tail;
}
addNode(node){
this.head.next.pre = node;
node.pre = this.head;
node.next = this.head.next;
this.head.next = node;
}
removeNode(node){
node.pre.next = node.next;
node.next.pre = node.pre;
}
}
/**
* @param {number} capacity
*/
class LFUCache{
constructor(capacity = 100){
this.init(capacity);
}
init(capacity){
this.capacity = capacity;
this.num = 0;
this.minFreq = 0;
this.kvMap = new Map();
this.freqMap = new Map();
}
/**
* @param {number} key
* @return {number}
*/
get(key){
if (this.capacity === 0) return -1;
if (!this.kvMap.has(key)) return -1;
let node = this.kvMap.get(key);
let linkLine = this.freqMap.get(node.freq);
linkLine.removeNode(node);
//清空了
if (linkLine.head.next === linkLine.tail) {
this.freqMap.delete(node.freq);
if (this.minFreq == node.freq) this.minFreq++;
}
node.freq++;
if (this.freqMap.has(node.freq)) {
linkLine = this.freqMap.get(node.freq);
linkLine.addNode(node);
} else {
this.freqMap.set(node.freq, new LFULinkLine(node));
}
return node.val;
}
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
put (key, value) {
if (this.capacity === 0) return;
if (this.kvMap.has(key)) {
//更新
let node = this.kvMap.get(key);
node.val = value;
let linkLine = this.freqMap.get(node.freq);
linkLine.removeNode(node);
if (linkLine.head.next === linkLine.tail) {
if (this.minFreq == node.freq) this.minFreq++;
this.freqMap.delete(node.freq);
}
node.freq++;
if (this.freqMap.has(node.freq)) {
linkLine = this.freqMap.get(node.freq);
linkLine.addNode(node);
} else {
linkLine = new LFULinkLine(node);
this.freqMap.set(node.freq, linkLine);
}
} else {
//存入
if (this.capacity == this.num) {
//存满
let freq = this.minFreq;
let linkLine = this.freqMap.get(freq);
let node = linkLine.tail.pre;
linkLine.removeNode(node);
this.kvMap.delete(node.key);
if (linkLine.head.next === linkLine.tail) {
this.freqMap.delete(node.freq);
}
} else {
this.num++;
}
let node = new LFUNode(key, value, 0);
this.kvMap.set(key, node);
if (this.freqMap.has(0)) {
let linkLine = this.freqMap.get(0);
linkLine.addNode(node);
} else {
let linkLine = new LFULinkLine(node);
this.freqMap.set(0, linkLine);
}
this.minFreq = 0;
}
};
};
/**
* Your LFUCache object will be instantiated and called as such:
* var obj = new LFUCache(capacity)
* var param_1 = obj.get(key)
* obj.put(key,value)
*/
exports.LFUCache = LFUCache;