0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何輕松理解「鏈表」實(shí)現(xiàn)「LRU緩存淘汰算法

電子工程師 ? 來(lái)源:lq ? 2018-12-25 10:09 ? 次閱讀

前幾節(jié)學(xué)習(xí)了「鏈表」、「時(shí)間與空間復(fù)雜度」的概念,本節(jié)將結(jié)合「循環(huán)鏈表」、「雙向鏈表」與 「用空間換時(shí)間的設(shè)計(jì)思想」來(lái)設(shè)計(jì)一個(gè)很有意思的緩存淘汰策略:LRU緩存淘汰算法

三種最常見(jiàn)的鏈表結(jié)構(gòu)

循環(huán)鏈表的概念

如上圖所示:?jiǎn)捂湵淼奈步Y(jié)點(diǎn)指針指向空地址,表示這就是最后的結(jié)點(diǎn)了。而循環(huán)鏈表的尾結(jié)點(diǎn)指針是指向鏈表的頭結(jié)點(diǎn)。

因此循環(huán)鏈表是一種特殊的單鏈表。它跟單鏈表唯一的區(qū)別就在于尾結(jié)點(diǎn)。它像一個(gè)環(huán)一樣首尾相連,所以叫作「循環(huán)鏈表」。

循環(huán)鏈表的特點(diǎn)

和單鏈表相比,循環(huán)鏈表的優(yōu)點(diǎn)是從鏈尾到鏈頭比較方便,當(dāng)要處理的數(shù)據(jù)具有環(huán)型結(jié)構(gòu)特點(diǎn)時(shí),適合采用循環(huán)鏈表。

雙向鏈表概念

雙向鏈表也叫雙鏈表,是鏈表的一種,它的鏈接方向是雙向的,它的每個(gè)數(shù)據(jù)結(jié)點(diǎn)中都包含有兩個(gè)指針,分別指向直接后繼和直接前驅(qū)。

所以,從雙向鏈表中的任意一個(gè)結(jié)點(diǎn)開(kāi)始,都可以很方便地訪問(wèn)它的前驅(qū)結(jié)點(diǎn)和后繼結(jié)點(diǎn)。

雙向鏈表的數(shù)據(jù)結(jié)構(gòu)中,會(huì)有兩個(gè)比較重要的參數(shù):pre 和 next。

pre 指向前一個(gè)數(shù)據(jù)結(jié)構(gòu)

next 指向下一個(gè)數(shù)據(jù)結(jié)構(gòu)

單鏈表與雙鏈表的對(duì)比

雙向鏈表的特點(diǎn)

與單鏈表對(duì)比,雙鏈表需要多一個(gè)指針用于指向前驅(qū)節(jié)點(diǎn),因此如果存儲(chǔ)同樣多的數(shù)據(jù),雙向鏈表要比單鏈表占用更多的內(nèi)存空間

雙鏈表的插入和刪除需要同時(shí)維護(hù) next 和 prev 兩個(gè)指針。

雙鏈表中的元素訪問(wèn)需要通過(guò)順序訪問(wèn),支持雙向遍歷,這就是雙向鏈表操作的靈活性根本

雙向鏈表的基本操作

1.添加元素。

與單向鏈表相對(duì)比雙向鏈表可以在 O(1) 時(shí)間復(fù)雜度搞定,而單向鏈表需要 O(n) 的時(shí)間復(fù)雜度。

雙向鏈表的添加元素包括頭插法和尾插法。

頭插法和尾插法

頭插法:將鏈表的左邊稱為鏈表頭部,右邊稱為鏈表尾部。頭插法是將右邊固定,每次新增的元素都在左邊頭部增加。

尾插法:將鏈表的左邊稱為鏈表頭部,右邊稱為鏈表尾部。尾插法是將左邊固定,每次新增都在鏈表的右邊最尾部。

2.查詢?cè)?/p>

查詢?cè)?/p>

雙向鏈表的靈活處就是知道鏈表中的一個(gè)元素結(jié)構(gòu)就可以向左或者向右開(kāi)始遍歷查找需要的元素結(jié)構(gòu)。因此對(duì)于一個(gè)有序鏈表,雙向鏈表的按值查詢的效率比單鏈表高一些。因?yàn)椋覀兛梢杂涗浬洗尾檎业奈恢?p,每次查詢時(shí),根據(jù)要查找的值與 p 的大小關(guān)系,決定是往前還是往后查找,所以平均只需要查找一半的數(shù)據(jù)。

