LRU緩存機制實現(cpp版)

一、概念

計算機的緩存容量有限,如果緩存滿了就要刪除一些內容,給新內容騰位置。但問題是,刪除哪些內容呢?我們肯定希望刪掉哪些沒什麼用的緩存,而把有用的數據繼續留在緩存裏,方便之後繼續使用。那麼,什麼樣的數據,我們判定爲「有用的」的數據呢?

LRU 緩存淘汰算法就是一種常用策略。LRU 的全稱是 Least Recently Used,即最近最少被使用,也就是說我們認爲最近使用過的數據應該是是「有用的」,很久都沒用過的數據應該是無用的,內存滿了就優先刪那些很久沒用過的數據。

二、算法描述

獲取數據 get 和 寫入數據 put 。

獲取數據 get(key) - 如果密鑰 (key) 存在於緩存中,則獲取密鑰的值(總是正數),否則返回 -1。
寫入數據 put(key, value) - 如果密鑰不存在,則寫入其數據值。當緩存容量達到上限時,它應該在寫入新數據之前刪除最近最少使用的數據值,從而爲新的數據值留出空間。

三、算法思想

要讓 put 和 get 方法的時間複雜度爲 O(1)O(1),我們可以總結出 cache 這個數據結構必要的條件:查找快,插入快,刪除快,有順序之分。

因爲顯然 cache 必須有順序之分,以區分最近使用的和久未使用的數據;而且我們要在 cache 中查找鍵是否已存在;如果容量滿了要刪除最後一個數據;每次訪問還要把數據插入到隊頭。

那麼,什麼數據結構同時符合上述條件呢?哈希表查找快,但是數據無固定順序;鏈表有順序之分,插入刪除快,但是查找慢。所以結合一下,形成一種新的數據結構:哈希鏈表。

LRU 緩存算法的核心數據結構就是哈希鏈表,雙向鏈表和哈希表的結合體。

四、代碼及具體思路

#include <list>
#include <iterator>
#include <unordered_map>
#include <map>
using namespace std;

class LRUCache {
public:
    int cap = 0;

    LRUCache(int capacity)
    {
        this->cap = capacity;
    }

    int get(int key)
    {
        auto iter = map.find(key);
        //沒有在map中找到
        if (iter == map.end())
            return -1;

        else
        {
            int value = iter->second->second;
            cache.push_front(*(iter->second));
            cache.erase(iter->second);
            map[key] = cache.begin();
            return value;
        } 
    }

    void put(int key, int value)
    {
        //先判斷key是否存在
        auto iter = map.find(key);
        //key不存在
        if (iter == map.end())
        {
            //判斷緩存容量是否已滿
            if (cache.size() == cap)
            {
                //容量滿需要釋放cache 和map
                auto lst = cache.back();
                map.erase(lst.first);
                cache.pop_back();
            }
            //再插入
            cache.push_front({ key,value });
            map[key] = cache.begin();
        }

        //key已經存在
        else
        {
            //先將緩存中原數據刪除
            cache.erase(iter->second);
            //再加入
            cache.push_front({ key,value });
            map[key] = cache.begin();   
        }
    }

protected:
    list<pair<int, int>> cache;
    unordered_map <int, list<pair<int, int>>::iterator> map;
};

void main()
{
    LRUCache cache (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
}

以上就是本篇文章的全部內容,如有不足,請多批評指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章