1. class LRUCache {
  2. constructor(capacity) {
  3. this.capacity = capacity // 缓存的容量
  4. this.hash = {} // 哈希表
  5. this.count = 0 // 缓存数目
  6. this.dummyHead = new ListNode() // 虚拟头结点
  7. this.dummyTail = new ListNode() // 虚拟尾节点
  8. this.dummyHead.next = this.dummyTail
  9. this.dummyTail.prev = this.dummyHead // 相联系
  10. }
  11. }
  12. 设计 dummyHead dummyTail 的意义
  13. 虚拟头尾节点,不存数据,只是为了让真实头尾节点的操作,和其他节点一致,方便快速访问头尾节点。
  14. 初始还没有添加真实节点,要将虚拟头尾节点联结在一起。
  15. get(key) {
  16. let node = this.hash[key] // 从哈希表中,获取对应的节点
  17. if (node == null) return -1 // 如果节点不存在,返回-1
  18. this.moveToHead(node) // 被读取了,该节点移动到链表头部
  19. return node.value // 返回出节点值
  20. }
  21. moveToHead(node) {
  22. this.removeFromList(node) // 从链表中删除节点
  23. this.addToHead(node) // 添加到链表的头部
  24. }
  25. removeFromList(node) {
  26. let temp1 = node.prev // 暂存它的后继节点
  27. let temp2 = node.next // 暂存它的前驱节点
  28. temp1.next = temp2 // 前驱节点的next指向后继节点
  29. temp2.prev = temp1 // 后继节点的prev指向前驱节点
  30. }
  31. addToHead(node) { // 插入到虚拟头结点和真实头结点之间
  32. node.prev = this.dummyHead // node的prev指针,指向虚拟头结点
  33. node.next = this.dummyHead.next // node的next指针,指向原来的真实头结点
  34. this.dummyHead.next.prev = node // 原来的真实头结点的prev,指向node
  35. this.dummyHead.next = node // 虚拟头结点的next,指向node
  36. }
  37. put(key, value) {
  38. let node = this.hash[key] // 获取链表中的node
  39. if (node == null) { // 不存在于链表,是新数据
  40. if (this.count == this.capacity) { // 容量已满
  41. this.removeLRUItem() // 删除最远一次使用的数据
  42. }
  43. let newNode = new ListNode(key, value) // 创建新的节点
  44. this.hash[key] = newNode // 存入哈希表
  45. this.addToHead(newNode) // 将节点添加到链表头部
  46. this.count++ // 缓存数目+1
  47. } else { // 已经存在于链表,老数据
  48. node.value = value // 更新value
  49. this.moveToHead(node) // 将节点移到链表头部
  50. }
  51. }
  52. removeLRUItem() { // 删除“老家伙”
  53. let tail = this.popTail() // 将它从链表尾部删除
  54. delete this.hash[tail.key] // 哈希表中也将它删除
  55. this.count-- // 缓存数目-1
  56. }
  57. popTail() { // 删除链表尾节点
  58. let tail = this.dummyTail.prev // 通过虚拟尾节点找到它
  59. this.removeFromList(tail) // 删除该真实尾节点
  60. return tail // 返回被删除的节点
  61. }
class ListNode {
  constructor(key, value) {
    this.key = key
    this.value = value
    this.next = null
    this.prev = null
  }
}

class LRUCache {
  constructor(capacity) {
    this.capacity = capacity
    this.hash = {}
    this.count = 0
    this.dummyHead = new ListNode()
    this.dummyTail = new ListNode()
    this.dummyHead.next = this.dummyTail
    this.dummyTail.prev = this.dummyHead
  }

  get(key) {
    let node = this.hash[key]
    if (node == null) return -1
    this.moveToHead(node)
    return node.value
  }

  put(key, value) {
    let node = this.hash[key]
    if (node == null) {
      if (this.count == this.capacity) {
        this.removeLRUItem()
      }
      let newNode = new ListNode(key, value)
      this.hash[key] = newNode
      this.addToHead(newNode)
      this.count++
    } else {
      node.value = value
      this.moveToHead(node)
    }
  }

  moveToHead(node) {
    this.removeFromList(node)
    this.addToHead(node)
  }

  removeFromList(node) {
    let temp1 = node.prev
    let temp2 = node.next
    temp1.next = temp2
    temp2.prev = temp1
  }

  addToHead(node) {
    node.prev = this.dummyHead
    node.next = this.dummyHead.next
    this.dummyHead.next.prev = node
    this.dummyHead.next = node
  }

  removeLRUItem() {
    let tail = this.popTail()
    delete this.hash[tail.key]
    this.count--
  }

  popTail() {
    let tail = this.dummyTail.prev
    this.removeFromList(tail)
    return tail
  }
}

Map

/**
 * @param {number} capacity
 */
var LRUCache = function(capacity) {
    this.map = new Map();
    this.capacity = capacity;
};

/** 
 * @param {number} key
 * @return {number}
 */
LRUCache.prototype.get = function(key) {
    if(this.map.has(key)){
        let value = this.map.get(key);
        this.map.delete(key); // 删除后,再 set ,相当于更新到 map 最后一位
        this.map.set(key, value);
        return value
    } else {
        return -1
    }
};

/** 
 * @param {number} key 
 * @param {number} value
 * @return {void}
 */
LRUCache.prototype.put = function(key, value) {
    // 如果已有,那就要更新,即要先删了再进行后面的 set
    if(this.map.has(key)){
        this.map.delete(key);
    }
    this.map.set(key, value);
    // put 后判断是否超载
    if(this.map.size > this.capacity){
        this.map.delete(this.map.keys().next().value);
    }

};

/**
 * Your LRUCache object will be instantiated and called as such:
 * var obj = new LRUCache(capacity)
 * var param_1 = obj.get(key)
 * obj.put(key,value)
 */