什麼是LRU
LRU Cache是一個Cache置換演算法,含義是“最近最少使用”,當Cache滿(沒有閒置cache塊)時,把滿足“最近最少使用”的資料從Cache中置換出去,並且保證Cache中第一個資料是最近剛剛訪問的。由“局部性原理”,這樣的資料更有可能被接下來的程式訪問。 LRU基本演算法 要求 提供兩個介面:一個擷取資料int get(int key),一個寫入資料void set(int key, int value)。 無論擷取資料還是寫入資料,這個資料要保持在最容易訪問的位置。 緩衝的資料大小有限,當緩衝滿時置換出最長時間沒有被訪問的資料,否則直接把資料加入緩衝即可。 演算法
使用list來儲存快取資料的訪問序列,頭指標指向剛剛訪問過的資料。
使用map儲存資料的key和資料所在鏈表中的位置。map主要用於加速尋找(log(n)的時間複雜度)。
每次擷取資料時,遍曆map判斷資料(使用資料的key)是否在緩衝中,在則返回資料(存在則通過資料所在鏈表中的位置返回資料值);不在則返回-1。
每次寫入新的資料時,可能有三種情況: 資料已在緩衝中
遍曆map判斷資料是否已在緩衝中,在則更新資料值,共置資料緩衝在鏈表頭。 資料不在緩衝中,緩衝已滿
剔除掉鏈表末尾的資料和map指定的資料key,並把新的資料加入到緩衝鏈表的頭,並更新map; 資料不在緩衝中,緩衝未滿
直接把新的資料加入到緩衝鏈表的頭,並更新map。 LRU實現
實現方案:使用stl的map和list
這裡map使用unordered_map(hashmap)+list(雙向鏈表),因此本質上使用hashmap和雙向鏈表
class LRUCache{ int m_capacity; unordered_map<int, list<pair<int, int>>::iterator> m_map; //m_map_iter->first: key, m_map_iter->second: list iterator; list<pair<int, int>> m_list; //m_list_iter->first: key, m_list_iter->second: value;public: LRUCache(int capacity): m_capacity(capacity) { } int get(int key) { auto found_iter = m_map.find(key); if (found_iter == m_map.end()) //key doesn't exist return -1; m_list.splice(m_list.begin(), m_list, found_iter->second); //move the node corresponding to key to front return found_iter->second->second; //return value of the node } void set(int key, int value) { auto found_iter = m_map.find(key); if (found_iter != m_map.end()) //key exists { m_list.splice(m_list.begin(), m_list, found_iter->second); //move the node corresponding to key to front found_iter->second->second = value; //update value of the node return; } if (m_map.size() == m_capacity) //reached capacity { int key_to_del = m_list.back().first; m_list.pop_back(); //remove node in list; m_map.erase(key_to_del); //remove key in map } m_list.emplace_front(key, value); //create new node in list m_map[key] = m_list.begin(); //create correspondence between key and node }};