簡單的LRU Cache設計與實現

2022-04-07 16:09:43 字數 2710 閱讀 3669

要求:

設計並實現乙個lru快取的資料結構,支援get和set操作

get(key):若快取中存在key,返回對應的value,否則返回-1

set(key,value):若快取中存在key,替換其value,否則插入key及其value,如果插入時快取已經滿了,應該使用lru演算法把最近最久沒有使用的key踢出快取。

設計1:

cache使用陣列,每個key再關聯乙個時間戳,時間戳可以直接用個long long型別表示,在cache中維護乙個最大的時間戳:

分析下時間空間複雜度,get的時候,需要從前往後找key,時間為o(n),set的時候,也要從前往後找key,當快取滿的時候,還得找到時間戳最小的key,時間複雜度為o(n)。除了快取本身,並沒有使用其他空間,空間複雜度為o(1)。 這個速度顯然是比較慢的,隨著資料量的增大,get和set速度越來越慢。可能有人會想到用雜湊表作為底層儲存,這樣get的時間複雜度確實可以減低為o(1),set的時候,只要快取沒有滿,也可以在o(1)的時間完,但在快取滿的時候,依然需要每次遍歷找時間戳最小的key,時間複雜度還是o(n)。

設計2:

cache底層使用單鏈表,同時用乙個雜湊表儲存每個key對應的鍊錶結點的前驅結點,並記錄鍊錶尾結點的key

get,set時間複雜度o(1),總的空間複雜度o(n)。比前面的設計好一點。下面的再來看下關於設計2的兩個實現

實現1,自定義鍊錶

為了方便鍊錶的插入與刪除,使用了帶頭結點head的鍊錶,所以真正有效的第乙個結點是head->next。另外,只是簡單的實現,沒有容錯,不支援併發,簡單的記憶體管理

ps. 用雙向鍊錶來實現會簡單寫,這裡用單鏈表和雜湊表共同實現了雙向鍊錶的功效,也就是雜湊除了用來查詢,還指示了key對應的結點的前驅結點。

struct

node

};class

lrucache

~lrucache()

free(_begin);//

再釋放記憶體

} }

intget(int

key)

node->_next = _head->_next;

if(node->_next!=null)

_head->_next =node;

umap_prenodes[key] =_head;

/*更新_last

*/if(_last ==key )

value = node->_value;

}return

value;

}void

set(int key, int

value)

node->_value = value; //

重置結點值

/*更新_last

*/if(_last ==key )

}else

if(_size == _capacity)

else}}

/*把node插入到第乙個結點的位置

*/node->_next = _head->_next;

if(node->_next!=null)

_head->_next =node;

umap_prenodes[key] =_head;

}private

:

int_size;

int_capacity;

int _last;//

_last是鍊錶中最後乙個結點的key

node*_head;

unordered_map

umap_prenodes;//

儲存key對應的結點的前驅結點,鍊錶中第乙個結點的前驅結點為_head

char* _begin;//

快取的起始位置

char* _cur_begin;//

用於分配結點記憶體的起始位置

};

實現2,使用stl的list

這個版本的實現來自leetcode discuss

class

lrucache

intget(int

key)

void

set(int key, int

value)

if (m_map.size() == m_capacity) //

reached capacity

m_list.emplace_front(key, value);

//create new node in list

m_map[key] = m_list.begin(); //

create correspondence between key and node

}};

通過兩個版本的實現,可以看到,使用stl的容器**非常簡潔,但也不是說自定義鍊錶版本的實現就不好,如果從併發的角度來說,自定義的結構,在實現併發時,鎖的粒度會小一點,而直接使用stl容器,鎖的粒度為大一點,因為,使用stl,必須鎖定乙個函式,而使用自定義結構可以只鎖定某個函式內部的某些操作,而且更方便實現無鎖併發。另外,從leetcode的測試結果來看,這兩個版本的效能差不多。

LRU Cache的簡單c 實現

lru cache是乙個cache的置換演算法,含義是 最近最少使用 把滿足 最近最少使用 的資料從cache中剔除出去,並且保證cache中第乙個資料是最近剛剛訪問的,因為這樣的資料更有可能被接下來的程式所訪問。lru的應用比較廣泛,最基礎的記憶體頁置換中就用了,對了,這裡有個概念要清楚一下,ca...

LRUCache演算法的簡單實現

lru是least recently used的縮寫,意為最近最少使用演算法。lrucache是一種常用的快取替換演算法,根據使用率淘汰資料,即使用率最小的會被淘汰,通常會用乙個雙向鍊錶來實現,在這個雙向鍊錶中,如果乙個cache被命中,則將這個資料移動到鍊錶的頭部,而不經常使用的cache就會逐漸...

Arduino 簡單追光系統的猜想與簡單實現

首先,我想象的追光器大概是這樣的 哪邊有光就往那邊轉.應該是不難理解吧。獻醜了。因為缺錢缺工具,所以成品暫時還沒有做出來。大概接了線,燒了程式,大概能使,就這樣吧.這是使用1個舵機,在乙個水平方向做180度的運動,要是做成橫豎兩個方向的活動,實現的方法也是一樣的,只不過這就共需要2個舵機,4個光敏電...