最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用JavaScript實(shí)現(xiàn)LRU緩存的代碼詳解

 更新時(shí)間:2024年05月21日 11:20:31   作者:隱藏用戶_y  
LRU(Least?Recently?Used)算法是一種廣泛應(yīng)用于內(nèi)存管理和緩存系統(tǒng)的策略,本文將介紹LRU算法的基本原理,并通過JavaScript實(shí)現(xiàn)案例,幫助讀者理解其在前端開發(fā)中的應(yīng)用場景,需要的朋友可以參考下

引言

LRU(Least Recently Used)算法是一種廣泛應(yīng)用于內(nèi)存管理和緩存系統(tǒng)的策略,在微前端、狀態(tài)管理以及性能優(yōu)化等場景下,合理使用緩存機(jī)制能夠有效提升應(yīng)用性能。本文將介紹LRU算法的基本原理,并通過JavaScript實(shí)現(xiàn)案例,幫助讀者理解其在前端開發(fā)中的應(yīng)用場景。

LRU算法原理

LRU(最近最少使用)算法是一種常用的緩存淘汰策略,它假定“最近最久未使用的數(shù)據(jù)在未來被訪問的可能性最小”。當(dāng)緩存空間不足時(shí),LRU會(huì)優(yōu)先移除最近最少使用的數(shù)據(jù),為新數(shù)據(jù)騰出存儲(chǔ)空間。

實(shí)現(xiàn)方式

哈希表適合快速查找、插入和刪除的場景,而雙向鏈表適合頻繁插入和刪除節(jié)點(diǎn)的場景。在某些情況下,這兩種數(shù)據(jù)結(jié)構(gòu)也可以結(jié)合實(shí)現(xiàn)LRU緩存算法時(shí),可以使用哈希表存儲(chǔ) key 和對應(yīng)的節(jié)點(diǎn),雙向鏈表存儲(chǔ)實(shí)際的數(shù)據(jù)節(jié)點(diǎn),以實(shí)現(xiàn)快速的查找和插入刪除操作。

圖解示例

假設(shè)設(shè)計(jì)一個(gè)容量為3的LRU緩存

首先添加3個(gè)元素

哈希表中依次添加數(shù)據(jù)的key值:key1,key2,key3

雙向鏈表存儲(chǔ)哈希對(key,value),key3是最后一個(gè)添加的(最新添加記錄是key3),那么key3對應(yīng)的哈希值添加到鏈表的頭部node3。表示最近使用的。

這個(gè)時(shí)候如果要添加第四個(gè)數(shù)據(jù),key4放入哈希表,node4放入雙向鏈表頭部,node4包含key4,value4,然而此時(shí)容量不足,需要?jiǎng)h除一個(gè)元素,從尾部刪除一個(gè)最久沒使用的元素,刪除上面圖示中的node1的數(shù)據(jù),同時(shí)在哈希表中刪除node1對應(yīng)的key1 把node4添加到鏈表頭部,key4添加進(jìn)哈希表是同步進(jìn)行的。

如果最近要訪問key3,需要把node3從當(dāng)前位置刪除,并插入到鏈表頭部

簡而言之:

每次添加元素到鏈表中的時(shí)候都是從頭部添加

每次刪除元素的時(shí)候都是從尾部刪除

刪除的時(shí)候同時(shí)從哈希表里面刪除對應(yīng)的key

再次訪問的元素,需要把元素移動(dòng)到鏈表的頭部

實(shí)現(xiàn)代碼

使用哈希鏈表,可以在每個(gè)緩存項(xiàng)的節(jié)點(diǎn)上同時(shí)存儲(chǔ)鍵值信息以及指向鏈表中前后節(jié)點(diǎn)的引用。當(dāng)一個(gè)緩存項(xiàng)被訪問時(shí),先通過哈希表找到對應(yīng)節(jié)點(diǎn),然后將其從原有位置移出并插入鏈表尾部

class LRUCacheNode {
  constructor(key, value) {
    this.key = key;
    this.value = value;
    this.prev = null;
    this.next = null;
  }
}


class LRUCache {
  constructor(capacity = 500) {
    this.capacity = capacity;
    this.cacheMap = new Map(); // 使用哈希表存儲(chǔ)鍵值對
    this.doubleLinkedList = new DoublyLinkedList(); // 雙向鏈表維護(hù)緩存順序
  }

  get(key) {
    if (this.cacheMap.has(key)) {
      const node = this.cacheMap.get(key);
      this.doubleLinkedList.moveToTail(node); // 將節(jié)點(diǎn)移動(dòng)到鏈表尾部,表示最新訪問
      return node.value;
    }
    return -1; // 或者返回null,表示key不存在于緩存中
  }

  put(key, value) {
    if (this.cacheMap.has(key)) {
      const node = this.cacheMap.get(key);
      node.value = value;
      this.doubleLinkedList.moveToTail(node);
    } else {
      if (this.cacheMap.size >= this.capacity) {
        const headNode = this.doubleLinkedList.deleteHead();
        this.cacheMap.delete(headNode.key); // 移除最舊的緩存項(xiàng)
      }
      const newNode = new Node(key, value);
      this.cacheMap.set(key, newNode);
      this.doubleLinkedList.addToTail(newNode);
    }
  }
}

