原文連接: https://wangwei.one/posts/jav...
前面,咱們學習了 鏈表 的實現,今天咱們來學習鏈表的一個經典的應用場景——LRU淘汰算法。html
緩存是一種提升數據讀取性能的技術,在硬件設計、軟件開發中都有着很是普遍的應用,好比常見的 CPU 緩存、數據庫緩存、瀏覽器緩存等等。java
緩存的大小有限,當緩存被用滿時,哪些數據應該被清理出去,哪些數據應該被保留?這就須要緩存淘汰策略來決定。常見的策略有三種:先進先出策略 FIFO(First In,First Out)
、最少使用策略 LFU(Least Frequently Used)
、最近最少使用策略 LRU(Least Recently Used)
,本篇將介紹LRU策略算法。node
這一算法的核心思想是,當緩存數據達到預設的上限後,會優先淘汰掉近期最少使用的緩存對象。git
LRU淘汰算法涉及數據的添加與刪除,出於性能考慮,採用鏈表來進行實現,思路以下:github
放入一個數據時,若是數據已存在則將其移動到鏈表頭部,並更新Key所對應的Value值,若是不存在,則:算法
查詢一個數據時,遍歷整個鏈表,若是能查詢到對應的數據,則將其移動到鏈表頭部;若是查詢不到則返回null
;數據庫
O(n)
,咱們能夠使用散列表HashMap
來記錄每一個Key所對應的Node節點,將時間複雜度降爲O(1)。
package one.wangwei.algorithms.utils; import java.util.HashMap; import java.util.Map; /** * LRU Cache * * @author https://wangwei.one * @date 2019/01/29 */ public class LRUCache<K, V> { private int capacity; private Node head; private Node tail; private Map<K, Node> nodeMap; public LRUCache(int capacity) { this.capacity = capacity; this.nodeMap = new HashMap<>(capacity); } /** * Get Key * * @param key * @return */ public V get(K key) { Node existNode = nodeMap.get(key); if (existNode == null) { return null; } remove(existNode); addFirst(existNode); return existNode.value; } /** * Add Key-Value * * @param key * @param value */ public void put(K key, V value) { Node existNode = nodeMap.get(key); if (existNode == null) { Node newNode = new Node(key, value); if (nodeMap.size() >= capacity) { removeLast(); } addFirst(newNode); } else { // update the value existNode.value = value; remove(existNode); addFirst(existNode); } } /** * remove node * * @param node */ private void remove(Node node) { Node prev = node.prev; Node next = node.next; if (prev == null) { head = next; } else { prev.next = next; } if (next == null) { tail = prev; } else { next.prev = prev; } nodeMap.remove(node.key); } /** * add first node * * @param node */ private void addFirst(Node node) { node.prev = null; if (head == null) { head = tail = node; } else { node.next = head; head.prev = node; head = node; } nodeMap.put(node.key, node); } /** * remove last */ private void removeLast() { if (tail == null) { return; } // remove key from map nodeMap.remove(tail.key); // remove node from linked list Node prev = tail.prev; if (prev != null) { prev.next = null; tail = prev; } else { head = tail = null; } } private class Node { private K key; private V value; private Node prev; private Node next; private Node(K key, V value) { this.key = key; this.value = value; } } }
源碼
LeetCode上相關的練習題:Leetcode 146. LRU Cache瀏覽器
性能測試:LeetCode上運行時間爲88ms
,超過了 43.42%
的Java代碼。緩存