標籤:依次 根據 需要 移動 erase iostream == capacity 表頭
前言
這兩天碰到面試題,說是頁面調度演算法,之前在作業系統書上有瞭解過,LRU(近期最少使用),還有OPT(最佳頁面替換演算法)、FIFO(先進先出頁面置換演算法),今天先來實現LRU 最近最少使用。
LRU 原理
LRU(Least recently used,最近最少使用)演算法根據資料的曆史訪問記錄來進行淘汰資料,其核心思想是“如果資料最近被訪問過,那麼將來被訪問的幾率也更高”。
參照網上的寫法,給出以下例子做個參考:
1 #include <iostream> 2 #include <unordered_map> 3 #include <list> 4 #include <utility> 5 using namespace std; 6 using namespace stdext; 7 8 class LRUCache { 9 public:10 LRUCache(int capacity) {11 m_capacity = capacity;12 }13 14 int get(int key) {15 int retValue = -1;16 unordered_map<int, list<pair<int, int> > ::iterator> ::iterator it = cachesMap.find(key);17 18 //如果在Cashe中,將記錄移動到鏈表的最前端 19 if (it != cachesMap.end())20 {21 retValue = it->second->second;22 //移動到最前端 23 list<pair<int, int> > ::iterator ptrPair = it->second;24 pair<int, int> tmpPair = *ptrPair;25 caches.erase(ptrPair++);26 caches.push_front(tmpPair);27 28 29 //修改map中的值 30 cachesMap[key] = caches.begin();31 }32 return retValue;33 }34 35 void set(int key, int value) {36 37 unordered_map<int, list<pair<int, int> > ::iterator> ::iterator it = cachesMap.find(key);38 39 if (it != cachesMap.end()) //已經存在其中 40 {41 list<pair<int, int> > ::iterator ptrPait = it->second;42 ptrPait->second = value;43 //移動到最前面 44 pair<int, int > tmpPair = *ptrPait;45 caches.erase(ptrPait);46 caches.push_front(tmpPair);47 48 49 //更新map 50 cachesMap[key] = caches.begin();51 }52 else //不存在其中 53 {54 pair<int, int > tmpPair = make_pair(key, value);55 56 57 if (m_capacity == caches.size()) //已經滿 58 {59 int delKey = caches.back().first;60 caches.pop_back(); //刪除最後一個 61 62 63 //刪除在map中的相應項 64 unordered_map<int, list<pair<int, int> > ::iterator> ::iterator delIt = cachesMap.find(delKey);65 cachesMap.erase(delIt++);66 }67 68 69 caches.push_front(tmpPair);70 cachesMap[key] = caches.begin(); //更新map 71 }72 }73 74 75 private:76 int m_capacity; //cashe的大小 77 list<pair<int, int> > caches; //用一個雙鏈表格儲存體cashe的內容 78 unordered_map< int, list<pair<int, int> > ::iterator> cachesMap; //使用map加快尋找的速度 79 };80 81 82 int main(int argc, char **argv)83 {84 LRUCache s(2);85 s.set(2, 1);86 s.set(1, 1);87 cout << s.get(2) << endl;88 s.set(4, 1);89 s.set(5, 2);90 cout << s.get(5) << endl;91 cout << s.get(4) << endl;92 getchar();93 return 0;94 }
在vs 2015 進行運行 ,輸出:
解釋:程式首先會初始化2個儲存空間的LRUCache類,依次插進{2, 1 },{1,1} ,之後輸出 key=2 => value=1 ,之後插進 {4, 1} , 因為已經滿了所以替換掉最近沒有使用的{1 ,1} ,變成了 { 4,1} ,{2,1} ,之後又插進{5, 2} ,又替換掉了 {2,1} ,變成了 {4, 1} ,{5,2},然後輸出剩下兩個key,再重新排序誰最近使用過。
用到的知識是 : 雙鏈表 + 雜湊表 (使用map,內部元素自動排序;使用unordered_map內部不會進行有序排序)
頁面調度演算法(LRU)的原理 :緩衝機制中新資料或擊中的資料放到鏈表頭部,表示最近使用的資料,如果鏈表滿,從尾部淘汰資料。但只用鏈表會存在一個問題,擊中資料的時間複雜度為O(n),每次需要遍曆鏈表,所以引入雜湊表,時間複雜度降到O(1),以空間換時間。
LRU (近期最少使用)演算法 c++實現