• 设计LRU缓存结构


    1. 什么是LRU缓存?

    LRU缓存是一种基于最近访问原则缓存策略。它的核心思想是,当缓存空间满时,优先淘汰最近最少使用的数据。这种策略的好处是,可以保留最常访问的数据,提高缓存命中率,从而提高系统性能

    2. LRU缓存的实现原理

    LRU缓存的实现可以借助哈希表和双向链表。哈希表用于快速查找缓存中的数据,而双向链表用于维护数据的访问顺序。每当访问一个数据时,如果数据已经存在于缓存中,将其移动到链表的头部;如果数据不存在于缓存中,将其添加到链表的头部。当缓存空间满时,淘汰链表尾部的数据即可。

    3. LRU缓存的实现步骤

    - 初始化缓存大小和哈希表

    - 访问数据时,检查哈希表中是否存在该数据

    - 如果存在,将数据移动到链表头部

    - 如果不存在,将数据添加到链表头部,并在哈希表中添加对应的键值对

    - 如果缓存已满,删除链表尾部的数据,并在哈希表中删除对应的键值对

    4.具体实现

    1. public class LRUCache {
    2. //链表存储键值对(旧数据靠链表尾)
    3. class Node {
    4. int key;
    5. int value;
    6. Node prev;
    7. Node next;
    8. public Node(int key, int value) {
    9. this.key = key;
    10. this.value = value;
    11. }
    12. }
    13. //缓存大小
    14. private int capacity;
    15. //缓存
    16. private Map cache;
    17. //头指针
    18. private Node head;
    19. //尾指针组成双向链表
    20. private Node tail;
    21. //初始化缓存
    22. public LRUCache(int capacity) {
    23. this.capacity = capacity;
    24. this.cache = new HashMap<>();
    25. this.head = new Node(0, 0);
    26. this.tail = new Node(0, 0);
    27. head.next = tail;
    28. tail.next = head;
    29. }
    30. //获取缓存数据
    31. public int get(int key) {
    32. if (cache.containsKey(key)) {
    33. Node node = cache.get(key);
    34. //更新数据(把该数据放到链表头)
    35. removeNode(node);
    36. addToHead(node);
    37. return node.value;
    38. }
    39. //不存在则返回-1
    40. return -1;
    41. }
    42. //存放数据
    43. public void put(int key, int value) {
    44. //包含则更新,不然新增
    45. if (cache.containsKey(key)) {
    46. Node node = cache.get(key);
    47. node.value = value;
    48. //更新数据
    49. removeNode(node);
    50. addToHead(node);
    51. } else {
    52. //大于容量,则删除最后一个值(最不经常使用的数据)
    53. if (cache.size() == capacity) {
    54. Node tailPrev = tail.prev;
    55. removeNode(tailPrev);
    56. cache.remove(tailPrev.key);
    57. }
    58. Node newNode = new Node(key, value);
    59. cache.put(key, newNode);
    60. addToHead(newNode);
    61. }
    62. }
    63. //删除链表节点
    64. private void removeNode(Node node) {
    65. Node prevNode = node.prev;
    66. Node nextNode = node.next;
    67. prevNode.next = nextNode;
    68. nextNode.prev = prevNode;
    69. }
    70. //头部插入节点
    71. private void addToHead(Node node) {
    72. Node nextNode = head.next;
    73. head.next = node;
    74. node.prev = head;
    75. node.next = nextNode;
    76. nextNode.prev = node;
    77. }
    78. }

  • 相关阅读:
    【Redis】Zset有序集合
    陈奂仁音乐狂欢节:怪异的多色吉他 NFT 系列来袭!
    Google Earth Engine(GEE)——ui.util.debounce的使用
    Sentinel
    【Linux】《Linux命令行与shell脚本编程大全 (第4版) 》笔记-Chapter11-构建基础脚本
    Pytorch框架学习路径(一:张量简介与创建)
    memcpy的使⽤和模拟实现
    一文解析推特上最常见的加密骗局
    Day51|动态规划part12:309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费
    Linux命令200例:free用来显示系统内存使用情况
  • 原文地址:https://blog.csdn.net/DU9999999/article/details/133036160