实用指南:Leetcode 146. LRU 缓存 哈希表 + 双向链表

原题链接:Leetcode 146. LRU 缓存

在这里插入图片描述
在这里插入图片描述

LRU(Least Recently Used,最近最少使用)缓存是一种内存数据管理策略,核心思想是:当缓存空间满时,优先淘汰 “最近一段时间内最少被访问” 的素材,为新素材腾出空间。它的设计目标是利用 “局部性原理”(程序或用户访问数据时,往往会在短时间内重复访问同一批数据),尽可能保留高频访问的信息,从而减少对底层存储(如数据库、硬盘)的依赖,提升数据读取效率。

LRU 的行为围绕 “访问” 和 “淘汰” 两个关键场景展开:

  • 数据访问时(读 / 写):
    • 若数据已在缓存中(“命中”),则将其标记为 “最近启用过”(更新它的访问优先级,避免被优先淘汰);
    • 若素材不在缓存中(“未命中”),则将其存入缓存;若缓存已满,先淘汰 “最久未访问” 的数据,再存入新数据。
  • 缓存满时淘汰:
    严格选择 “最近一段时间内没有被访问过” 或 “访问频率最低” 的数据进行删除。

LRU 的高效实现需要满足两个核心需求:

  • 快速查找数据(判断是否在缓存中)
  • 快速更新 / 删除数据(调整访问优先级、淘汰旧数据)
  • 经典实现采用 “哈希表 + 双向链表” 的组合

代码参考官解:LRU缓存机制

// 设计一个双向链表结构体
struct Node{
int key,value;
Node* prev;
Node* next;
Node():key(0),value(0),prev(nullptr),next(nullptr) {};
Node(int k,int v):key(k),value(v),prev(nullptr),next(nullptr) {};
};
class LRUCache {
private:
int size;
int capacity;
Node* head;
Node* tail;
unordered_map<int,Node*> cache;
  public:
  LRUCache(int _capacity): capacity(_capacity),size(0) {
  head = new Node();
  tail = new Node();
  head->next = tail;
  tail->prev = head;
  }
  int get(int key) {
  // 如果在当前缓存内没有找到
  if(!cache.count(key)){
  return -1;
  }
  // 如果找到
  Node* node = cache[key];
  move_to_head(node);
  return node->value;
  }
  void put(int key, int value) {
  // 如果在当前缓存内没有找到
  if(!cache.count(key)){
  // 如果 key 不存在,创建一个新的节点
  Node* node = new Node(key,value);
  // 添加进哈希表
  cache[key]=node;
  size++;
  // 添加至双向链表的头部
  add_to_head(node);
  if(size>capacity){
  // 如果超出容量,删除双向链表的尾部节点
  Node* drop_node = remove_tail();
  // 删除哈希表中对应的项
  cache.erase(drop_node->key);
  // 防止内存泄漏
  delete drop_node;
  size--;
  }
  }
  //如果当前缓存中有
  else{
  // 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
  Node* node = cache[key];
  node->value = value;
  move_to_head(node);
  }
  }
  void add_to_head(Node* node){
  node->prev = head;
  node->next = head->next;
  head->next->prev = node;
  head->next = node;
  }
  void remove_node(Node* node){
  node->prev->next = node->next;
  node->next->prev = node->prev;
  }
  void move_to_head(Node* node){
  remove_node(node);
  add_to_head(node);
  }
  Node* remove_tail(){
  Node* node = tail->prev;
  remove_node(node);
  return node;
  }
  };
  /**
  * Your LRUCache object will be instantiated and called as such:
  * LRUCache* obj = new LRUCache(capacity);
  * int param_1 = obj->get(key);
  * obj->put(key,value);
  */
posted @ 2025-10-23 16:30  ycfenxi  阅读(0)  评论(0)    收藏  举报