数据结构 之 【LRU Cache】(注意list的splice接口函数)

目录

[1.什么是LRU Cache](#1.什么是LRU Cache)

[2.LRU Cache的简单实现](#2.LRU Cache的简单实现)

成员变量

构造函数

查询数据(get(key))

[插入/更新数据(put(key, value))](#插入/更新数据(put(key, value)))


1.什么是LRU Cache

  • LRU 是Least Recently Used的缩写,意思是最近最少使用,它是一种Cache替换算法。
  • 什么是 Cache?狭义的Cache指的是位于CPU和主存间的快速RAM , 通常它不像系统主存那样使用 DRAM技术,而使用昂贵但较快速的SRAM技术。 广义上的Cache指的是位于速度相差较大的两种 硬件之间, 用于协调两者数据传输速度差异的结构
  • 除了CPU与主存之间有Cache, 内存与硬盘 之间也有Cache,乃至在硬盘与网络之间也有某种意义上的Cache── 称为Internet临时文件夹或 网络内容缓存等
  • Cache的容量有限 ,因此当Cache的容量用完后,而又有新的内容需要添加进来时, 就需要挑选 并舍弃原有的部分内容,从而腾出空间来放新内容。LRU Cache 的替换原则就是将最近最少使用 的内容替换掉。其实,LRU译成最久未使用会更形象, 因为该算法每次替换掉的就是一段时间内 最久没有使用过的内容。

2.LRU Cache的简单实现

以讲解这题为切口进行实现

yjy146. LRU 缓存 - 力扣(LeetCode)

成员变量

复制代码
    //表头元素表示最近最多使用,尾元素表示最近最少使用
    //链表插入删除O(1),更新LRU效率O(N),先找到,再转移
    list<pair<int, int>> _LRUlist;
    typedef list<pair<int, int>>::iterator _Listiterator;
    unordered_map<int, _Listiterator> _hashMap;//查找更新O(1),LRU不可实现
    int _capacity;

(1) _capacity表示缓存的容量

(2)

  • 只用unordered_map,查找更新效率为O(1),但是无法记录数据的频率,如果使用引用计数,又需要查找,效率低,难以实现LRU
  • 让链表尾元素表示最近最少使用的数据就可以实现LRU,但是,查找更新的效率为O(N)
  • 所以,_LRUlist存储数据,
    _hashMap实现关键字 与链表中关键字对应数据的迭代器一一映射

构造函数

复制代码
    LRUCache(int capacity) {
        _capacity = capacity;
    }

初始化成员变量_capacity 即可

查询数据(get(key)

复制代码
    int get(int key) {
        auto it = _hashMap.find(key);
        //找不到就返回-1
        if(it == _hashMap.end()) return -1;
        //找到了,返回之前,更新元素位置
        _LRUlist.splice(_LRUlist.begin(), _LRUlist, it->second);

        return it->second->second;
    }

_hashMap根据关键字key以O(1)的时间效率进行查找,

找不到返回-1,找到了就将数据更新到表头,再返回value值

  • 在 C++ 中,std::list::splice()std::list 的一个高效成员函数 ,用于在常数时间 O(1)移动链表中的元素或整个链表,无需拷贝或析构元素。它通过重新链接链表节点实现
  1. 移动单个节点

    |-------------------------------------------------------------|
    | void splice(iterator position, list& other, iterator it); |

    • 作用 :将 other 链表中的节点 it 移动到当前链表的 position 位置。
    • 要求it 必须是 other 的有效迭代器,position 可以属于 other,但是ji被移动的节点(或范围)不能包含 position 本身(即不能自引用)
  2. 移动整个链表

    |------------------------------------------------|
    | void splice(iterator position, list& other); |

    • 作用 :将 other 链表的所有元素移动到当前链表的 position 位置。
    • 结果other 变为空链表。
  3. 移动一个范围内的节点

    |-------------------------------------------------------------------------------|
    | void splice(iterator position, list& other, iterator first, iterator last); |

    • 作用 :将 other 链表中 [first, last) 范围内的节点移动到当前链表的 position 位置。
    • 注意[first, last) 必须是 other 的有效范围,且不能包含 position 的迭代器(避免自引用)。

插入/更新数据(put(key, value)

复制代码
void put(int key, int value)
 {
    auto ret = _hashMap.find(key);
    //找不到,表头插入,注意删除数据
    if (ret == _hashMap.end())
    {
        //删除数据

        //头插

    }
    else//找到了就更新
    {

    }
}

(1)插入、更新数据得先查找

(2)找不到就需要插入数据,但是缓存容量有限,得先考虑删除数据

复制代码
if (_hashMap.size() == _capacity)
{
    //链表尾节点元素
    pair<int, int> back = _LRUlist.back();
    _hashMap.erase(back.first);
    _LRUlist.pop_back();
}
  • 将链表尾元素视为最近最少使用的元素,所以删除尾元素

  • 然后头插最新数据

    复制代码
              _LRUlist.push_front(make_pair(key, value));
              _hashMap[key] = _LRUlist.begin();

(2)找到了就更新value值,同时将数据转移到表头

复制代码
            ret->second->second = value;
            _LRUlist.splice(_LRUlist.begin(), _LRUlist, ret->second);

ret->second表示链表中节点的迭代器

相关推荐
【正弦】2 小时前
list的模拟实现
数据结构·list
努力写代码的熊大10 小时前
List迭代器和模拟(迭代器的模拟)
数据结构·windows·list
长路归期无望12 小时前
C语言小白实现多功能计算器的艰难历程
c语言·开发语言·数据结构·笔记·学习·算法
dragoooon3414 小时前
[优选算法专题三.二分查找——NO.24搜索旋转排序数组中的最⼩值]
数据结构·leetcode·动态规划
Haooog14 小时前
654.最大二叉树(二叉树算法)
java·数据结构·算法·leetcode·二叉树
那我掉的头发算什么16 小时前
【数据结构】双向链表
java·开发语言·数据结构·链表·intellij-idea·idea
半桔16 小时前
【STL源码剖析】从源码看 list:从迭代器到算法
java·数据结构·c++·算法·stl·list
拾光Ծ16 小时前
【C++】STL之list模拟实现:关于链表容器的双向迭代器你知道多少?
开发语言·数据结构·c++·list·visual studio
轩源源16 小时前
双向链表,这也太简单了吧!(C语言实现)
c语言·数据结构·算法·链表·青少年编程