LRU(Least Recently Used)即最近最少使用,是一種緩存算法(頁面置換算法)。咱們知道,緩存一般是具備固定大小的,他應該只保存那些經常被用到的數據,而數據如何更新則是經過緩存算法實現,LRU算法就是一種簡單,經常使用的緩存算法。node
LRU算法是核心思想是:若是一個數據在最近一段時間都沒有被用到,那麼它在未來被使用到的可能性也很小。故當緩存空間已滿的狀況下,咱們須要淘汰掉最久沒有被訪問到的數據。理想的LRU算法讀寫是時間複雜度應該都爲O(1)。算法
爲了達到理想的性能,咱們須要一種既能夠按訪問順序排序,又能夠在常數時間隨機訪問的數據結構。這裏能夠採用HashMap和雙向鏈表實現。HashMap能夠存儲Key,能夠在常數時間裏讀寫Key,而Value用來指向雙向鏈表的節點,爲了在常數時間裏移除一個節點咱們還須要Head節點和Tril節點。緩存
代碼實現以下:數據結構
class LruCache<K, V>() { private data class Node<K, V>( var key: K? = null, var value: V? = null, var prev: Node<K, V>? = null, var next: Node<K, V>? = null ) private val hashMap: HashMap<K, Node<K, V>> = hashMapOf() private var count = 0 private var capacity = 8 private val head: Node<K, V> = Node() private val tail: Node<K, V> = Node() init { head.next = tail tail.prev = head } constructor(capacity: Int) : this() { this.capacity = capacity } fun get(key: K): V? { val node = hashMap[key] ?: return null move(node) return node.value } fun put(key: K, value: V) { val node = hashMap[key] if (node == null) { val newNode = Node(key, value) add(newNode) hashMap[key] = newNode ++count if (count > capacity) { val deleteNode = delete() hashMap.remove(deleteNode.key) --count } } else { node.value = value move(node) } } private fun add(node: Node<K, V>) { node.prev = head node.next = head.next head.next!!.prev = node head.next = node } private fun remove(node: Node<K, V>) { val prev = node.prev!! val next = node.next!! prev.next = next next.prev = prev } private fun move(node: Node<K, V>) { remove(node) add(node) } private fun delete(): Node<K, V> { val node = tail.prev!! remove(node) return node } }
而在實際使用中,咱們可使用LinkedHashMap實現,其內部就是使用雙向鏈表,咱們只需稍做修改便能使用。
在LinkedHashMap的構造參數(initialCapacity:Int, loadFactor:Float,accessOrder:Boolean)
中,initialCapacity
是HashMap的初始大小,loadFactor
則是裝載因子,accessOrder=false
表示基於插入順序,accessOrder=true
表示基於訪問順序。
實現LRU的關鍵方法:ide
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<K, V>?): Boolean { return size > capacity }
以上表示當LinkedHashMap大小超過咱們設定的大小時,移除鏈表首部的節點性能
class LruChche<K, V>(private val capacity: Int = 8) { private var hashMap: LinkedHashMap<K, V> = object : LinkedHashMap<K, V> (capacity / 0.75.toInt() + 1, 0.75f, true) { override fun removeEldestEntry(eldest: MutableMap.MutableEntry<K, V>?): Boolean { return size > capacity } } fun get(key: K): V? = hashMap[key] fun put(key: K, value: V) { hashMap[key] = value } }
第一次據說LRU算法是在現代操做系統這本書中,但引發我深究的是Glide這個庫在自定義Model的時候,便有了一探究竟的想法,故整理資料寫下這些文字,一面是爲了加深本身的影響,另外一面也但願我所說的能讓你們更簡單的去理解LRU,一塊兒學習。學習