leetcode/notes/src/lru_cache.md

2.9 KiB
Raw Blame History

LRU

Leetcode 146. LRU Cache

Header:

#ifndef S0146_LRU_CACHE_HPP
#define S0146_LRU_CACHE_HPP

#include <cstdlib>
#include <unordered_map>

class LRUCache {
 public:
  /**
   * @brief Least Recently Used Cache
   *
   * 这是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰
   *
   * @param capacity 容量,这是一个正整数
   */
  LRUCache(int capacity);
  /**
   * @brief 读取数据
   *
   * @param key 数据对应的键值
   * @return 数据的值
   */
  int get(int key);
  /**
   * @brief 放入对应的数据
   *
   * @param key 数据对应的键值
   * @param value 数据对应的值
   */
  void put(int key, int value);

 private:
  struct CacheNode {
    int key;
    int value;
    CacheNode *next;
    CacheNode *prev;
    CacheNode(int key, int value)
        : key(key), value(value), next(nullptr), prev(nullptr){};
    CacheNode(int key, int value, CacheNode *next, CacheNode *prev)
        : key(key), value(value), next(next), prev(prev){};
  };
  CacheNode *head;
  CacheNode *tail;
  int capacity;
  std::unordered_map<int, CacheNode *> map;  // 键值是 key值是该节点的指针
  void moveToHead(CacheNode *node);          // 将节点移动到头部
};

#endif

Source:

#include "s0146_lru_cache.hpp"

void LRUCache::moveToHead(CacheNode *node) {
  // 如果是头部节点
  if (node == head) return;
  // 如果不是头部节点,但是是尾部节点
  if (node == tail) tail = node->prev;
  // 处理该节点的前后两个节点的指针
  if (node->prev) node->prev->next = node->next;
  if (node->next) node->next->prev = node->prev;
  // 将该节点移动到头部
  node->prev = nullptr;
  node->next = head;
  // 处理头部节点
  head->prev = node;
  head = node;
}

LRUCache::LRUCache(int capacity) {
  this->capacity = capacity;
  head = nullptr;
  tail = nullptr;
  map = std::unordered_map<int, CacheNode *>();
}

int LRUCache::get(int key) {
  if (map.size() == 0) return -1;
  if (map.count(key) == 0) return -1;
  moveToHead(map[key]);
  return map[key]->value;
}

void LRUCache::put(int key, int value) {
  // 如果 key 已存在,则更新 value ,并将这个节点移动到头部
  if (map.count(key) == 1) {
    map[key]->value = value;
    moveToHead(map[key]);
    return;
  }
  // 否则创建该节点
  CacheNode *newNode = (CacheNode *)malloc(sizeof(CacheNode));
  newNode->value = value;
  newNode->key = key;
  newNode->next = head;
  newNode->prev = nullptr;
  // 处理头部节点
  if (head) head->prev = newNode;
  head = newNode;
  // 处理尾部节点
  if (map.size() == 0) tail = newNode;
  // 更新哈希表
  map[key] = newNode;
  // 如果容量已满
  if (map.size() > capacity) {
    // 更新尾部节点
    CacheNode *node = tail;
    if (tail->prev) {
      tail->prev->next = nullptr;
      tail = tail->prev;
    }
    // 移除该节点
    map.erase(node->key);
    free(node);
  }
}