3.刪除元素

在實(shí)際的軟件開(kāi)發(fā)中,從鏈表中刪除一個(gè)數(shù)據(jù)無(wú)外乎這兩種情況:

刪除結(jié)點(diǎn)中“值等于某個(gè)給定值”的結(jié)點(diǎn)

刪除給定指針指向的結(jié)點(diǎn)

刪除元素

對(duì)于雙向鏈表來(lái)說(shuō),雙向鏈表中的結(jié)點(diǎn)已經(jīng)保存了前驅(qū)結(jié)點(diǎn)的指針,刪除時(shí)不需要像單鏈表那樣遍歷。所以,針對(duì)第二種情況,單鏈表刪除操作需要 O(n) 的時(shí)間復(fù)雜度,而雙向鏈表只需要在 O(1) 的時(shí)間復(fù)雜度。

雙向循環(huán)鏈表

雙向循環(huán)鏈表

如圖所示,雙向循環(huán)鏈表的概念很好理解:「雙向鏈表」 + 「循環(huán)鏈表」的組合。

緩存淘汰策略

緩存是一種提高數(shù)據(jù)讀取性能的技術(shù),在硬件設(shè)計(jì)、軟件開(kāi)發(fā)中都有著非常廣泛的應(yīng)用,比如常見(jiàn)的 CPU 緩存、數(shù)據(jù)庫(kù)緩存、瀏覽器緩存等等。

緩存的大小有限,當(dāng)緩存被用滿時(shí),哪些數(shù)據(jù)應(yīng)該被清理出去,哪些數(shù)據(jù)應(yīng)該被保留?這就需要緩存淘汰策略來(lái)決定。常見(jiàn)的策略有三種:先進(jìn)先出策略 FIFO(First In,F(xiàn)irst Out)、最少使用策略 LFU(Least Frequently Used)、最近最少使用策略 LRU(Least Recently Used)。

在各個(gè)語(yǔ)言的第三方框架中都大量使用到了 LRU 緩存策略。程序員小吳接觸到的有Java中的 「 Mybatis 」,iOS中的 「YYCache」與「Lottie」等。

LRU緩存淘汰算法

LRU是最近最少使用策略的縮寫(xiě),是根據(jù)數(shù)據(jù)的歷史訪問(wèn)記錄來(lái)進(jìn)行淘汰數(shù)據(jù),其核心思想是“如果數(shù)據(jù)最近被訪問(wèn)過(guò),那么將來(lái)被訪問(wèn)的幾率也更高”。

LRU概念

鏈表實(shí)現(xiàn)LRU

將Cache的所有位置都用雙鏈表連接起來(lái),當(dāng)一個(gè)位置被命中之后,通過(guò)調(diào)整鏈表的指向,將該位置調(diào)整到鏈表頭的位置,新加入的Cache直接加到鏈表頭中。

這樣,在多次進(jìn)行Cache操作后,最近被命中的,就會(huì)被向鏈表頭方向移動(dòng),而沒(méi)有命中的,而想鏈表后面移動(dòng),鏈表尾則表示最近最少使用的Cache。

當(dāng)需要替換內(nèi)容時(shí)候,鏈表的最后位置就是最少被命中的位置,我們只需要淘汰鏈表最后的部分即可。

鏈表實(shí)現(xiàn)LRU動(dòng)畫(huà)演示

如果此數(shù)據(jù)之前已經(jīng)被緩存在鏈表中了,通過(guò)遍歷得到這個(gè)數(shù)據(jù)對(duì)應(yīng)的結(jié)點(diǎn),并將其從原來(lái)的位置刪除,然后再插入到鏈表的頭部。

如果此數(shù)據(jù)沒(méi)有在緩存鏈表中,可以分為兩種情況:

如果此時(shí)緩存未滿,則將此結(jié)點(diǎn)直接插入到鏈表的頭部;

如果此時(shí)緩存已滿,則鏈表尾結(jié)點(diǎn)刪除,將新的數(shù)據(jù)結(jié)點(diǎn)插入鏈表的頭部。

