返回

JavaScript双向链表实现LFU缓存算法

闲谈

1. 简介

缓存是一个临时存储数据的区域,它可以提高数据访问的效率。LFU(Least Frequently Used)缓存算法是一种常用的缓存淘汰算法,它会优先淘汰最不经常使用的缓存项。

2. 双向链表实现

双向链表是一种特殊的链表,它允许从两个方向访问元素。在LFU缓存算法中,我们可以使用双向链表来存储缓存项。每个缓存项都有一个指向下一个缓存项的指针和一个指向前一个缓存项的指针。

3. 算法实现

LFU缓存算法的实现主要涉及以下几个步骤:

  1. 初始化一个双向链表,并设置头节点和尾节点。
  2. 当需要缓存一个新项时,首先检查该项是否已经在链表中。如果已经存在,则将该项移到链表的头部。如果不存在,则将该项添加到链表的头部。
  3. 当需要淘汰一个缓存项时,从链表的尾部删除该项。
  4. 当需要获取一个缓存项时,从链表的头部开始搜索。如果找到该项,则将该项移到链表的头部。如果未找到该项,则返回null。

4. 代码示例

class LFUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.head = new Node();
    this.tail = new Node();
    this.head.next = this.tail;
    this.tail.prev = this.head;
    this.freqMap = new Map();
  }

  get(key) {
    const node = this.freqMap.get(key);
    if (!node) {
      return null;
    }
    this.moveToHead(node);
    return node.value;
  }

  put(key, value) {
    if (this.capacity <= 0) {
      return;
    }
    const node = this.freqMap.get(key);
    if (node) {
      node.value = value;
      this.moveToHead(node);
      return;
    }
    if (this.freqMap.size === this.capacity) {
      this.removeTail();
    }
    const newNode = new Node(key, value);
    this.freqMap.set(key, newNode);
    this.addToHead(newNode);
  }

  moveToHead(node) {
    this.removeNode(node);
    this.addToHead(node);
  }

  addToHead(node) {
    const nextNode = this.head.next;
    this.head.next = node;
    node.prev = this.head;
    node.next = nextNode;
    nextNode.prev = node;
  }

  removeNode(node) {
    const prevNode = node.prev;
    const nextNode = node.next;
    prevNode.next = nextNode;
    nextNode.prev = prevNode;
    node.prev = null;
    node.next = null;
  }

  removeTail() {
    const tailNode = this.tail.prev;
    this.removeNode(tailNode);
    this.freqMap.delete(tailNode.key);
  }
}

class Node {
  constructor(key, value) {
    this.key = key;
    this.value = value;
    this.prev = null;
    this.next = null;
  }
}

5. 结语

LFU缓存算法是一种常用的缓存淘汰算法,它可以有效地提高缓存的命中率和性能。通过使用双向链表来实现LFU缓存算法,我们可以快速有效地追踪和淘汰最不经常使用的缓存项。

6. 相关链接