Leetcode LRU快取,陣列+結構體實現

siyu1915發表於2021-02-02

一、演算法思路

LRUCache類有以下函式和變數:

  • LRUCache(int capacity): capacity是當前物件能夠儲存的鍵值對(key,value)最大個數。
  • int get(int key): 根據指定的key尋找value值,若沒有找到key就返回-1
  • void put(int key, int value): 儲存一個新的鍵值對(key,value),如果key已經存在,就更新value,如果當前已達最大容量,就將最近最少使用的鍵值對替換。
  • void show(): 檢視當前所有鍵值對資訊。(題目並沒有要求書寫這個函式,只是為了方便除錯)。
  • int size: 當前所儲存的鍵值對個數。
  • int max_size: 最大鍵值對個數(對應建構函式的capacity)。
  • Node *list:鍵值對陣列。

Node結構體的定義:

typedef struct LRUCacheNode {
    int key;
    int value;
    int count;
} Node;

其中key,value構成了鍵值對(key,value),count表示已有多久沒有使用。當一個鍵值對節點(Node)被第一次插入、查詢或是修改,其count都會被置零,而其他節點的count自增。已達到最大儲存量後,插入節點會修改所有節點中count最大的,修改完畢(也就是value值被更新後),count會被置零,而其他節點的count依然會自增。

二、程式碼演示

LRUCache(int capacity) {
        max_size = capacity;
        size = 0;
        list = new Node[max_size];
}

LRUCache的建構函式僅僅初始化max_size,size和list。三者的定義如下:

private:
    int size;
    int max_size;
    Node *list;

接下來是get函式,比較簡單,依次遍歷list並尋找符合要求的節點,不要忘記將符合要求的節點的count置零,以及將其他節點的count自增:

int get(int key) {
        int value = -1;
        for (int i = 0; i < size; ++i) {
            Node *tmp = &list[i];
            if (tmp->key == key) {
                tmp->count = 0;
                value = tmp->value;
            } else {
                tmp->count++;
            }
        }
        return value;
}

接下來說重點——put函式:

void put(int key, int value) {
        bool contains = false;
        for (int i = 0; i < size; ++i) {
            Node *tmp = &list[i];
            if (tmp->key == key) {
                tmp->count = 0;
                tmp->value = value;
                contains = true;
            } else {
                tmp->count++;
            }
        }

        if (contains) { return; }

        if (size >= max_size) {
            int max_count = -1;
            Node *max_node;
            for (int i = 0; i < size; ++i) {
                Node *tmp = &list[i];
                if (tmp->count > max_count) {
                    max_count = tmp->count;
                    max_node = tmp;
                }
            }
            max_node->key = key;
            max_node->value = value;
            max_node->count = 0;
        } else {
            Node n;
            n.key = key;
            n.value = value;
            n.count = 0;
            list[size++] = n;
        }
}

 put函式首先在list中尋找(key,value)是否存在,是則僅更新節點並返回。如果沒有找到節點,接下來判斷list是否已滿:如果沒有滿,就將(key,value)儲存到list陣列;如果已經滿了,首先根據count大小,尋找出count最大的節點,將其修改(此步並不需要將其他節點count自增,因為在第一步尋找(key,value)是否存在是已經自增過了)。

接下來是show函式,可以自行調整樣式:

void show() {
        for (int i = 0; i < size; ++i) {
            Node *tmp = &list[i];
            cout << tmp->key << "\t" << tmp->value << "\t" << tmp->count << "\n";
        }
}

main函式除錯:

int main() {
    LRUCache cache = LRUCache(2 /* 快取容量 */ );
    cache.put(1, 1);
    cache.put(2, 2);
    cout << cache.get(1) << "\n";       // 返回  1
    cache.put(3, 3);    // 該操作會使得金鑰 2 作廢
    cout << cache.get(2) << "\n";       // 返回 -1 (未找到)
    cache.put(4, 4);    // 該操作會使得金鑰 1 作廢
    cout << cache.get(1) << "\n";       // 返回 -1 (未找到)
    cout << cache.get(3) << "\n";       // 返回  3
    cout << cache.get(4) << "\n";       // 返回  4

    return 0;
}

main函式輸出:

1
-1
-1
3
4

三、提交結果

 

 執行用時並不理想,有待優化。

相關文章