鍊錶 如何實現LRU快取淘汰演算法

2021-10-01 07:06:02 字數 2285 閱讀 2180

乙個經典的鍊錶應用場景,就是lru快取淘汰演算法

快取是一種提高資料讀取效能的技術,比如cpu快取、資料庫快取、瀏覽器快取等等

快取的大小有限,當快取被用滿的時候哪些資料該被清理出去?哪些資料該被保留?需要快取淘汰策略來決定:先進先出策略fifo,最少使用策略lfu,最近最少使用策略lru

陣列需要一塊連續的記憶體空間來儲存,對記憶體的要求比較高,如果申請乙個100m大小的陣列,當記憶體中沒有連續的、足夠大的儲存空間時,即便記憶體的剩餘總可用空間大於100m,仍然會申請失敗,而鍊錶不是,用過「指標」將一組零散的記憶體塊串聯起來使用,如果我們申請的是100m大小的鍊錶,不會有問題。

第乙個結點叫作頭結點,最後乙個叫作尾結點,頭結點用來記錄鍊錶的基位址,可以遍歷得到整條鍊錶,尾結點指向乙個空位址null,表示這是鍊錶的最後乙個結點

支援資料的查詢、插入和刪除操作:

針對鍊錶的插入刪除操作,只需要考慮相鄰結點的指標改變,所以對應的時間複雜度是o(1),但是鍊錶想隨機訪問第k個元素,就沒有陣列高效,無法像陣列一樣,根據首位址和下標,通過定址公式就能直接計算出對應的記憶體位址,而是需要根據指標乙個結點乙個結點依次遍歷,直到找到相應的結點,需要o(n)的時間複雜度

乙個特殊的單鏈表,與單鏈表的唯一區別是在尾結點,迴圈鍊錶的尾結點是指向鍊錶的頭結點

優點是從鏈尾到鏈頭比較方便,當要處理的資料具有環形結構特點的時候,採用迴圈鍊錶,比如約瑟夫問題

支援兩個方向,每個結點不止有乙個後繼指標next指向後面的結點,還有乙個前驅指標prev指向前面的結點

雙向鍊錶支援o(1)時間複雜度的情況下找到前驅結點

刪除操作:刪除結點中「值等於某個給定值」的結點和刪除給定指標指向的結點,第一種情況單鏈表和雙向鍊錶為了查詢到值等於給定值的結點都需要從頭結點開始乙個乙個依次遍歷對比,直到找到值等於給定值的結點,再進行刪除,耗時的時間複雜度總共是o(n)。第二章情況,已經找到了要刪除的結點,但是刪除某個結點q需要知道其前驅結點,單鏈表得從頭結點開始遍歷鍊錶找到前驅結點,雙向鍊錶只需要在o(1)的時間複雜度內搞定

除了插入、刪除操作雙向鍊錶有優勢外,作為乙個有序鍊錶,雙向鍊錶的按值查詢的效率也高,我們可以記錄上次查詢的位置p,每次查詢時,根據要查詢的值與p的大小比較,所以平均只需要查詢一半的資料

快取實際上就是利用了空間換時間的設計思想,我們可以通過快取技術,事先將資料載入在記憶體中,雖然比較浪費記憶體空間,但是每次資料查詢的速度大大提高。

對於執行比較慢的程式,可以通過消耗更多的記憶體(空間換時間)來進行優化

陣列和鍊錶相比並不能侷限於時間複雜度,陣列簡單易用,在實現上使用的是連續的記憶體空間,可以借助cpu的快取機制,預讀陣列中的資料,所以訪問效率更高,鍊錶在記憶體中並不是連續儲存,對cpu快取並不友好,沒辦法有效預讀

鍊錶本身沒有大小的限制,天然支援動態擴容,是與陣列的最大的區別

乙個有序單鏈表,越靠近鍊錶尾部的結點是越早之前訪問的,當有乙個新的資料被訪問時,我們從煉表頭開始順序遍歷鍊錶

1.如果此資料之前已經被快取在鍊錶中,我們遍歷得到這個資料對應的結點,並將其從原來的位置刪除,然後再插入到鍊錶的頭部

2.如果此資料沒有快取鍊錶中,又可以分為兩種情況:

①此時快取未滿,則將此結點直接插入到鍊錶的頭部;

②此時快取已滿,則鍊錶尾結點刪除,將新的資料結點插入鍊錶的頭部

實現了乙個lru快取

快取訪問的時間複雜度是o(n),如果引入雜湊表來記錄每個資料的位置,將快取訪問的時間複雜度降到o(1)

如果字串是通過單鏈表來儲存的,如何判斷是乙個回文串?

使用快慢兩個指標找到鍊錶中點,慢指標每次前進一步,快指標每次前進兩步,快指標到達終點的時候,慢指標的位置就是鍊錶中間結點,迴圈次數為鍊錶除去中間結點後前後兩組的長度,求得單向鍊錶中間結點,並計算遍歷次數,遍歷次數就是半鍊錶長度,在慢指標前進的過程中,同時修改其next指標,使得鍊錶前半部分反序,最後比較中點兩側的鍊錶是否相等

快慢指標定位中間結點,從中間結點對後半部分逆序,前後半部分比較,判斷是否回文,後半部分逆序復原

看記憶體消耗多少,空間複雜度是o(1)

#include #include #define n 100

int main()

;int i = 0;

int len = 0;

printf("please input character string:\n");

gets(a);

len = strlen(a); //計算輸入字串的長度;

for(i = 0; i < (len / 2); i++) //只需要判斷前一半(len/2)長度就好了

}printf("是回文數\n");

return 0;

}

鍊錶 如何實現LRU快取淘汰演算法

一 什麼是鍊錶?和陣列一樣,鍊錶也是一種線性表。從記憶體結構來看,鍊錶的記憶體結構是不連續的記憶體空間,是將一組零散的記憶體塊串聯起來,從而進行資料儲存的資料結構。二 為什麼使用鍊錶?即鍊錶的特點 三 常用鍊錶 單鏈表 迴圈鍊錶和雙向鍊錶 四 選擇陣列還是鍊錶?五 應用 如何分別用鍊錶和陣列實現lr...

鍊錶(上) 如何實現LRU快取淘汰演算法

鍊錶是一種最基礎的資料結構,學習鍊錶有什麼用?為了回答這個問題,先來討論乙個經典的鍊錶應用場景,那就是 lru 快取淘汰演算法。快取是一種提高資料讀取效能的技術,在硬體設計 軟體開發中都有著非常廣泛的應用,比如常見的 cpu 快取 資料庫快取 瀏覽器快取等等。快取的大小有限,當快取被用滿時,哪些資料...

06 鍊錶(上) 如何實現LRU快取淘汰演算法

我們先來討論乙個經典的鍊錶應用場景,那就是 lru 快取淘汰演算法。快取的大小有限,當快取被用滿時,哪些資料應該被清理出去,哪些資料應該被保留?這就需要快取淘汰策略來決定。常見的策略有三種 先進先出策略 fifo first in,first out 最少使用策略 lfu least frequen...