IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【LeetCode】【哈希表+双向链表】LRU 缓存 思路解析和代码 -> 正文阅读

[数据结构与算法]【LeetCode】【哈希表+双向链表】LRU 缓存 思路解析和代码

LRU 缓存

题目链接

个人思路

采用C++的容器,没有手撕双向链表

题意

实现LRU的初始化,读取,写入,分别对应LRUCache()、get()、put()
在这里插入图片描述

用到的理论和技术

  1. 双向链表list的插入、删除、访问、迭代器、auto关键字
  2. map,插入、删除、访问
  3. 类的初始化
  4. LRU机制

思路

LRU(Least Recently Used),最近最少使用算法,是页面置换算法的一种
也叫最近最久未使用算法
LRUCache():初始化内存的大小
get():获取内存中的数据,若不存在返回-1
put():向内存写入数据。

  1. 若数据存在,则更新并访问当前数据,表示当前使用过当前数据;
  2. 如果不存在
    • 内存没有超限,则写入当前数据,表示当前使用过当前数据。
    • 内存超限,删去最近最久未使用的数据,写入当前数据,表示当前使用过当前数据。

数据结构:
下文规定,哈希表map统称键值;输入数据统称key,val

  1. pair<int,int>:输入数据是key,val的形式,数据形式:key,val
  2. 双向链表List<pair<int, int> >,双向链表
  3. map<int, pair<int, int>::iterator>,mp[key]:map的键 == 数据的key,map的值 == 数据 key,val在双向链表中的迭代器

Q1:为什么要用链表
A:由于算法考虑到访问的顺序,因此需要使用链表
Q2:为什么要用双向量表
A:链表头部表示最近使用过,链表尾部表示最近未使用过,因此涉及到头部的插入和尾部的插入与删除
Q3:为什么要用map
A:要保证常规时间内插入删除
Q4:为什么map的值是key-val对所在双向链表中的迭代器
A:便于list.erase(iter),在任意位置删除
Q5:既然哈希表中已经存了 数据的key,为什么链表中还要存数据key-val对呢,只存val不行么?
A:当内存满了,双向链表末尾数据被删除,对应的哈希表中的旧数据也要删除,然而哈希表的删除是根据哈希表的值进行的,链表中只存数据的val,是无法找到对应数据的key

注意

  • list的函数,begin()和end()表示的不是元素,而是迭代器
  • 元素是通过front()和back()访问的
  • end()表示的不是容器最后一个元素的迭代器,而是容器末端下一位置
  • auto访问map时,这里的auto推导出来的类型并不是迭代器类型,而是键值对(pair)类型
    //因此get()不能写成
    //key存在,返回key的val,并把键值对提到链表头部
    auto key_value = *hash[key];//这里的auto推导出来的类型并不是迭代器类型,而是键值对(pair)类型,不能省略
    cache.erase(hash[key]); //cache删除旧数据
    cache.push_front(*hash[key]); //cache把键值对提到链表头部,此处不能用*hash[key]替换auto,此时catche需要的是pair,auto类型转换结果是pair,但*hash[key]结果不是pair
    hash[key] = cache.begin();
    return cache.front().second;
    

个人思路代码

伪代码

// key 映射到 Node(key, val)
HashMap<Integer, Node> map;
// Node(k1, v1) <-> Node(k2, v2)...
DoubleList cache;

int get(int key) {
    if (key 不存在) {
        return -1;
    } else {        
        将数据 (key, val) 提到开头;
        return val;
    }
}

void put(int key, int val) {
    Node x = new Node(key, val);
    if (key 已存在) {
        把旧的数据删除;
        将新节点 x 插入到开头;
    } else {
        if (cache 已满) {
            删除链表的最后一个数据腾位置;
            删除 map 中映射到该数据的键;
        } 
        将新节点 x 插入到开头;
        map 中新建 key 对新节点 x 的映射;
    }
}
class LRUCache {
private:
    int cap;
    list<pair<int, int> > cache; //双向链表,保证头尾节点在常规时间内删除、插入
    //hash的键存储 数据的key,hash的值存储  数据key-val键值对在双向链表中的迭代器
    unordered_map<int, list<pair<int, int> >::iterator> hash; 
public:
    LRUCache(int capacity) {
        cap = capacity;
    }
    
    //获取缓存中的关键字
    int get(int key) {
        if(hash.count(key) == 0){
            //key不存在,返回-1
            return -1;
        }
        else{
            //key存在,返回key的val,并把键值对提到链表头部
            auto key_value = *hash[key];//这里的auto推导出来的类型并不是迭代器类型,而是键值对(pair)类型,不能省略
            cache.erase(hash[key]); //cache删除旧数据
            cache.push_front(key_value); //cache把键值对提到链表头部
            hash[key] = cache.begin();
            return cache.front().second;
        }
    }
    
    //插入缓存
    void put(int key, int value) {
        if(hash.count(key) != 0){
            //key值已存在,把旧数据删除,新数据插入到双向链表头部
            cache.erase(hash[key]);//删去cache中的旧数据
        }
        else{
            //key值不存在
            if(cache.size() >= cap){
                //内存超限,删除双向链表末尾数据,删除hash中的旧数据,新数据插入到双向链表头部
                hash.erase(cache.back().first);//hash删除末尾数据
                // cache.erase(cache.end());//cache删除末尾数据,末尾数据的地址并非cache.end(),如for(iter != mp.end())
                cache.pop_back();
            }
        }
        //新数据插入到双向链表头部
        cache.push_front({key, value});
        hash[key] = cache.begin();
    }
};

/**
 * 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);
 */

参考

作者:labuladong
链接:https://leetcode-cn.com/problems/lru-cache/solution/lru-ce-lue-xiang-jie-he-shi-xian-by-labuladong/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-13 22:03:13  更:2022-03-13 22:06:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 13:52:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码