O(1)時(shí)間復(fù)雜度內(nèi)實(shí)現(xiàn)LRU簡(jiǎn)單算法

LRU算法

LRU(Least Recently Used),即最近最少使用算法。常用于實(shí)現(xiàn)一個(gè)簡(jiǎn)單的緩存功能颤陶,就是把很久未使用的直接移除掉幔托,只保留最近使用的穴亏。

LRU主要功能

LRU主要需要實(shí)現(xiàn)兩個(gè)功能

  • 添加緩存(涉及到刪除緩存)
  • 獲取緩存

實(shí)現(xiàn)原理

其實(shí)用一個(gè)單鏈表就能實(shí)現(xiàn)簡(jiǎn)單的LRU算法蜂挪,但是鏈表的查找時(shí)間復(fù)雜度比較高了,是O(n)嗓化。其實(shí)用一個(gè)散列表+雙鏈表就可以實(shí)現(xiàn)一個(gè)O(1)復(fù)雜度的LRU算法棠涮。用散列表就可以直接定位某個(gè)緩存,時(shí)間復(fù)雜度O(1)刺覆,但是散列表插入緩存之后严肪,就沒有了順序,所以才需要一個(gè)鏈表來維護(hù)這個(gè)緩存的順序隅津,這樣才能知道哪些緩存一直未使用诬垂,超過緩存最大容量之后需要?jiǎng)h除未使用的緩存。而如果單鏈表刪除某個(gè)緩存的話伦仍,又需要先遍歷這個(gè)元素(時(shí)間復(fù)雜度O(n))才行结窘。所以這里用雙鏈表,那么就可以通過散列表直接定位到這個(gè)緩存節(jié)點(diǎn)充蓝,然后知道這個(gè)緩存節(jié)點(diǎn)的前驅(qū)和后繼節(jié)點(diǎn)就可以在O(1)時(shí)間復(fù)雜度內(nèi)刪除這個(gè)緩存了隧枫。

show me your code

package com.program;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * LRUCache算法:最近最少使用算法
 * 核心算法實(shí)現(xiàn):散列表+雙向鏈表
 * 算法核心功能:
 * 1.添加緩存(先判斷散列表中是否存在該緩存,如果存在谓苟,則將該緩存移動(dòng)到鏈尾官脓。
 * 如果不存在,則先判斷鏈表是否已經(jīng)滿了涝焙,如果滿了則先把頭結(jié)點(diǎn)刪除卑笨,未滿則直接插到鏈尾)
 * 2.查找緩存(因?yàn)槭巧⒘斜恚詴r(shí)間復(fù)雜度仑撞,接近O(1))
 * 3.刪除緩存
 */
public class LRUCache {
    private int cacheSize = 10;
    private HashMap<String, Node> map = new HashMap<>();
    private Node head;
    private Node tail;

    public void LRUCache(int cacheSize) {
        this.cacheSize = cacheSize;
    }

    /**
     * 添加緩存
     * 先判斷是否已有該緩存赤兴,如果有則直接放到鏈尾取出,
     * 如果沒有隧哮,則判斷是否已滿桶良,如果滿了,刪除鏈頭數(shù)據(jù)沮翔,否則直接插到鏈尾
     */
    public void addCache(String key, String value) {
        if (map.containsKey(key)) {
            Node node = map.get(key);
            if (node.next != null) {
                if (node.pre == null) {
                    head = node.next;
                } else {
                    node.pre.next = node.next;
                    node.next.pre = node.pre;
                }
                tail.next = node;
                node.pre = tail;
                node.next = null;
                tail = node;
            }
        } else {
            Node node = new Node(key, value);
            if (map.size() == cacheSize) {
                Node temp = head;
                head = head.next;
                map.remove(temp.key);
                node.pre = tail;
                tail.next = node;
                tail = node;
            } else {
                if (head == null) {
                    head = node;
                    tail = node;
                } else {
                    node.pre = tail;
                    tail.next = node;
                    tail = node;
                }
            }
            map.put(key, node);
        }
    }

    /**
     * 獲取緩存
     * 先判斷是否有緩存陨帆,如果有,需要把該緩存移動(dòng)到鏈尾返回
     */
    public String getCache(String key) {
        if (map.containsKey(key)) {
            Node node = map.get(key);
            if (node.next == null) {
                return node.value;
            }
            if (node.pre == null) {
                head = node.next;
            } else {
                node.pre.next = node.next;
                node.next.pre = node.pre;
            }
            tail.next = node;
            node.pre = tail;
            node.next = null;
            tail = node;
            return node.value;
        } else {
            return null;
        }
    }

    public void test() {
        Iterator<Map.Entry<String, Node>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Node> entry = iterator.next();
            System.out.println(entry.getKey() + "--" + entry.getValue().value);
        }
    }

    public void test2() {
        Node temp = head;
        while (temp != null) {
            System.out.println(temp.key);
            temp = temp.next;
        }
    }

    public static void main(String[] args) {
        LRUCache cache = new LRUCache();
        cache.addCache("key0", "value0");
        cache.addCache("key1", "value1");
        cache.addCache("key2", "value2");
        cache.addCache("key3", "value3");
        cache.addCache("key4", "value4");
        cache.addCache("key5", "value5");
        cache.addCache("key6", "value6");
        cache.addCache("key7", "value7");
        cache.addCache("key8", "value8");
        cache.addCache("key9", "value9");
        cache.getCache("key9");
        cache.test2();
    }

    class Node {
        String key;
        String value;
        Node pre;
        Node next;

        public Node(String key, String value) {
            this.key = key;
            this.value = value;
        }
    }
}

免責(zé)聲明:代碼未經(jīng)充分測(cè)試采蚀,如果發(fā)現(xiàn)問題還請(qǐng)不吝賜教疲牵,謝謝。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末榆鼠,一起剝皮案震驚了整個(gè)濱河市瑰步,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌璧眠,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異责静,居然都是意外死亡袁滥,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門灾螃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來题翻,“玉大人,你說我怎么就攤上這事腰鬼∏对” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵熄赡,是天一觀的道長(zhǎng)姜挺。 經(jīng)常有香客問我,道長(zhǎng)彼硫,這世上最難降的妖魔是什么炊豪? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮拧篮,結(jié)果婚禮上词渤,老公的妹妹穿的比我還像新娘。我一直安慰自己串绩,他們只是感情好缺虐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著礁凡,像睡著了一般高氮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上把篓,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天纫溃,我揣著相機(jī)與錄音,去河邊找鬼韧掩。 笑死紊浩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疗锐。 我是一名探鬼主播坊谁,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼滑臊!你這毒婦竟也來了口芍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤雇卷,失蹤者是張志新(化名)和其女友劉穎鬓椭,沒想到半個(gè)月后颠猴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡小染,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年翘瓮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裤翩。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡资盅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出踊赠,到底是詐尸還是另有隱情呵扛,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布筐带,位于F島的核電站今穿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏烫堤。R本人自食惡果不足惜荣赶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鸽斟。 院中可真熱鬧拔创,春花似錦、人聲如沸富蓄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)立倍。三九已至灭红,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間口注,已是汗流浹背变擒。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寝志,地道東北人娇斑。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像材部,于是被迫代替她去往敵國(guó)和親毫缆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

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