LRU算法实现

      1.lru缓存策略
      构成要素有两个:内存大小和替换策略.
      实现方法: hashtable+双向链表
      查询时间复杂度o(1),修改更新时间复杂度o(1).
      
      2.lru工作原理
      
    
    
  1 1.题目地址:https://leetcode-cn.com/problems/lru-cache/
  2 2.题目内容:LRU缓存机制(中等)
  3 
  4 运用你所掌握的数据结构,设计和实现一个LRU(最近最少使用)缓存机制.它应该支持以下操作:获取数据get和写入数据put.
  5 
  6 获取数据get(key)-如果关键字(key)存在于缓存中,则获取关键字的值(总是正数),否则返回-1.
  7 写入数据put(key,value)-如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组[关键字/值].当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间.
  8 
  9 示例:
 10 LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
 11 
 12 cache.put(1, 1);
 13 cache.put(2, 2);
 14 cache.get(1);       // 返回  1
 15 cache.put(3, 3);    // 该操作会使得关键字 2 作废
 16 cache.get(2);       // 返回 -1 (未找到)
 17 cache.put(4, 4);    // 该操作会使得关键字 1 作废
 18 cache.get(1);       // 返回 -1 (未找到)
 19 cache.get(3);       // 返回  3
 20 cache.get(4);       // 返回  4
 21 
 22 第一步:确定题目要实现的主要业务功能
 23 第二步:实现业务功能的单元
 24 第三步:组装实现业务功能的单元
 25 
 26 4.lru(哈希表+双向链表)
 27 
 28 public class Lru {
 29     // 1.定义双向链表
 30     class DoubleLinkNode {
 31         int key;
 32         int value;
 33         DoubleLinkNode prev;
 34         DoubleLinkNode next;
 35 
 36         public DoubleLinkNode() {}
 37 
 38         public DoubleLinkNode(int key, int value) {
 39             this.key = key;
 40             this.value = value;
 41         }
 42     }
 43 
 44     // 2.定义哈希表
 45     private Map<Integer, DoubleLinkNode> cache = new HashMap<>();
 46     // 3.定义缓存数量,缓存容量
 47     private int size;
 48     private int capacity;
 49     // 4.定义头尾节点
 50     private DoubleLinkNode head;
 51     private DoubleLinkNode tail;
 52 
 53     public Lru(int capacity) {
 54         this.size = 0;
 55         this.capacity = capacity;
 56         // 设置伪头部和尾部,非常巧妙
 57         head = new DoubleLinkNode();
 58         tail = new DoubleLinkNode();
 59         head.next = tail;
 60         tail.prev = head;
 61     }
 62 
 63     /**
 64      * 将节点写入头部
 65      * A-B-C,其中AC插入B,需要处理B的prv和next节点,C的prev,A的next
 66      */
 67     private void addToHead(DoubleLinkNode node) {
 68         node.prev = head;
 69         node.next = head.next;
 70         // 下面顺序不可颠倒 
 71         head.next.prev = node;
 72         head.next = node;
 73     }
 74 
 75     /**
 76      * 删除结点
 77      * A-B-C,其中ABC删除B,需要处理A的next和c的prev
 78      */
 79     private void removeNode(DoubleLinkNode node) {
 80         node.prev.next = node.next;
 81         node.next.prev = node.prev;
 82     }
 83 
 84     /**
 85      * 移动到头结点
 86      * A-B-C,其中AC插入B,需要处理B的prv和next节点,A的next,C的prev
 87      */
 88     private void moveToHead(DoubleLinkNode node) {
 89         removeNode(node);
 90         addToHead(node);
 91     }
 92     
 93     /**
 94      * 删除尾结点
 95      * @return DoubleLinkNode
 96      */
 97     private DoubleLinkNode removeTail() {
 98         DoubleLinkNode node = tail.prev;
 99         removeNode(node);
100         return node;
101     }
102     
103     /**
104      * 获取缓存值
105      * @param key
106      */
107     public int get(int key) {
108         DoubleLinkNode node = cache.get(key);
109         if (node == null) {
110             return -1;
111         } else {
112             addToHead(node);
113             return node.value;
114         }
115     }
116     
117     /**
118      * 保存缓存值
119      * @param key
120      */
121     public void put(int key, int value) {
122         DoubleLinkNode node = cache.get(key);
123         // 如果节点存在
124         if (node != null) {
125             node.value = value;
126             moveToHead(node);
127         } else {
128             // 创建新节点,添加到hash表中
129             DoubleLinkNode newNode = new DoubleLinkNode(key, value);
130             cache.put(key, newNode);
131             // 移动到双向链表头部
132             moveToHead(newNode);
133             size++;
134             if (size > capacity) {
135                 // hash表超出容量
136                 DoubleLinkNode tail = removeTail();
137                 cache.remove(tail.key);
138                 size--;
139             }
140         }
141     }
142 }

 

posted @ 2020-10-28 18:12  halfway2  阅读(161)  评论(0编辑  收藏  举报