我們維護乙個有序的單鏈表,越靠近鍊錶尾部的越是越早之前訪問的,當有乙個新的資料訪問時,我們從頭遍歷鍊錶
1 如果此資料之前已經被快取到了鍊錶中,我們遍歷得到這個資料節點,然後從原位置刪除,插入到鍊錶的頭部
2 如果此資料沒有快取到鍊錶中,分為倆種情況
2.1 如果此時鍊錶未滿,就將此節點快取到煉表頭
2.2 如果此時快取已經滿了,則把鍊錶尾節點刪除,再將新的資料新增到頭結點。
這就是乙個簡單的lru快取,這種情況不管有沒有滿,都要遍歷一遍鍊錶,所以時間複雜度為o(n),我們還可以利用雜湊表優化
乙個lru快取演算法主要包括以下操作
1 向快取裡新增乙個資料
2 從快取裡刪除乙個資料
3 從快取裡查詢乙個資料
這三個操作都涉及查詢操作,如果單純的用鍊錶只能是o(n),如果我們將鍊錶和雜湊表結合,就可以做到o(1),具體的資料結構如下面
我們使用雙向鍊錶儲存資料,鍊錶中每個節點儲存資料data,前驅指標prve和後繼指標next之外,還儲存了乙個hnext,那hnext有什麼作用呢?
因為雜湊表是通過鍊錶法,解決雜湊衝突的,所以每個節點會存在倆條鏈中,一條就是雜湊表中的雙向鍊錶,另一條就是我們的拉鍊,前序指標和後續指標是為了將結點串在雙向鍊錶中,hnext是為了串在拉鍊中
這個資料結構,查詢乙個資料,通過雜湊表去查詢,時間複雜度為o(1)
這個資料結構,刪除這個資料,首先我們要找到這個資料的節點,可以通過雜湊表查詢,時間複雜度為o(1),然後刪除,因為是雙向鍊錶,可以找到前驅指標,所以可以o(1),刪除資料
這個資料結構,新增乙個資料,首先我們要查詢這個資料是否在快取中通過雜湊表查o(1),如果在其中,把它移到雙鏈表的尾部o(1),如果不在其中,看快取是否已滿,如果已經滿了,就把頭部結點刪除o(1),把新資料加入到尾部o(1),如果沒有滿,就直接假如到尾部o(1)
這樣就通過雜湊表和煉表,實現了乙個高效,支援lru演算法的快取系統原型
我們知道hashmap是由雜湊表實現的,那麼linkedhashmap多了乙個linked,指的是什麼?
其實linkedhashmap的linked是指雙鏈表,他支援插入順序遍歷資料,還支援訪問順序遍歷資料,也就是說linkedhashmap本身就是支援lru快取演算法的
實際上linkedhashmap是通過雜湊表和雙鏈表倆種資料結構結合實現的,其實linkedhashmap的linked是指雙鏈表,並不是治煉表法解決雜湊衝突
LRU演算法的實現2 資料結構
理論上不能算是最好的演算法,但是這個方法也可以。include using namespace std template typename k,typename v class lru keytable key make pair value,nowtime timetable nowtime ke...
LRU 演算法底層資料結構實現原理
前奏 如果 cpu 訪問的頁面不在記憶體中,則作業系統需要進行置換出記憶體中的頁面,然後把需要訪問的頁面從磁碟中置換到記憶體中,而這種演算法最常見的就是 lru 演算法,lru 演算法也被稱最近最少使用演算法.假如現在有乙個需求,公司需要抽出乙個使用者系統,向各個業務系統提供使用者的基本資訊 設計方...
資料結構與演算法 Redis中LRU演算法的基本思想
lru least recently used 是一種快取置換演算法。即在快取有限的情況下,如果有新的資料需要載入進快取,則需要將最不可能被繼續訪問的快取剔除掉。下面總結一下核心操作的步驟 class dlinkednodelru cache public class lrucache public...