LRU Cache 的原理及簡(jiǎn)單實(shí)現(xiàn)

LRU(Least Recently Used)是一種緩存淘汰算法,當(dāng)未命中時(shí)梨撞,將最近最少使用(即上一次使用的時(shí)間離現(xiàn)在最久)的塊置換出去來(lái)加載新塊雹洗。

例如,以下塊的訪問(wèn)順序?yàn)?A B C D E D F:

一旦 A B C D 被放置在緩存中(每個(gè)新訪問(wèn)增量為 1)卧波,而后又訪問(wèn) E 沒(méi)有命中队伟,需要將其替換進(jìn)其中一個(gè)塊中。根據(jù) LRU 算法幽勒,由于 A 具有最低的時(shí)間記錄 A(0),E 將取代 A港令。

算法需要跟蹤何時(shí)最近一次使用了各個(gè)塊啥容,這個(gè)代價(jià)是昂貴的。實(shí)際上只要維持被訪問(wèn)的順序就可以了顷霹,而不必知道確切的時(shí)間記錄咪惠。我們可以用 STL 中的雙向鏈表來(lái)實(shí)現(xiàn)這樣一個(gè)功能。

題目參考 Leetcode 146淋淀。

實(shí)現(xiàn) get 和 put 兩種方法遥昧,其中:

  • get(key) 返回 key 對(duì)應(yīng)的 value(保證大于 0),如果沒(méi)有則返回 -1朵纷。
  • put(key, value) 無(wú)返回值炭臭,若命中,將其 value 置為新值袍辞;若未命中鞋仍,但 capacity 大于當(dāng)前已存塊數(shù),直接插入搅吁;若未命中且數(shù)量已達(dá) capacity威创,執(zhí)行 LRU 算法進(jìn)行替換落午。

借助 list 來(lái)記錄塊的使用情況,每一個(gè)新加入或命中的塊都被放到頭部肚豺,未命中時(shí)被替換掉的一定是位于尾部的節(jié)點(diǎn)溃斋。用一個(gè) unordered_map 來(lái)存儲(chǔ) key 對(duì)應(yīng)的 value 和在 list 中的位置(因?yàn)閷?duì) list 迭代器的刪除操作不會(huì)導(dǎo)致其他迭代器失效),每次操作后都需要更新存儲(chǔ)的 list 迭代器吸申。

代碼如下梗劫,具體細(xì)節(jié)參照注釋?zhuān)?/p>

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int value_1 = obj.get(key);
 * obj.put(key,value);
 */

class LRUCache {
public:
    LRUCache(int capacity) {
        cap = capacity;
        cache.reserve(cap);    // 預(yù)留 capacity 大小的空間
    }
    
    int get(int key) {
        auto iter = cache.find(key);
        if(iter != cache.end()) {    // 若命中
            touch(iter);    // 更新節(jié)點(diǎn)記錄
            return iter->second.first;    // 返回 value 值
        }
        return -1;    // 未獲取到返回 -1
    }
    
    void put(int key, int value) {
        auto iter = cache.find(key);
        if(iter == cache.end()) {    // 未命中
            if(cache.size() == cap) {    // cache 已滿(mǎn)
                cache.erase(data.back());    // 從 cache 中刪除位于 list 末尾的 key
                data.pop_back();    // 從 data 中彈出位于 list 末尾的 key
            }
            
            data.push_front(key);    // cache 無(wú)論滿(mǎn)不滿(mǎn)都需要,從頭部加入新的 key呛谜,更新時(shí)間順序記錄
        }
        else {    // 命中
            touch(iter);    // 更新節(jié)點(diǎn)記錄
        }
        cache[key] = {value, data.begin()};    // 未命中時(shí)置新塊在跳,命中時(shí)置新值
    }
    
private:
    list<int> data;
    unordered_map<int, pair<int, list<int>::iterator>> cache;
    int cap;
    /*
    命中時(shí),將塊在 list 中原來(lái)的節(jié)點(diǎn)刪除隐岛,重新插入到頭部猫妙。
    unordered_map 中存儲(chǔ)的迭代器也需要修改。
    */
    void touch(unordered_map<int, pair<int, list<int>::iterator>>::iterator it) {
        int k = it->first;
        data.erase(it->second.second);
        data.push_front(k);
        it->second.second = data.begin();
    }
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末聚凹,一起剝皮案震驚了整個(gè)濱河市割坠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌妒牙,老刑警劉巖彼哼,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異湘今,居然都是意外死亡敢朱,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)摩瞎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拴签,“玉大人,你說(shuō)我怎么就攤上這事旗们◎玖ǎ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵上渴,是天一觀的道長(zhǎng)岸梨。 經(jīng)常有香客問(wèn)我,道長(zhǎng)稠氮,這世上最難降的妖魔是什么曹阔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮隔披,結(jié)果婚禮上次兆,老公的妹妹穿的比我還像新娘。我一直安慰自己锹锰,他們只是感情好芥炭,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布漓库。 她就那樣靜靜地躺著,像睡著了一般园蝠。 火紅的嫁衣襯著肌膚如雪渺蒿。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天彪薛,我揣著相機(jī)與錄音茂装,去河邊找鬼。 笑死善延,一個(gè)胖子當(dāng)著我的面吹牛少态,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播易遣,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼彼妻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了豆茫?” 一聲冷哼從身側(cè)響起侨歉,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎揩魂,沒(méi)想到半個(gè)月后幽邓,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡火脉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年牵舵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倦挂。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡畸颅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妒峦,到底是詐尸還是另有隱情,我是刑警寧澤兵睛,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布肯骇,位于F島的核電站,受9級(jí)特大地震影響祖很,放射性物質(zhì)發(fā)生泄漏笛丙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一假颇、第九天 我趴在偏房一處隱蔽的房頂上張望胚鸯。 院中可真熱鬧,春花似錦笨鸡、人聲如沸姜钳。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)哥桥。三九已至辙浑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拟糕,已是汗流浹背判呕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留送滞,地道東北人侠草。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像犁嗅,于是被迫代替她去往敵國(guó)和親边涕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理愧哟,服務(wù)發(fā)現(xiàn)奥吩,斷路器,智...
    卡卡羅2017閱讀 134,693評(píng)論 18 139
  • 一、基本數(shù)據(jù)類(lèi)型 注釋 單行注釋?zhuān)?/ 區(qū)域注釋?zhuān)?* */ 文檔注釋?zhuān)?** */ 數(shù)值 對(duì)于byte類(lèi)型而言...
    龍貓小爺閱讀 4,267評(píng)論 0 16
  • 生活本是美好的肥矢,陽(yáng)光多么燦爛端衰,天空多么明朗,活在世界上是多么的幸福甘改。然而旅东,人總是不能控制自己的憂(yōu)愁,不能左右自己的...
    袁謙閱讀 217評(píng)論 0 0
  • 今天一大早起來(lái)最重要的事就是上微博!找密碼忘嫉!然后關(guān)注傅園慧荤牍! 登錄了好久都不上的新浪微博,搜索傅園慧庆冕,我硬是榮幸的...
    肥魚(yú)胡說(shuō)閱讀 292評(píng)論 0 0
  • 今天是2018年4月18日康吵,對(duì)我來(lái)說(shuō),是一個(gè)值得紀(jì)念的日子访递。我們小課題組的繪本閱讀教學(xué)開(kāi)始試講了晦嵌。這是我們...
    瀾書(shū)童閱讀 3,308評(píng)論 1 2