JS 實現緩衝演算法的樣本(FIFO/LRU),fifolru

來源:互聯網
上載者:User

JS 實現緩衝演算法的樣本(FIFO/LRU),fifolru

FIFO

最簡單的一種緩衝演算法,設定緩衝上限,當達到了緩衝上限的時候,按照先進先出的策略進行淘汰,再增加進新的 k-v 。

使用了一個對象作為緩衝,一個數組配合著記錄添加進對象時的順序,判斷是否到達上限,若到達上限取數組中的第一個元素key,對應刪除對象中的索引值。

/** * FIFO隊列演算法實現緩衝 * 需要一個對象和一個數組作為輔助 * 數組記錄進入順序 */class FifoCache{  constructor(limit){    this.limit = limit || 10    this.map = {}    this.keys = []  }  set(key,value){    let map = this.map    let keys = this.keys    if (!Object.prototype.hasOwnProperty.call(map,key)) {      if (keys.length === this.limit) {        delete map[keys.shift()]//先進先出,刪除隊列第一個元素      }      keys.push(key)    }    map[key] = value//無論存在與否都對map中的key賦值  }  get(key){    return this.map[key]  }}module.exports = FifoCache

LRU

LRU(Least recently used,最近最少使用)演算法。該演算法的觀點是,最近被訪問的資料那麼它將來訪問的機率就大,緩衝滿的時候,優先淘汰最無人問津者。

演算法實現思路:基於一個雙鏈表的資料結構,在沒有滿員的情況下,新來的 k-v 放在鏈表的頭部,以後每次擷取緩衝中的 k-v 時就將該k-v移到最前面,緩衝滿的時候優先淘汰末尾的。

雙向鏈表的特點,具有頭尾指標,每個節點都有 prev(前驅) 和 next(後繼) 指標分別指向他的前一個和後一個節點。

關鍵點:在雙鏈表的插入過程中要注意順序問題,一定是在保持鏈表不斷的情況下先處理指標,最後才將原頭指標指向新插入的元素,在代碼的實現中請注意看我在注釋中說明的順序注意點!

class LruCache {  constructor(limit) {    this.limit = limit || 10    //head 指標指向表頭元素,即為最常用的元素    this.head = this.tail = undefined    this.map = {}    this.size = 0  }  get(key, IfreturnNode) {    let node = this.map[key]    // 如果尋找不到含有`key`這個屬性的緩衝對象    if (node === undefined) return    // 如果尋找到的緩衝對象已經是 tail (最近使用過的)    if (node === this.head) { //判斷該節點是不是是第一個節點      // 是的話,皆大歡喜,不用移動元素,直接返回      return returnnode ?        node :        node.value    }    // 不是頭結點,鐵定要移動元素了    if (node.prev) { //首先要判斷該節點是不是有前驅      if (node === this.tail) { //有前驅,若是尾節點的話多一步,讓尾指標指向當前節點的前驅        this.tail = node.prev      }      //把當前節點的後繼交接給當前節點的前驅去指向。      node.prev.next = node.next    }    if (node.next) { //判斷該節點是不是有後繼      //有後繼的話直接讓後繼的前驅指向當前節點的前驅      node.next.prev = node.prev      //整個一個過程就是把當前節點拿出來,並且保證鏈表不斷,下面開始移動當前節點了    }    node.prev = undefined //移動到最前面,所以沒了前驅    node.next = this.head //注意!!! 這裡要先把之前的排頭給接到手!!!!讓當前節點的後繼指向原排頭    if (this.head) {      this.head.prev = node //讓之前的排頭的前驅指向現在的節點    }    this.head = node //完成了交接,才能執行此步!不然就找不到之前的排頭啦!    return IfreturnNode ?      node :      node.value  }  set(key, value) {    // 之前的演算法可以直接存k-v但是現在要把簡單的 k-v 封裝成一個滿足雙鏈表的節點    //1.查看是否已經有了該節點    let node = this.get(key, true)    if (!node) {      if (this.size === this.limit) { //判斷緩衝是否達到上限        //達到了,要刪最後一個節點了。        if (this.tail) {          this.tail = this.tail.prev          this.tail.prev.next = undefined          //平滑斷鏈之後,銷毀當前節點          this.tail.prev = this.tail.next = undefined          this.map[this.tail.key] = undefined          //當前緩衝記憶體釋放一個槽位          this.size--        }        node = {          key: key        }        this.map[key] = node        if(this.head){//判斷緩衝裡面是不是有節點          this.head.prev = node          node.next = this.head        }else{          //緩衝裡沒有值,皆大歡喜,直接讓head指向新節點就行了          this.head = node          this.tail = node        }        this.size++//減少一個緩衝槽位      }    }    //節點存不存在都要給他重新賦值啊    node.value = value  }}module.exports = LruCache

具體的思路就是如果所要get的節點不是頭結點(即已經是最近使用的節點了,不需要移動節點位置)要先進行平滑的斷鏈操作,處理好指標指向的關係,拿出需要移動到最前面的節點,進行鏈表的插入操作。

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援幫客之家。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.