鏈表實(shí)現(xiàn)LRU

通過(guò)動(dòng)圖可以發(fā)現(xiàn),如果緩存空間足夠大,那么存儲(chǔ)的數(shù)據(jù)也就足夠多,通過(guò)緩存中命中數(shù)據(jù)的概率就越大,也就提高了代碼的執(zhí)行速度。這就是空間換時(shí)間的設(shè)計(jì)思想。

對(duì)于程序開(kāi)發(fā)來(lái)說(shuō),時(shí)間復(fù)雜度和空間復(fù)雜度是可以相互轉(zhuǎn)化的。說(shuō)通俗一點(diǎn),就是:

對(duì)于執(zhí)行的慢的程序,可以通過(guò)消耗內(nèi)存(即構(gòu)造新的數(shù)據(jù)結(jié)構(gòu))來(lái)進(jìn)行優(yōu)化;

而消耗內(nèi)存的程序,可以通過(guò)消耗時(shí)間來(lái)降低內(nèi)存的消耗。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴

原文標(biāo)題:看動(dòng)畫(huà)輕松理解「鏈表」實(shí)現(xiàn)「LRU緩存淘汰算法」

文章出處:【微信號(hào):rgznai100,微信公眾號(hào):rgznai100】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    LRU緩存模塊最佳實(shí)踐

    LRU(Least Recently Used)是一種緩存替換算法,它的核心思想是當(dāng)緩存滿時(shí),替換最近最少使用的數(shù)據(jù)。在實(shí)際應(yīng)用中,LRU
    的頭像 發(fā)表于 09-30 16:47 ?762次閱讀

    Redis的LRU實(shí)現(xiàn)和應(yīng)用

    在編程中,計(jì)數(shù)器是一種基本但強(qiáng)大的工具,用于跟蹤和管理數(shù)據(jù)和資源。本文將深入探討不同類型的計(jì)數(shù)器的應(yīng)用,從Redis的LRU(最近最少使用)緩存淘汰算法
    的頭像 發(fā)表于 12-15 09:24 ?495次閱讀

    【原創(chuàng)】Android開(kāi)發(fā)—Lru核心數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)突破緩存框架

    【原創(chuàng)】Android開(kāi)發(fā)—Lru核心數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)突破緩存框架回復(fù)即可獲取下載鏈接[hide=d15]鏈接:http://pan.baidu.com/s/1c2BfjsW 密碼:bta5 更多學(xué)習(xí)資料加Q:1352716312,
    發(fā)表于 06-21 16:58

    《CDN 之我見(jiàn)》系列二:原理篇(緩存、安全)

    Hash 運(yùn)算都得到同一個(gè)余數(shù)),則性能與單鏈表無(wú)異,查找時(shí)間復(fù)雜度是 O(n)。如果磁盤(pán)空間不夠了怎么辦?使用基于訪問(wèn)熱度的內(nèi)容淘汰算法,例如 FIFO、LRU、LFU、SLRU、
    發(fā)表于 06-12 16:59

    架構(gòu)設(shè)計(jì)應(yīng)用級(jí)緩存回收策略

    下。FIFO(First In First Out):先進(jìn)先出算法,即先放入緩存的先被移除。LRU(Least Recently Used):最近最少算法,使用時(shí)間距離現(xiàn)在最久的那個(gè)被
    發(fā)表于 01-14 17:08

    算法與數(shù)據(jù)結(jié)構(gòu)——雙向鏈表

    第三章為算法與數(shù)據(jù)結(jié)構(gòu),本文為3.3 雙向鏈表。
    的頭像 發(fā)表于 09-19 17:56 ?7205次閱讀
    <b class='flag-5'>算法</b>與數(shù)據(jù)結(jié)構(gòu)——雙向<b class='flag-5'>鏈表</b>

    如何進(jìn)行單鏈表的查找、插入與刪除的詳細(xì)介紹包括了算法和源程序

    鏈表的查找、插入與刪除。設(shè)計(jì)算法,實(shí)現(xiàn)線性結(jié)構(gòu)上的單鏈表的產(chǎn)生以及元素的查找、插入與刪除。具體實(shí)現(xiàn)要求:
    發(fā)表于 07-16 08:00 ?22次下載
    如何進(jìn)行單<b class='flag-5'>鏈表</b>的查找、插入與刪除的詳細(xì)介紹包括了<b class='flag-5'>算法</b>和源程序

    帶你輕松理解數(shù)據(jù)結(jié)構(gòu)與算法系列

      主要使用圖片來(lái)描述常見(jiàn)的數(shù)據(jù)結(jié)構(gòu)和算法,輕松閱讀并理解掌握。本系列包括各種堆、各種隊(duì)列、各種列表、各種樹(shù)、各種圖、各種排序等等。
    發(fā)表于 08-01 17:34 ?2次下載
    帶你<b class='flag-5'>輕松</b><b class='flag-5'>理解</b>數(shù)據(jù)結(jié)構(gòu)與<b class='flag-5'>算法</b>系列

    一文讀懂緩存淘汰算法:LFU 算法

    實(shí)現(xiàn)難度上來(lái)說(shuō),LFU 算法的難度大于 LRU 算法,因?yàn)?LRU 算法相當(dāng)于把數(shù)據(jù)按照時(shí)間排
    的頭像 發(fā)表于 08-25 17:37 ?9733次閱讀
    一文讀懂<b class='flag-5'>緩存</b><b class='flag-5'>淘汰</b><b class='flag-5'>算法</b>:LFU <b class='flag-5'>算法</b>

    谷歌在內(nèi)存方面依賴于per memcg lru lock

    能力。 作為世間最流行的操作系統(tǒng)Linux, 內(nèi)核使用LRU, Last Recent Used 鏈表來(lái)管理全部用戶使用的內(nèi)存,用一組鏈表串聯(lián)起一個(gè)個(gè)的內(nèi)存頁(yè),并且使用lru lock
    的頭像 發(fā)表于 01-15 14:00 ?1833次閱讀
    谷歌在內(nèi)存方面依賴于per memcg <b class='flag-5'>lru</b> lock

    設(shè)計(jì)并實(shí)現(xiàn)一個(gè)滿足LRU約束的數(shù)據(jù)結(jié)構(gòu)

    LRUCache(int capacity)` 以 **「正整數(shù)」** 作為容量 `capacity` 初始化 `LRU` 緩存
    的頭像 發(fā)表于 06-07 17:05 ?892次閱讀
    設(shè)計(jì)并<b class='flag-5'>實(shí)現(xiàn)</b>一個(gè)滿足<b class='flag-5'>LRU</b>約束的數(shù)據(jù)結(jié)構(gòu)

    基于LRU-K模型如何實(shí)現(xiàn)高效的元數(shù)據(jù)緩存?

    對(duì)于存儲(chǔ)來(lái)說(shuō),性能是繞不開(kāi)的話題。當(dāng)提到性能,可靠、高效的緩存策略是極其重要的。
    的頭像 發(fā)表于 06-29 15:05 ?775次閱讀
    基于<b class='flag-5'>LRU</b>-K模型如何<b class='flag-5'>實(shí)現(xiàn)</b>高效的元數(shù)據(jù)<b class='flag-5'>緩存</b>?

    Redis的LRU與LFU算法實(shí)現(xiàn)

    Redis是一款基于內(nèi)存的高性能NoSQL數(shù)據(jù)庫(kù),數(shù)據(jù)都緩存在內(nèi)存里, 這使得Redis可以每秒輕松地處理數(shù)萬(wàn)的讀寫(xiě)請(qǐng)求。
    的頭像 發(fā)表于 07-11 09:48 ?771次閱讀
    Redis的<b class='flag-5'>LRU</b>與LFU<b class='flag-5'>算法</b><b class='flag-5'>實(shí)現(xiàn)</b>

    鏈表和雙鏈表的區(qū)別在哪里

    的頭像 發(fā)表于 07-27 11:20 ?1491次閱讀
    單<b class='flag-5'>鏈表</b>和雙<b class='flag-5'>鏈表</b>的區(qū)別在哪里

    redis的lru原理

    Redis是一種基于內(nèi)存的鍵值數(shù)據(jù)庫(kù),它使用了LRU(Least Recently Used)算法來(lái)進(jìn)行緩存的數(shù)據(jù)淘汰。LRU
    的頭像 發(fā)表于 12-05 09:56 ?526次閱讀