• LeetCode 146. LRU 缓存


    题目链接

    力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

    了解LRU

            LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

    题目解析

            我们定义一个双向链表,若某个结点被获取或者新插入或者改动。我们就视为该节点刚刚被访问了,因此就将该节点插入该双向链表的头结点处。

            若超过该缓存的capacity就将该双向链表的尾结点进行删除。

            我们在此需要自己实现一个双向链表供我们使用,为了更好的通过某个结点的key来访问到该结点,我们使用哈希表将key和对应的结点进行存储。

    代码

    1. struct DLinkedNode
    2. {
    3. int _key;
    4. int _value;
    5. DLinkedNode * prev;
    6. DLinkedNode * next;
    7. // 无参的构造函数
    8. DLinkedNode () :_key(0), _value(0), prev(nullptr), next(nullptr) {}
    9. // 有参的构造函数
    10. DLinkedNode (int key, int value) :_key(key), _value(value), prev(nullptr), next(nullptr)
    11. {}
    12. };
    13. class LRUCache
    14. {
    15. // 双向链表+哈希表
    16. public:
    17. LRUCache(int capacity) :_capacity(capacity), _size(0)
    18. {
    19. // 创建一个伪头部结点和伪尾部结点
    20. head = new DLinkedNode ();
    21. tail = new DLinkedNode ();
    22. head->next = tail;
    23. tail->prev = head;
    24. }
    25. int get(int key)
    26. {
    27. if (cache.count(key) != 0)
    28. {
    29. DLinkedNode * cur = cache[key];
    30. moveToHead(cur);
    31. return cur->_value;
    32. }
    33. return -1;
    34. }
    35. void put(int key, int value)
    36. {
    37. // 如果key不存在的情况下
    38. if (cache.count(key) == 0)
    39. {
    40. // 为该key创建一个新的结点
    41. DLinkedNode * node = new DLinkedNode (key, value);
    42. // 添加到哈希表中
    43. cache[key] = node;
    44. // 将该结点添加至头部
    45. addToHead(node);
    46. // 更新大小
    47. _size++;
    48. // 如果此时已经超过缓存容量
    49. if (_size > _capacity)
    50. {
    51. // 删除双链表的尾部结点
    52. DLinkedNode * removenode = removeTail();
    53. // 删除哈希表中对应的键值对
    54. cache.erase(removenode->_key);
    55. // 防止内存泄漏
    56. delete removenode;
    57. // 更新大小
    58. _size--;
    59. }
    60. }
    61. // 如果key存在,通过哈希表找到对应的结点,然后修改value然后将该结点移动到头部即可
    62. else
    63. {
    64. DLinkedNode * node = cache[key];
    65. node->_value = value;
    66. moveToHead(node);
    67. }
    68. }
    69. // 将该结点添加到头部位置
    70. void addToHead(DLinkedNode * node)
    71. {
    72. node->prev = head;
    73. node->next = head->next;
    74. head->next->prev = node;
    75. head->next = node;
    76. }
    77. // 移除该结点
    78. // 方法就是让该结点的前后节点连接起来
    79. void removeNode(DLinkedNode * node)
    80. {
    81. node->prev->next = node->next;
    82. node->next->prev = node->prev;
    83. }
    84. // 将该结点移动到头部位置
    85. void moveToHead(DLinkedNode * node)
    86. {
    87. // 首先移除该结点
    88. removeNode(node);
    89. // 然后让该结点移动到头部位置
    90. addToHead(node);
    91. }
    92. DLinkedNode * removeTail()
    93. {
    94. DLinkedNode * node = tail->prev;
    95. removeNode(node);
    96. return node;
    97. }
    98. private:
    99. //
    100. unordered_map<int, DLinkedNode *> cache;
    101. DLinkedNode * head;
    102. DLinkedNode * tail;
    103. int _size;
    104. int _capacity;
    105. };
    106. /**
    107. * Your LRUCache object will be instantiated and called as such:
    108. * LRUCache* obj = new LRUCache(capacity);
    109. * int param_1 = obj->get(key);
    110. * obj->put(key,value);
    111. */

  • 相关阅读:
    Vue3 —— 创建 Vue3.0 工程
    【Pytorch with fastai】第 5 章 :图像分类
    文心一言 VS 讯飞星火 VS chatgpt (105)-- 算法导论10.1 3题
    Java-继承
    如何编写 Kubernetes 的 YAML 文件?
    带团队后的日常思考(十二)
    【博学谷学习记录】超强总结,用心分享|架构师-前置知识-mongodb基本使用
    MySQL批量入库的几种方式详解
    详细解读Latent Diffusion Models:原理和代码
    Git常用操作命令
  • 原文地址:https://blog.csdn.net/m0_57249790/article/details/133205684