LRU算法

LRU算法介紹

眾所周知,操作系統(tǒng)緩存是有限的,當緩存快要耗盡的時候冤灾,我們就需要對已經(jīng)存在的頁面進行置換。記得在大二學習操作系統(tǒng)的時候介紹過幾個緩存策略辕近,分別是OPT韵吨,F(xiàn)IFO,LRU移宅,Clock归粉,LFU。我們本文簡單介紹一下LRU算法的實現(xiàn)漏峰。

LRU算法實現(xiàn)

實現(xiàn)簡介

我在網(wǎng)上搜索LRU算法的時候看到leetcode一道題目糠悼,這里我以leetcode 146一套題目為例,講解LRU算法的實現(xiàn)浅乔。我使用的語言是C++绢掰,如果你熟悉C++的話用LinkedList+map,Java的話有現(xiàn)成的數(shù)據(jù)結構即LinkedHashMap

實現(xiàn)思路

實現(xiàn)主要使用的數(shù)據(jù)結構是LinkedList + map(即鏈表+哈希表)滴劲。實現(xiàn)主要的函數(shù)是initgetput顾复。init函數(shù)負責初始化班挖,其中包括cache大小的設置等;get函數(shù)負責獲取緩存中的對于的頁面芯砸。put函數(shù)負責將新的頁面插入緩存中萧芙。下面我具體介紹一下這三個函數(shù)的具體實現(xiàn)。

  1. init函數(shù)中假丧,我們初始化一個LinkedList = NULL;双揪,同時初始化這個cache的大小capacity和現(xiàn)在的頁面數(shù)count
  2. get函數(shù)中包帚,我們根據(jù)key到hash表中去查詢有沒有對應的節(jié)點渔期,如果存在,將這個節(jié)點摘出來渴邦,放在鏈表最頭部的位置疯趟。這里摘出來有個小技巧,我們可以將這個節(jié)點和他后面的幾點數(shù)據(jù)互換谋梭,然后刪除后面的節(jié)點信峻。如圖
RemoveNode
  1. put函數(shù)中,我們先查詢這個節(jié)點是不是存在瓮床,如果存在盹舞,根據(jù)value生成新的節(jié)點,存在map中隘庄,替換原來的節(jié)點踢步,并且push到鏈表的頭部。如果不存在峭沦,直接生成新節(jié)點贾虽,存入map,并push到鏈表頭部吼鱼。

實現(xiàn)代碼

//
//  main.cpp
//  LRU_Demo
//
//  Created by 李林 on 2017/9/14.
//  Copyright ? 2017年 lee. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <iterator>
using namespace std;

/*
 核心思想:map+List蓬豁。類似于Java中LinkedHashMap。
 map變化和List變化需要同步菇肃,查詢運用map優(yōu)勢地粪,增減運用List優(yōu)勢。
 */

struct Node {
    int key;
    int val;
    Node *next;
    Node(int k, int v) : key(k), val(v), next(NULL) {
    }
};

class LRUCache {
public:
    LRUCache(int capacity) {
        count = 0;
        size = capacity;
        cacheList = NULL;
    }
    
    int get(int key) {
        if (cacheList == NULL)  return -1;
        
        map<int, Node *>::iterator it = mp.find(key);
        if (it == mp.end()) {
            return -1;
        } else {
            Node *newNode = it->second;
            pushNewNodeToFront(newNode);
            return cacheList->val;
        }
    }
    
    void put(int key, int val) {
        if (cacheList == NULL) {
            cacheList = new Node(key, val);
            cacheList->next = NULL;
            mp[key] = cacheList;
            count++;
        } else {
            map<int, Node *>::iterator it = mp.find(key);
            if (it == mp.end()) {       // 沒有這個key
                
                if (count == size) {
                    Node *p = cacheList;
                    Node *pre = p;
                    
                    while (p->next != NULL) {
                        pre = p;
                        p = p->next;
                    }
                    
                    mp.erase(p->key);
                    count--;
                    if (pre == p) {     // 只有一個節(jié)點
                        cacheList = NULL;
                    } else {
                        pre->next = NULL;
                    }
                    free(p);
                }
                
                Node *newNode = new Node(key, val);
                newNode->next = cacheList;
                cacheList = newNode;
                mp[key] = cacheList;
                count++;
            } else {                    // 有這個key
                Node *newNode = it->second;
                newNode->val = val;
                pushNewNodeToFront(newNode);
            }
        }
    }
    
