• 【面试题】手撕缓存LRU


    设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能

    • put(key, value):将记录(key, value)插入该结构
    • get(key):返回key对应的value值

    对于put(key, value)来说,我们需要考虑两部分:

    1. 如果缓存中存在,那么直接将缓存中对应的元素移动到缓存头部
    2. 如果缓存中不存在,那么把元素添加到缓存头部,如果此时缓存的大小超出了预先设定的值,那么则将缓存尾部的元素删除

    对于get(key)来说,我们还是需要考虑两部分:

    1. 如果缓存中存在,那么返回该值,并且将这个值移动到缓存头部
    2. 如果缓存中不存在,那么返回-1

    综上所述:对于一个LRU缓存来说,主要包含以下三种操作。

    1. 查找一个元素。
    2. 在缓存末尾删除一个元素。
    3. 在缓存头部添加一个元素。

    所以,我们最容易想到的实现方式就是通过双端链表+哈希表来实现这个问题,最终实现代码如下:

    1. class LRUCache {
    2. private HashMap cache;
    3. private int capacity;
    4. private ListNode head,tail;
    5. class ListNode{
    6. int key;
    7. int value;
    8. ListNode prev;
    9. ListNode next;
    10. public ListNode(){
    11. }
    12. public ListNode(int key,int value){
    13. this.key=key;
    14. this.value=value;
    15. }
    16. }
    17. public LRUCache(int capacity) {
    18. this.capacity =capacity;
    19. cache = new HashMap<>();
    20. head = new ListNode();
    21. tail = new ListNode();
    22. head.next = tail;
    23. tail.prev = head;
    24. }
    25. public int get(int key) {
    26. //首先判断一下是否存在key
    27. ListNode node = cache.get(key);
    28. if(node==null){
    29. return -1;
    30. }
    31. //如果存在,把缓存移动到头部,返回value
    32. moveToHead(node);
    33. return node.value;
    34. }
    35. public void put(int key, int value) {
    36. //判断是否存在
    37. ListNode node = cache.get(key);
    38. //如果不存在,添加到头部,如果容量到达上限,则删除队尾的元素,如果存在直接移动到头部
    39. if(node==null){
    40. ListNode newNode = new ListNode(key,value);
    41. cache.put(key,newNode);
    42. addNode(newNode);
    43. if(cache.size()>capacity){
    44. ListNode last = popTail();
    45. cache.remove(last.key);
    46. }
    47. }else{
    48. node.value=value;
    49. moveToHead(node);
    50. }
    51. }
    52. public void addNode(ListNode node){
    53. node.prev = head;
    54. node.next = head.next;
    55. head.next.prev = node;
    56. head.next = node;
    57. }
    58. public void removeNode(ListNode node){
    59. ListNode prevNode = node.prev;
    60. ListNode NextNode = node.next;
    61. prevNode.next = NextNode;
    62. NextNode.prev = prevNode;
    63. }
    64. public void moveToHead(ListNode node){
    65. removeNode(node);
    66. addNode(node);
    67. }
    68. public ListNode popTail(){
    69. ListNode lastNode = tail.prev;
    70. removeNode(lastNode);
    71. return lastNode;
    72. }
    73. }

  • 相关阅读:
    验证UDP端口是否开放
    内网Windows Git Server部署
    Linux下c++串口编程
    java计算机毕业设计酒店预约入住系统源码+mysql数据库+系统+lw文档+部署
    场景图形管理 - (2)
    设计一个填充工具完美解决前后端甩锅的问题了
    时序预测 | MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元时间序列预测
    网络安全(黑客)-自学手册
    [MapStruct]集合的映射
    JVM垃圾回收系列之垃圾收集器二
  • 原文地址:https://blog.csdn.net/loss_rose777/article/details/140444881