用unordered_map和双向链表实现LRU缓存

本文介绍了如何使用unordered_map和双向链表实现LRU(最近最少使用)缓存机制,满足O(1)的时间复杂度要求。通过哈希表存储key与链表节点指针的映射,链表头部存放最近访问的数据。当缓存满时,删除链表尾部节点。文章详细阐述了get和set操作的逻辑,并提供了相关代码实现。
摘要由CSDN通过智能技术生成

LRU为最近最少使用算法,可以类比为手机app多任务管理来理解,每个app刚用完在会被放在最前面,当内存满时,最久没用的app内存会被释放,题目链接如下:
Leetcode 146-LRU缓存机制
题目要求:
put和get操作时间复杂度为O(1)

分析:

  • 首先,这些key-value的数据应该按时间顺序排列,链表是有序的;但链表查询时间为O(n),无法满足要求;
  • 哈希表查询时间为O(1),但是无序的。

因此可以用哈希表来存储key和链表节点指针的映射;
每次最新访问或存储的数据放在链表的头部,当cache容量满时删掉链表尾部的节点

  • 查询:哈希表存储key和链表节点指针的映射,可以以O(1)时间查到某个key对应的数据是否存在
  • 插入:在链表头部插入,时间为O(1)
  • 删除:对于链表来说,删除就是改变节点指针的关系并释放该节点内存,为了避免需要O(n)时间找到前节点,应使用双向链表;同时,删除最不常使用的节点时,也要删除cache哈希表中的value,这需要知道该节点的key,因此链表中不仅要存value,也要存key。

①双向链表实现代码如下:

typedef struct DListNode{
   
    int key;
    int val;
    DListNode* next;
    DListNode* pre;
    DListNode():key(0),val(0),next(nullptr),pre(nullptr){
   }
    DListNode(int _key,int _val):key(_key),val(_val),next(
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LRU 缓存是一种常见的缓存淘汰算法,它的设计思想是将最近最少使用的数据从缓存中淘汰出去,以保证缓存的数据都是热点数据,从而提高缓存的命中率。 下面是一个基于双向链表哈希表实现LRU 缓存C++ 设计实现: ```cpp #include <unordered_map> struct Node { int key; int value; Node* prev; Node* next; Node(int k, int v) : key(k), value(v), prev(nullptr), next(nullptr) {} }; class LRUCache { public: LRUCache(int capacity) : size_(capacity), head_(nullptr), tail_(nullptr) {} int get(int key) { auto iter = cache_.find(key); if (iter == cache_.end()) { return -1; } else { Node* node = iter->second; move_to_head(node); return node->value; } } void put(int key, int value) { auto iter = cache_.find(key); if (iter == cache_.end()) { Node* node = new Node(key, value); add_to_head(node); cache_[key] = node; if (cache_.size() > size_) { Node* tail = remove_tail(); cache_.erase(tail->key); delete tail; } } else { Node* node = iter->second; node->value = value; move_to_head(node); } } private: int size_; Node* head_; Node* tail_; std::unordered_map<int, Node*> cache_; void add_to_head(Node* node) { if (head_ == nullptr) { head_ = node; tail_ = node; } else { node->next = head_; head_->prev = node; head_ = node; } } void move_to_head(Node* node) { if (node == head_) { return; } else if (node == tail_) { tail_ = tail_->prev; tail_->next = nullptr; } else { node->prev->next = node->next; node->next->prev = node->prev; } node->next = head_; head_->prev = node; node->prev = nullptr; head_ = node; } Node* remove_tail() { Node* node = tail_; if (head_ == tail_) { head_ = nullptr; tail_ = nullptr; } else { tail_ = tail_->prev; tail_->next = nullptr; } return node; } }; ``` 在这个实现中,我们使用了一个双向链表保存缓存中的数据,并使用一个哈希表来提高查找效率。在 `get` 操作中,如果缓存中不存在目标数据则返回 -1,否则将目标数据移到链表头部并返回其值。在 `put` 操作中,如果缓存中不存在目标数据则创建一个新的节点并将其添加到链表头部,如果缓存已满则删除链表尾部的节点。如果缓存中已存在目标数据则将其值更新并将其移动到链表头部。 需要注意的是,在 `move_to_head` 和 `remove_tail` 操作中,我们需要判断目标节点是否已经在链表的头部或尾部,以避免对空指针进行操作。此外,在每次操作中,我们还需要更新哈希表中对应节点的指针。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值