JS 實現一個 LRU 算法


LRU 是 Least Recently Used 的縮寫,即最近最少使用,是一種常用的頁面置換算法,選擇內存中最近最久未使用的頁面予以淘汰。

可用的 NodeJS 庫見node-lru-cache

然怎么使用 JS 簡單寫一個?類似的題目見 LeetCode 146 LRU 緩存機制,進階要求時間復雜度 O(1) 。

思路

解法:維護一個數組,提供 get 和 put 方法,並且限定 max 數量。

使用時,get 可以標記某個元素是最新使用的,提升它去第一項。put 可以加入某個key-value,但需要判斷是否已經到最大限制 max

  • 若未到能直接往數組第一項里插入
  • 若到了最大限制 max,則需要淘汰數據尾端一個元素。
LRUCache cache = new LRUCache( 2 /* 緩存容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回  1
cache.put(3, 3);    // 該操作會使得密鑰 2 作廢
cache.get(2);       // 返回 -1 (未找到)
cache.put(4, 4);    // 該操作會使得密鑰 1 作廢
cache.get(1);       // 返回 -1 (未找到)
cache.get(3);       // 返回  3
cache.get(4);       // 返回  4

具體代碼

一般的解法,通過維護一個數組,數組項存放了 key-value 鍵值對對象,每次需要遍歷去尋找 key 值所在的數組下標操作。

已經通過 leetCode 146 的檢測。執行用時 : 720 ms。內存消耗 : 58.5 MB。

var LRUCache = function (capacity) {
  this.capacity = capacity;
  this.cache = [];
};

/**
 * @param {number} key
 * @return {number}
 */
LRUCache.prototype.get = function (key) {
  let index = this.cache.findIndex((item) => item.key === key);
  if (index === -1) {
    return -1;
  }
  // 刪除此元素后插入到數組第一項
  let value = this.cache[index].value;
  this.cache.splice(index, 1);
  this.cache.unshift({
    key,
    value,
  });
  return value;
};

/**
 * @param {number} key
 * @param {number} value
 * @return {void}
 */
LRUCache.prototype.put = function (key, value) {
  let index = this.cache.findIndex((item) => item.key === key);
  // 想要插入的數據已經存在了,那么直接提升它就可以
  if (index > -1) {
    this.cache.splice(index, 1);
  } else if (this.cache.length >= this.capacity) {
    // 若已經到達最大限制,先淘汰一個最久沒有使用的
    this.cache.pop();
  }
  this.cache.unshift({ key, value });
};

上面的做法其實有變種,可以通過一個對象來存鍵值對,一個數組來存放鍵的順序。

來看進階要求

時間復雜度 O(1),那就不能數組遍歷去查找 key 值。可以用 ES6 的 Map 來解了,因為 Map 既能保持鍵值對,還能記住插入順序。

var LRUCache = function (capacity) {
  this.cache = new Map();
  this.capacity = capacity;
};

LRUCache.prototype.get = function (key) {
  if (this.cache.has(key)) {
    // 存在即更新
    let temp = this.cache.get(key);
    this.cache.delete(key);
    this.cache.set(key, temp);
    return temp;
  }
  return -1;
};

LRUCache.prototype.put = function (key, value) {
  if (this.cache.has(key)) {
    // 存在即更新(刪除后加入)
    this.cache.delete(key);
  } else if (this.cache.size >= this.capacity) {
    // 不存在即加入
    // 緩存超過最大值,則移除最近沒有使用的
    this.cache.delete(this.cache.keys().next().value);
  }
  this.cache.set(key, value);
};

上述代碼來自LRU 緩存機制-官方,執行用時 : 228 ms,內存消耗 : 59 MB

使用案例


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM