HashMap+双向链表实现LRU
生活随笔
收集整理的這篇文章主要介紹了
HashMap+双向链表实现LRU
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
LRU即是Least Recently Used,即最近最少使用,選擇最近最久未使用的數據將其淘汰。
最簡單的想法是使用先進先出(FIFO)的方式來實現,通過雙向鏈表來實現
因為鏈表插入和刪除快,但是查詢慢 ,而?HashMap的查詢速度快很多,所以除了構建一個雙向鏈表,還構建了一個哈希map,用于快速查詢對應key的節(jié)點,用空間換時間
每次key被訪問的時候,把被訪問到的key移到頭節(jié)點,這樣當添加新節(jié)點的時候,直接添加到頭節(jié)點即可,如果緩存已滿,直接刪除尾節(jié)點就可以了
jdk里有提供現成的LinkedHashMap,采用HashMap+鏈表的方式自己實現了一下
/*** @Description* @Author chenpp* @Date 2019/11/21 17:50* 定義雙向鏈表的節(jié)點*/ public class Node<K,V> {private K key;private V value;private Node next;private Node pre;public Node(K key,V value){this.key = key;this.value = value;}public K getKey() {return key;}public void setKey(K key) {this.key = key;}public V getValue() {return value;}public void setValue(V value) {this.value = value;}public Node getNext() {return next;}public void setNext(Node next) {this.next = next;}public Node getPre() {return pre;}public void setPre(Node pre) {this.pre = pre;} } /*** @Description* @Author chenpp* @Date 2019/11/21 17:56* 定義一個雙向鏈表*/ public class DoubleLinkedList<K,V> {transient Node<K,V> first;transient Node<K,V> last;/*** 當前鏈表里的節(jié)點數目* */transient int size;/*** 添加節(jié)點到鏈表頭部* */public void addFirst(Node node) {if (first == null) {first = node;last = node;} else {Node oldFirst = first;oldFirst.setPre(node);node.setNext(oldFirst);first = node;}size++;}/*** 刪除鏈表里已有的node節(jié)點** */private Node removeNode(Node node){if(node == null){return null;}Node preNode = node.getPre();Node nextNode = node.getNext();if(preNode != null) {preNode.setNext(nextNode);}else{first = nextNode;}if(nextNode != null){nextNode.setPre(preNode);}else{last = preNode;}size--;return node;}/*** 將鏈表指定節(jié)點node移動到頭部** */public Node moveToHead(Node node){if(node == first){return node;}if( node == last){last = node.getPre();}else{node.getNext().setPre(node.getPre());}node.getPre().setNext(node.getNext());node.setPre(null);node.setNext(first);first = node;return node;}/*** 刪除最后一個節(jié)點* 并返回刪除的節(jié)點** */public Node removeLast(){Node node = last;removeNode(last);return node;}public int size(){return size;} } /*** @Description* @Author chenpp* @Date 2019/11/21 17:52* */ public class LRUCache<K,V> {private HashMap<K, Node<K,V>> linkedHashMap;private int capacity;private DoubleLinkedList linkedList;public LRUCache(int capacity){this.capacity = capacity;linkedList = new DoubleLinkedList();linkedHashMap = new HashMap<K, Node<K,V>>();}/*** 訪問緩存指定的key* 將對應的node移動到鏈表頭部** */public V get(K k){Node<K,V> node = linkedHashMap.get(k);if(node == null){return null;}//將訪問的節(jié)點移動到頭節(jié)點linkedList.moveToHead(node);return node.getValue();}/*** 新增node節(jié)點到鏈表頭部* 如果緩存超過最大容量,則刪除尾部節(jié)點** */public void put(K key,V val){Node node = linkedHashMap.get(key);//如果節(jié)點的key本來就存在,則直接移動到頭節(jié)點if(node != null){node.setValue(val);node = linkedList.moveToHead(node);}else{node = new Node(key,val);//如果key不存在,則新增節(jié)點到頭部if(linkedList.size() >= capacity){//移除訪問時間最遠的節(jié)點Node last = linkedList.removeLast();linkedHashMap.remove(last.getKey());}linkedList.addFirst(node);}//更新hashMap里的值linkedHashMap.put(key,node);}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();Node node = linkedList.first;while(node != null){sb.append(String.format("%s:%s ", node.getKey(),node.getValue()));node = node.getNext();}return sb.toString();}}測試一下:
/*** @Description* @Author chenpp* @Date 2019/11/21 19:49*/ public class Test {public static void main(String[] args) {LRUCache<String,String> cache = new LRUCache<String, String>(5);cache.put("a","111");cache.put("b","2121");cache.put("c","3231");cache.put("d","2122");cache.put("e","2131");cache.get("3");//e d c b aSystem.out.println(cache.toString());cache.get("a");// a e d c bSystem.out.println(cache.toString());cache.put("f","13123");// f a e d cSystem.out.println(cache.toString());cache.get("b");System.out.println(cache.toString());cache.get("a");// a f e d cSystem.out.println(cache.toString());cache.put("g","g");// g a f e dSystem.out.println(cache.toString());cache.put("c","31");// c g a f eSystem.out.println(cache.toString());cache.get("d");System.out.println(cache.toString());cache.get("c");System.out.println(cache.toString());} }總結
以上是生活随笔為你收集整理的HashMap+双向链表实现LRU的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: virtualbox+vagrant安装
- 下一篇: docker学习笔记(一)docker入