1. 程式人生 > >每天一點點之資料結構與演算法 - 應用 - 分別用連結串列和陣列實現LRU緩衝淘汰策略

每天一點點之資料結構與演算法 - 應用 - 分別用連結串列和陣列實現LRU緩衝淘汰策略

一、基本概念:

1、什麼是快取?

快取是一種提高資料讀取效能的技術,在硬體設計、軟體開發中都有著非廣泛的應用,比如常見的CPU快取、資料庫快取、瀏覽器快取等等。   2、為什麼使用快取?即快取的特點
快取的大小是有限的,當快取被用滿時,哪些資料應該被清理出去,哪些資料應該被保留?就需要用到快取淘汰策略。   3、 什麼是快取淘汰策略? 指的是當快取被用滿時清理資料的優先順序。
  4、有哪些快取淘汰策略?
常見的3種包括先進先出策略FIFO(First In,First Out)、最少使用策略LFU(Least Frenquently Used)、最近最少使用策略LRU(Least Recently Used)。
 

二、實現LRU快取淘汰策略

1、連結串列實現LRU快取淘汰策略
 

我的思路是這樣的:我們維護一個有序單鏈表,越靠近連結串列尾部的結點是越早之前訪問的。當有一個新的資料被訪問時,我們從連結串列頭開始順序遍歷連結串列。
1) 如果此資料之前已經被快取在連結串列中了,我們遍歷得到這個資料對應的結點,並將其從原來的位置刪除,然後再插入到連結串列的頭部。

2)如果此資料沒有在快取連結串列中,又可以分為兩種情況:

  • 如果此時快取未滿,則將此結點直接插入到連結串列的頭部;
  • 如果此時快取已滿,則連結串列尾結點刪除,將新的資料結點插入連結串列的頭部。

這樣我們就用連結串列實現了一個 LRU 快取,是不是很簡單?

現在我們來看下 m 快取訪問的時間複雜度是多少。因為不管快取有沒有滿,我們都需要遍歷一遍連結串列,所以這種基於連結串列的實現思路,快取訪問的時間複雜度為 O(n)。

實際上,我們可以繼續優化這個實現思路,比如引入(Hash table)來記錄每個資料的位置,將快取訪問的時間複雜度降到 O(1)。

 

 

2、陣列實現LRU快取淘汰策略
方式一:首位置儲存最新訪問資料,末尾位置優先清理
當訪問的資料未存在於快取的陣列中時,直接將資料插入陣列第一個元素位置,此時陣列所有元素需要向後移動1個位置,時間複雜度為O(n);當訪問的資料存在於快取的陣列中時,查詢到資料並將其插入陣列的第一個位置,此時亦需移動陣列元素,時間複雜度為O(n)。快取用滿時,則清理掉末尾的資料,時間複雜度為O(1)。
  方式二:首位置優先清理,末尾位置儲存最新訪問資料
當訪問的資料未存在於快取的陣列中時,直接將資料新增進陣列作為當前最有一個元素時間複雜度為O(1);當訪問的資料存在於快取的陣列中時,查詢到資料並將其插入當前陣列最後一個元素的位置,此時亦需移動陣列元素,時間複雜度為O(n)。快取用滿時,則清理掉陣列首位置的元素,且剩餘陣列元素需整體前移一位,時間複雜度為O(n)。(優化:清理的時候可以考慮一次性清理一定數量,從而降低清理次數,提高效能。)