LFU 缓存算法-----链表

Least Ffequently User

最少使用缓存的 算法

思路 O(1):

  1. 利用双向链表数据结果实现新增删除
  2. 利用map来读取存储数值及频率的次数
  3. 首先明确,我们要对外暴露两个方法,get 和 set
    1. 因为get和set的调用要更新次数以及缓存数据的存储,所以要实现一个私有方法 _update
  4. get 函数比较简单,如果存储的数据中有值的话,直接读取,并且更新使用的次数频率,否则返回 -1;
  5. set 函数 分两种情况,如果存储的数据中有值的话,更新值,并且更新使用的次数频率。 如果没有值, 又要分两种情况,当剩余的大小还有的话,把数据set 到 存储的数据和存储的频率中,并且同时更新剩余的空间大小和最小次数的设置;
    如果没有剩余空间可用,就要从频率的数据结构中读取最小次数的数据,并且在值和频率的map中删掉它,剩余空间大小要++
  6. _update 把旧节点删掉,并且插入新频率对应的表里

双向链表

  1. 头节点的后一个节点为尾节点
  2. 尾节点的前一个节点为头节点
  3. 链表删除: 将当前节点的前一个节点的 post 指针指向当前节点的 post 指针
    将当前节点的后一个节点的 pre 指针指向当前节点的 pre 指针
  4. 链表新增:
    1. 将 该节点的后一个节点 设置为 头节点的后一个节点(即尾节点)
    2. 将 尾节点的前一个节点 设置为 该节点
    3. 将头节点的后一个节点设置为该节点
    4. 将该节点的前一个节点设置为头节点
class Node {
    constructor (key, value) {
        this.value = value;
        this.key = key;
        this.frequence = 1;
        this.next = null;
        this.pre = null;
    }
}

class DoubleNodeList {
    constructor () {
        this.head = new Node();
        this.tail = new Node();
        this.head.next = this.tail;   //next节点指向尾节点
        this.tail.pre = this.head;    //前节点指向头结点
    }

    deleteNode (node) {
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }

    addNode (node) {
        node.pre = this.head;
        node.next = this.head.next;
        this.head.next = node;
        this.head.next.pre = node;
    }
}




/**
 * @param {number} capacity
 */
var LFUCache = function(capacity) {
    this.countCapacity = capacity;
    this.useCapacity = 0;
    this.minFrequence = 1;
    this.valueMap = new Map();
    this.frequenceMap = new Map();
};

/** 
 * @param {number} key
 * @return {number}
 */
LFUCache.prototype.get = function(key) {
    if (!this.valueMap.has(key)) {
        return -1;
    }
    let node = this.valueMap.get(key);
    this.update(node);
    return node.value;
};

/** 
 * @param {number} key 
 * @param {number} value
 * @return {void}
 */
LFUCache.prototype.put = function(key, value) {
    if (this.countCapacity === 0) {
        return;
    }
   
    let node = this.valueMap.get(key);
    if (node) {
        node.value = value;
        this.update(node);
    } else {
        if (this.useCapacity === this.countCapacity) {
            let minfrequenceNode = this.frequenceMap.get(this.minFrequence);
            minfrequenceNode.deleteNode(minfrequenceNode.tail.pre);
            this.valueMap.delete(minfrequenceNode.tail.pre.key);
            this.useCapacity--;
        }
        let newNode = new Node(key, value);
        this.valueMap.set(key, newNode);
        let nodeList = this.frequenceMap.get(1);
        if (!nodeList) {
            nodeList = new DoubleNodeList();
            this.frequenceMap.set(1, nodeList);
        }
        nodeList.addNode(newNode)
        this.minFrequence = 1;
        this.useCapacity++;
    }
    
};


LFUCache.prototype.update = function (node) {
    let frequence = node.frequence;

    let frequenceNode = this.frequenceMap.get(frequence);
    frequenceNode.deleteNode(node);

    if (frequence === this.minFrequence && frequenceNode.head.next === frequenceNode.tail) {
        this.minFrequence = frequence + 1;
    }

    node.frequence++;

    let newNode = this.frequenceMap.get(node.frequence);
    if (!newNode) {
        newNode = new DoubleNodeList();
        this.frequenceMap.set(node.frequence, newNode);
    }
    this.minFrequence = 1;
    debugger;
    newNode.addNode(node);
}

/**
 * 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)
 */

var lFUCache = new LFUCache(2);
lFUCache.put(1, 1);
lFUCache.put(2, 2);
lFUCache.get(1);      // 返回 1
lFUCache.put(3, 3);   // 去除键 2
lFUCache.get(2);      // 返回 -1(未找到)
lFUCache.get(3);      // 返回 3
lFUCache.put(4, 4);   // 去除键 1
lFUCache.get(1);      // 返回 -1(未找到)
lFUCache.get(3);      // 返回 3
lFUCache.get(4);      // 返回 4
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页