LRU算法
LRU是什么?按照英文的直接原义就是Least Recently Used,最近最久未使用法,它是按照一个非常著名的计算机操作系统基础理论得来的:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。基于这个思想,会存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。在计算机中大量使用了这个机制,它的合理性在于优先筛选热点数据,所谓热点数据,就是最近最多使用的数据!因为,利用LRU我们可以解决很多实际开发中的问题,并且很符合业务场景
1 import java.util.HashMap; 2 3 public class LRU<K, V> { 4 private int currentSize;//当前的大小 5 private int capcity;//总容量 6 private HashMap<K, Node> caches;//所有的node节点 7 private Node first;//头节点 8 private Node last;//尾节点 9 10 public LRU(int size) { 11 currentSize = 0; 12 this.capcity = size; 13 caches = new HashMap<K, Node>(size); 14 } 15 16 /** 17 * 放入元素 18 * @param key 19 * @param value 20 */ 21 public void put(K key, V value) { 22 Node node = caches.get(key); 23 //如果新元素 24 if (node == null) { 25 //如果超过元素容纳量 26 if (caches.size() >= capcity) { 27 //移除最后一个节点 28 caches.remove(last.key); 29 removeLast(); 30 } 31 //创建新节点 32 node = new Node(key,value); 33 } 34 //已经存在的元素覆盖旧值 35 node.value = value; 36 //把元素移动到首部 37 moveToHead(node); 38 caches.put(key, node); 39 } 40 41 /** 42 * 通过key获取元素 43 * @param key 44 * @return 45 */ 46 public Object get(K key) { 47 Node node = caches.get(key); 48 if (node == null) { 49 return null; 50 } 51 //把访问的节点移动到首部 52 moveToHead(node); 53 return node.value; 54 } 55 56 /** 57 * 根据key移除节点 58 * @param key 59 * @return 60 */ 61 public Object remove(K key) { 62 Node node = caches.get(key); 63 if (node != null) { 64 if (node.pre != null) { 65 node.pre.next = node.next; 66 } 67 if (node.next != null) { 68 node.next.pre = node.pre; 69 } 70 if (node == first) { 71 first = node.next; 72 } 73 if (node == last) { 74 last = node.pre; 75 } 76 } 77 return caches.remove(key); 78 } 79 80 /** 81 * 清除所有节点 82 */ 83 public void clear() { 84 first = null; 85 last = null; 86 caches.clear(); 87 } 88 89 /** 90 * 把当前节点移动到首部 91 * @param node 92 */ 93 private void moveToHead(Node node) { 94 if (first == node) { 95 return; 96 } 97 if (node.next != null) { 98 node.next.pre = node.pre; 99 } 100 if (node.pre != null) { 101 node.pre.next = node.next; 102 } 103 if (node == last) { 104 last = last.pre; 105 } 106 if (first == null || last == null) { 107 first = last = node; 108 return; 109 } 110 node.next = first; 111 first.pre = node; 112 first = node; 113 first.pre = null; 114 } 115 116 /** 117 * 移除最后一个节点 118 */ 119 private void removeLast() { 120 if (last != null) { 121 last = last.pre; 122 if (last == null) { 123 first = null; 124 } else { 125 last.next = null; 126 } 127 } 128 } 129 130 @Override 131 public String toString() { 132 StringBuilder sb = new StringBuilder(); 133 Node node = first; 134 while (node != null) { 135 sb.append(String.format("%s:%s ", node.key, node.value)); 136 node = node.next; 137 } 138 return sb.toString(); 139 } 140 141 142 public static void main(String[] args) { 143 LRU<Integer, String> lru = new LRU<Integer, String>(5); 144 lru.put(1, "a"); 145 lru.put(2, "b"); 146 lru.put(3, "c"); 147 lru.put(4,"d"); 148 lru.put(5,"e"); 149 System.out.println("原始链表为:"+lru.toString()); 150 151 lru.get(4); 152 System.out.println("获取key为4的元素之后的链表:"+lru.toString()); 153 154 lru.put(6,"f"); 155 System.out.println("新添加一个key为6之后的链表:"+lru.toString()); 156 157 lru.remove(3); 158 System.out.println("移除key=3的之后的链表:"+lru.toString()); 159 } 160 }
原始链表为:
5
:e
4
:d
3
:c
2
:b
1
:a
获取key为
4
的元素之后的链表:
4
:d
5
:e
3
:c
2
:b
1
:a
新添加一个key为
6
之后的链表:
6
:f
4
:d
5
:e
3
:c
2
:b
移除key=
3
的之后的链表:
6
:f
4
:d
5
:e
2
:b