    void pushNewNodeToFront(Node *newNode) {
        if (count == 1) return ;
        if (newNode == cacheList) return ;
        
        Node *Next = newNode->next;
        if (Next) {
            newNode->next = Next->next;
            swap(newNode->key, Next->key);
            swap(newNode->val, Next->val);
            Next->next = cacheList;
            cacheList = Next;
            
            // 勿忘map操作
            swap(mp[newNode->key], mp[Next->key]);
        } else {                        // 最后一個節(jié)點
            Node *p = cacheList;
            while (p->next != newNode) {
                p = p->next;
            }
            p->next = NULL;
            
            newNode->next = cacheList;
            cacheList = newNode;
        }
    }
    
private:
    int count;
    int size;
    Node *cacheList;
    map<int, Node*> mp;
};

int main(int argc, const char * argv[]) {
    
    LRUCache cache(2);
    
    cache.put(1, 1);
    cache.put(2, 2);
    cout<<cache.get(1)<<endl;       // returns 1
    cache.put(3, 3);    // evicts key 2
    cout<<cache.get(2)<<endl;       // returns -1 (not found)
    cache.put(4, 4);    // evicts key 1
    cout<<cache.get(1)<<endl;       // returns -1 (not found)
    cout<<cache.get(3)<<endl;       // returns 3
    cout<<cache.get(4)<<endl;       // returns 4
    return 0;
}

運行結果

運行的結果是1琐谤,-1蟆技,-1,3,4质礼。(-1代表未命中)

運行結果

參考文章

LRU wikidepia
CSDN 博客

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末旺聚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子眶蕉,更是在濱河造成了極大的恐慌砰粹,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件造挽,死亡現(xiàn)場離奇詭異碱璃,居然都是意外死亡,警方通過查閱死者的電腦和手機饭入,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門嵌器,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谐丢,你說我怎么就攤上這事爽航。” “怎么了庇谆?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵岳掐,是天一觀的道長。 經(jīng)常有香客問我饭耳,道長串述,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任寞肖,我火速辦了婚禮纲酗,結果婚禮上,老公的妹妹穿的比我還像新娘新蟆。我一直安慰自己觅赊,他們只是感情好,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布琼稻。 她就那樣靜靜地躺著吮螺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帕翻。 梳的紋絲不亂的頭發(fā)上鸠补,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音嘀掸,去河邊找鬼紫岩。 笑死,一個胖子當著我的面吹牛睬塌,可吹牛的內容都是我干的泉蝌。 我是一名探鬼主播歇万,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼勋陪!你這毒婦竟也來了贪磺?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤诅愚,失蹤者是張志新(化名)和其女友劉穎缘挽,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呻粹,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年苏研,在試婚紗的時候發(fā)現(xiàn)自己被綠了等浊。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡摹蘑,死狀恐怖筹燕,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情衅鹿,我是刑警寧澤撒踪,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站大渤,受9級特大地震影響制妄,放射性物質發(fā)生泄漏。R本人自食惡果不足惜泵三,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一耕捞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烫幕,春花似錦俺抽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捷犹,卻和暖如春弛饭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伏恐。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工孩哑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翠桦。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓横蜒,卻偏偏與公主長得像胳蛮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子丛晌,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內容

  • 1. LRU 1.1.原理 LRU(Leastrecentlyused仅炊,最近最少使用)算法根據(jù)數(shù)據(jù)的歷史訪問記錄來...
    安易學車閱讀 2,520評論 0 23
  • 1. LRU 1.1. 原理LRU(Least recently used,最近最少使用)算法根據(jù)數(shù)據(jù)的歷史訪問記...
    AKyS佐毅閱讀 2,153評論 0 3
  • 緩存淘汰算法--LRU算法 1. LRU 1.1 原理 LRU(Least recently used澎蛛,)算法根據(jù)...
    白公子是貓奴閱讀 476評論 0 0
  • LRU原理 LRU(Least recently used抚垄,最近最少使用)算法根據(jù)數(shù)據(jù)的歷史訪問記錄來進行淘汰數(shù)據(jù)...
    jiangmo閱讀 60,202評論 3 30
  • LRU(Least Recently Used)即最近最少使用算法,在操作系統(tǒng)內存管理中谋逻,有一類很重要的算法就是內...
    狗尾巴草敗了閱讀 462評論 0 0