LRU缓存

map实现

为什么用map而不用{...}

  • map不仅能存储, 还有顺序
  • {...}只能存储, 没有顺序
js 复制代码
class LRU {
  private maxLength = 1;
  private hash = new Map();

  constructor(length = 1) {
    if (length < 1) throw new Error("length 不能小于1");
    this.maxLength = length;
  }

  set(key: any, value: any) {
    if (this.hash.has(key)) {
      this.hash.delete(key);
    }

    this.hash.set(key, value);

    if (this.hash.size > this.maxLength) {
      const oldestKey = this.hash.keys().next().value;
      this.hash.delete(oldestKey);
    }
  }

  get(key: any) {
    const v = this.hash.get(key);

    this.hash.delete(key);
    this.hash.set(key, v);

    return v;
  }
}

测试: set更新排序

js 复制代码
const lru = new LRU(2);
lru.set(1, 100);
lru.set(2, 200);
lru.set(1, 101);
lru.set(3, 300);
console.log(lru.get(1)); // 101
console.log(lru.get(2)); // undefined
console.log(lru.get(3)); // 300

测试: get更新排序

js 复制代码
const lru = new LRU(2);
lru.set(1, 100);
lru.set(2, 200);
lru.get(1);
lru.set(3, 300);
console.log(lru.get(1)); // 100
console.log(lru.get(2)); // undefined
console.log(lru.get(3)); // 300

双向链表

  • 用双向链表仿了一个MyMap
  • 如何仿一个map
    • 既能快速查询hash[key]
    • 又能有顺序
js 复制代码
// 下面是MyMap的数据结构
// 既能快速查询, 又有顺序
const hash = {
    key1: item1 
            🔽   // item1.next = item2
    key2: item2
            🔽   // item2.next = item3
    key3: item3
            🔽   // item3.next = item4
    key4: item4
            🔽   // item4.next = item5
    key5: item5
}

代码实现

js 复制代码
class LRU {
  private maxLength = 1;
  private hash = new MyMap();

  constructor(length = 1) {
    if (length < 1) throw new Error("length 不能小于1");
    this.maxLength = length;
  }

  set(key: any, value: any) {
    if (this.hash.has(key)) {
      this.hash.delete(key);
    }

    this.hash.set(key, value);

    if (this.hash.size > this.maxLength) {
      const oldestKey = this.hash.head?.key;
      this.hash.delete(oldestKey);
    }
  }

  get(key: any) {
    const v = this.hash.get(key);

    this.hash.delete(key);
    this.hash.set(key, v);

    return v;
  }
}

class ListNode {
  key: string;
  value: any;
  next: ListNode | null = null;
  prev: ListNode | null = null;

  constructor(key: string, value: any) {
    this.key = key;
    this.value = value;
  }
}

class MyMap {
  data: { [key: string]: ListNode } = {};
  size: number = 0;
  head: ListNode | null = null;
  tail: ListNode | null = null;

  has(key: string) {
    return this.data[key] ? true : false;
  }

  // 移动到末尾, 末尾是最新鲜的
  move2Tail(node: ListNode) {
    if (this.tail === node) return; // 已经是最新鲜的了
    node = this.cut(node);
    const prevNode = this.tail;
    if (prevNode) prevNode.next = node;
    node.prev = prevNode;
    this.tail = node;
  }

  add(node: ListNode) {
    this.move2Tail(node);
    this.data[node.key] = node;
    this.size++;
    if (this.size === 1) this.head = node; // 添加的第一个
  }

  delete(key?: string) {
    if (!key) return;
    const node = this.data[key];
    if (node) this.cut(node);
    delete this.data[key];
    this.size--;
  }

  get(key: string) {
    const target = this.data[key];

    if (!target) return;
    // 末尾的是最新鲜的
    if (target !== this.tail) {
      this.move2Tail(target);
    }

    return target.value;
  }

  set(key: string, value: any) {
    const target = this.data[key];

    if (!target) {
      const newNode = new ListNode(key, value);
      this.add(newNode);
    } else {
      target.value = value;
      this.move2Tail(target);
    }
  }

  cut(node: ListNode) {
    const preNode = node.prev;
    const nextNode = node.next;

    if (this.head === node) {
      this.head = node.next;
    }
    if (this.tail === node) {
      this.tail = node.prev;
    }

    if (preNode) preNode.next = nextNode;
    if (nextNode) nextNode.prev = preNode;

    node.prev = null;
    node.next = null;
    return node;
  }
}
相关推荐
dly_blog1 小时前
Vue 响应式陷阱与解决方案(第19节)
前端·javascript·vue.js
消失的旧时光-19431 小时前
401 自动刷新 Token 的完整架构设计(Dio 实战版)
开发语言·前端·javascript
console.log('npc')1 小时前
Table,vue3在父组件调用子组件columns列的方法展示弹窗文件预览效果
前端·javascript·vue.js
用户47949283569151 小时前
React Hooks 的“天条”:为啥绝对不能写在 if 语句里?
前端·react.js
我命由我123452 小时前
SVG - SVG 引入(SVG 概述、SVG 基本使用、SVG 使用 CSS、SVG 使用 JavaScript、SVG 实例实操)
开发语言·前端·javascript·css·学习·ecmascript·学习方法
用户47949283569152 小时前
给客户做私有化部署,我是如何优雅搞定 NPM 依赖管理的?
前端·后端·程序员
C_心欲无痕2 小时前
vue3 - markRaw标记为非响应式对象
前端·javascript·vue.js
qingyun9893 小时前
深度优先遍历:JavaScript递归查找树形数据结构中的节点标签
前端·javascript·数据结构
熬夜敲代码的小N3 小时前
Vue (Official)重磅更新!Vue Language Tools 3.2功能一览!
前端·javascript·vue.js
90后的晨仔3 小时前
用 Python 脚本一键重命名序列帧图片的名称
前端