• 【力客热题HOT100】-【052】146 LRU缓存


    重点:

    (1)此处必须使用双向链表:因为要取出节点,放到末尾节点;

    (2)head和tail作为两个标志节点一直存在,但没有赋值;

    (3)精髓在于用双向链表来标识LRU的最长未被访问,达到O(1)的查询时间

    (4)双向链表删除和添加节点,两步和四步

    146. LRU 缓存

    难度中等

    请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。

    实现 LRUCache 类:

    • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
    • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
    • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

    函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

    示例:

    输入
    ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
    [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
    输出
    [null, null, null, 1, null, -1, null, -1, 3, 4]
    
    解释
    LRUCache lRUCache = new LRUCache(2);
    lRUCache.put(1, 1); // 缓存是 {1=1}
    lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
    lRUCache.get(1);    // 返回 1
    lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
    lRUCache.get(2);    // 返回 -1 (未找到)
    lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
    lRUCache.get(1);    // 返回 -1 (未找到)
    lRUCache.get(3);    // 返回 3
    lRUCache.get(4);    // 返回 4
    

    提示:

    • 1 <= capacity <= 3000
    • 0 <= key <= 10000
    • 0 <= value <= 105
    • 最多调用 2 * 105 次 get 和 put

    解析:

    需要双向链表+哈希表实现。哈希表存,双向链表用来判断访问次序,靠近头节点表明最近访问过的,靠近尾节点表明最久未被访问。分析如下:

    对于get操作:首先通过哈希表判断键,是否在该LRU中,如果在,直接返回,并将对应的节点移到链表的head;如果没有对应的键则返回-1;

    对于put操作:

           ——如果key不存在,则首先通过key和value创建新节点LinkNode,添加进哈希表,并且将该节点添加到链表头节点。再判断当前的节点数量size是否超过capcity,如果超过就删除链表尾节点,并删除哈希表中对应的项;

           ——如果key存在,则首先通过哈希表key定为节点位置,然后更新节点值,并且将该节点移至头节点;

    1. struct LinkNode{
    2. int val,key;
    3. LinkNode *next,*pre;
    4. LinkNode(): val(-1),key(-1),pre(nullptr),next(nullptr) {};
    5. LinkNode(int x,int y): key(x),val(y),pre(nullptr),next(nullptr) {};
    6. };
    7. class LRUCache {
    8. private:
    9. int size;
    10. int capacity;
    11. unordered_map<int,LinkNode*> cache;
    12. LinkNode *head,*tail;
    13. public:
    14. LRUCache(int _capacity) {
    15. capacity=_capacity;
    16. size=0;
    17. head=new LinkNode();
    18. tail=new LinkNode();
    19. head->next=tail;
    20. tail->pre=head;
    21. }
    22. int get(int key) {
    23. if(!cache.count(key))
    24. return -1;
    25. LinkNode *tmp=cache[key];
    26. MovetoHead(tmp);
    27. return tmp->val;
    28. }
    29. void put(int key, int value) {
    30. //如果该key已经存在
    31. if(cache.count(key))//则修改值,并将节点移至链表尾
    32. {
    33. LinkNode *tmp=cache[key];
    34. tmp->val=value;
    35. MovetoHead(tmp);
    36. }
    37. else{
    38. LinkNode *tmp=new LinkNode(key,value);
    39. AddtoHead(tmp);
    40. size++;
    41. cache[key]=tmp;
    42. //是否超出内存
    43. if(size>capacity){
    44. LinkNode *remove=RemoveTail();//删哈希表和链表
    45. cache.erase(remove->key);
    46. delete remove;//删除这个节点,释放空间
    47. size--;
    48. }
    49. }
    50. }
    51. LinkNode* RemoveTail(){
    52. LinkNode *node=tail->pre;
    53. RemoveNode(node);
    54. return node;
    55. }
    56. void RemoveNode(LinkNode *node){
    57. node->pre->next=node->next;
    58. node->next->pre=node->pre;
    59. }
    60. void MovetoHead(LinkNode *node){
    61. RemoveNode(node);
    62. AddtoHead(node);
    63. }
    64. void AddtoHead(LinkNode *node){
    65. node->pre=head;
    66. node->next=head->next;
    67. head->next->pre=node;
    68. head->next=node;
    69. }
    70. };
  • 相关阅读:
    逆向-beginners之循环while
    C++ 继承和派生 万字长文超详解
    关于2023中国(济南)国际换热传热技术与应用展览会通知
    POJ 3109 Inner Vertices 离散化+树状数组
    【无标题】
    活动回顾∣企企通亮相高质量企业数字化活动,深入探讨各领域采购数字化转型与变革
    UML活动图
    在公司项目中使用git的简单手册
    HWUI源码剖析(二) - 终于讲清楚OpenGL渲染的MVP矩阵的来龙去脉
    12_C++_链表_回调函数
  • 原文地址:https://blog.csdn.net/zhuge2017302307/article/details/125859618