// 雙向鏈表類和節(jié)點(diǎn)類的實(shí)現(xiàn)略(根據(jù)實(shí)際需求實(shí)現(xiàn))
class Node {
  constructor(key, value) {
    this.key = key; // 節(jié)點(diǎn)鍵值
    this.value = value; // 節(jié)點(diǎn)數(shù)據(jù)值
    this.prev = null; // 前驅(qū)節(jié)點(diǎn)引用
    this.next = null; // 后繼節(jié)點(diǎn)引用
  }
}
class DoublyLinkedList {
  constructor() {
    this.head = null; // 頭節(jié)點(diǎn)
    this.tail = null; // 尾節(jié)點(diǎn)
  }

  /**
   * 添加節(jié)點(diǎn)到鏈表尾部
   * @param {Node} newNode 新節(jié)點(diǎn)
   */
  addToTail(newNode) {
    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      newNode.prev = this.tail;
      this.tail.next = newNode;
      this.tail = newNode;
    }
  }

  /**
   * 移除頭節(jié)點(diǎn)并返回
   * @returns {Node | null} 刪除的頭節(jié)點(diǎn)或null(如果鏈表為空)
   */
  deleteHead() {
    if (!this.head) return null;

    const deletedNode = this.head;
    this.head = this.head.next;

    if (this.head) {
      this.head.prev = null;
    } else {
      this.tail = null;
    }

    return deletedNode;
  }

  /**
   * 將指定節(jié)點(diǎn)移動(dòng)到鏈表尾部
   * @param {Node} node 需要移動(dòng)的節(jié)點(diǎn)
   */
  moveToTail(node) {
    if (node === this.tail) return; // 如果已經(jīng)是尾節(jié)點(diǎn),則無需移動(dòng)

    // 斷開當(dāng)前節(jié)點(diǎn)與前后節(jié)點(diǎn)的連接
    node.prev.next = node.next;
    if (node.next) node.next.prev = node.prev;

    // 將節(jié)點(diǎn)添加至鏈表尾部
    this.addToTail(node);
  }
  
  // 其他可能的方法,如查找節(jié)點(diǎn)、在指定位置插入節(jié)點(diǎn)等...
}


使用場景

路由緩存

Vue.js 中的 keep-alive 組件雖然并未直接采用LRU算法,但在實(shí)際項(xiàng)目中,我們可以基于LRU策略自定義實(shí)現(xiàn)路由組件的緩存功能。

資源加載

對于頻繁請求且響應(yīng)較慢的API,可以通過LRU緩存最近請求的結(jié)果,減少網(wǎng)絡(luò)請求次數(shù)。

狀態(tài)管理

在Vuex或Redux等狀態(tài)管理庫中,也可以利用LRU算法進(jìn)行緩存,避免頻繁計(jì)算或獲取昂貴的狀態(tài)。

業(yè)務(wù)場景

電商大促,瀏覽器瀏覽歷史,微博熱點(diǎn)。實(shí)現(xiàn)的具體可能不同,但是思路均可使用LRU緩存實(shí)現(xiàn).

網(wǎng)頁瀏覽歷史

實(shí)現(xiàn)一個(gè)簡單的瀏覽歷史記錄功能

class LRUCache {
    constructor(capacity) {
        this.capacity = capacity;
        this.cache = new Map();
    }

    get(key) {
        if (this.cache.has(key)) {
            const value = this.cache.get(key);
            // 刪除舊數(shù)據(jù)再重新插入,以更新最近訪問的順序
            this.cache.delete(key);
            this.cache.set(key, value);
            return value;
        }
        return null;
    }

    put(key, value) {
        if (this.cache.has(key)) {
            this.cache.delete(key);
        } else if (this.cache.size >= this.capacity) {
            // 超出容量時(shí)刪除最久未訪問的數(shù)據(jù)(即最近使用頻率最低的數(shù)據(jù))
            const keys = this.cache.keys();
            this.cache.delete(keys.next().value);
        }
        this.cache.set(key, value);
    }

    displayHistory() {
        console.log("Browser History:");
        for (let [key, value] of this.cache) {
            console.log(key + " -> " + value);
        }
    }
}

// 使用示例
const historyCache = new LRUCache(5); // 設(shè)置緩存容量為5

historyCache.put("Page 1", "www.page1.com");
historyCache.put("Page 2", "www.page2.com");
historyCache.put("Page 3", "www.page3.com");
historyCache.get("Page 1");

// 輸出瀏覽歷史記錄
historyCache.displayHistory();

在上面的示例中,LRUCache 類實(shí)現(xiàn)了一個(gè)簡單的 LRU 緩存,通過 get 方法獲取歷史記錄,并通過 put 方法添加歷史記錄。displayHistory 方法用于展示瀏覽歷史記錄。

可以根據(jù)實(shí)際需求進(jìn)一步擴(kuò)展和優(yōu)化這個(gè)示例,比如添加時(shí)間戳來記錄訪問時(shí)間、持久化歷史記錄到本地存儲(chǔ)等功能。希望這個(gè)示例能幫助你實(shí)現(xiàn)瀏覽歷史記錄功能。

以上就是使用JavaScript實(shí)現(xiàn)LRU緩存的代碼詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript LRU緩存的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論

衡东县| 刚察县| 开阳县| 子长县| 镇雄县| 江都市| 灵宝市| 隆回县| 西乌| 逊克县| 五莲县| 洱源县| 尖扎县| 西畴县| 满城县| 柘城县| 长春市| 确山县| 桂平市| 吉安县| 鹤山市| 葫芦岛市| 平塘县| 博湖县| 安丘市| 遂昌县| 宁夏| 瑞安市| 交城县| 广水市| 大荔县| 吉首市| 高尔夫| 葵青区| 深水埗区| 阳朔县| 紫金县| 吉安市| 西乌| 正镶白旗| 昌乐县|