C 實現快取演算法LRU和LFU

2021-09-02 17:17:13 字數 3573 閱讀 3200

運用你所掌握的資料結構,設計和實現乙個lru (最近最少使用) 快取機制 。它應該支援以下操作: 獲取資料get和 寫入資料put

獲取資料get(key)- 如果金鑰 (key) 存在於快取中,則獲取金鑰的值(總是正數),否則返回 -1。

寫入資料put(key, value)- 如果金鑰不存在,則寫入其資料值。當快取容量達到上限時,它應該在寫入新資料之前刪除最近最少使用的資料值,從而為新的資料值留出空間。

高階:你是否可以在 o(1) 時間複雜度內完成這兩種操作?

思路:

lru實現採用雙向鍊錶 + hash_map 來進行實現。這裡採用雙向鍊錶的原因是:如果採用普通的單鏈表,則刪除節點的時候需要從表頭開始遍歷查詢,效率為o(n),採用雙向鍊錶可以直接改變節點的前驅的指標指向進行刪除達到o(1)的效率。使用map來儲存節點的key、value值便於能在o(logn)的時間查詢元素,對應get操作。

**:

#define _silence_stdext_hash_deprecation_warnings

#include#include#includeusing namespace std;

struct cachenode

};class lrucache

int get(int key);

void set(int key,int value);

void remove(cachenode *node);

void sethead(cachenode *node);

cachenode *gethead();

private:

int size;//最大快取數

cachenode *head, *tail;

hash_mapmap;//int是關鍵字

};int lrucache::get(int key)

return node->value;

} else

return -1;

}void lrucache::set(int key, int value)

node->value = value;

remove(node);

sethead(node);

} else

sethead(node);

map[key] = node; }}

void lrucache::remove(cachenode *node)

void lrucache::sethead(cachenode *node)

else }

cachenode* lrucache::gethead()

int main(void)

設計並實現最少訪問頻率(lfu)快取的資料結構。lfu的每個資料塊都有乙個引用計數,所有資料塊按照引用計數排序,具有相同引用計數的資料塊則按照時間進行排序。它應該支援以下操作:getput

get(key)- 如果鍵存在於快取中,則獲取鍵的值(總是正數),否則返回 -1。

put(key, value)- 如果鍵不存在,請設定或插入值。當快取達到其容量時,它應該在插入新專案之前,使最不經常使用的專案無效。在此問題中,當存在平局(即兩個或更多個鍵具有相同使用頻率)時,最近最少使用的鍵將被去除。

高階:你是否可以在 o(1) 時間複雜度內執行兩項操作?

思路:

lru實現採用2個雙向鍊錶 + 2個hash_map 來進行實現。乙個雙向鍊錶用來鏈結各個頻率的鍊錶,另乙個鍊錶用來鏈結相同訪問頻率的各個記錄。這兩個鍊錶是巢狀關係。

兩個hash_map分別是存放關鍵字和對應的node,以及node所對應的頻率鏈。

每次新加入節點都是從頭部加入,所以對於訪問次數相同的關鍵字,刪除的是鍊錶尾部的那個,所以鍊錶需要有指針對頭尾進行記錄。

**:

#define _silence_stdext_hash_deprecation_warnings

#include#include#includeusing namespace std;

class node

public:

int key;//關鍵字

int value;//值

int times;//訪問的次數

node *pre;//前乙個節點

node *next;//後乙個節點

};class nodelist

void deletenode(node *node);

public:

node *head;

node *tail;

nodelist *pre;

nodelist *next;

};nodelist::nodelist(node *node)

void nodelist::addnodefromhead(node *newhead)

void nodelist::deletenode(node *node)

//刪掉這個節點之後,鍊錶中還至少有乙個節點

else

else if (node == tail)

else

}node->next = nullptr;

node->pre = nullptr;

}class lfucache ;

lfucache::lfucache(int c)

void lfucache::set(int key, int value)

else//緩衝區之前沒有這個關鍵字

node *node = new node(key, value, 1);//新建乙個節點,訪問次數為1

if (headlist == nullptr)

headlist = new nodelist(node);

else

}records[key] = node;

heads[node] = headlist;

size++; }}

//oldnodelist是node原來屬於的那個nodelist,當訪問數加一之後需要找到下乙個nodelist

void lfucache::move(node *node, nodelist* oldnodelist)

else//oldnodelist有下乙個節點

else

}}//把乙個node從lodelist裡面delete之後,然後呼叫下面這個

//方法進行判斷是不是連整個鍊錶不要了

bool lfucache::modifyheadlist(nodelist *nodelist)

else

return true;

} return false;

}int lfucache::get(int key)

int main(void)

快取淘汰演算法 LRU 和 LFU

lru least recently used 即最近最少使用演算法,是一種常見的 cache 頁面置換演算法,有利於提高 cache 命中率。lru 的演算法思想 對於每個頁面,記錄該頁面自上一次被訪問以來所經歷的時間 t 當淘汰乙個頁面時,應選擇所有頁面中其 t 值最大的頁面,即記憶體中最近一段...

LRU與LFU快取替換演算法C 實現

lfu實現 資料結構unordered map dqueue unordered map的鍵為key,值為node 方便快速訪問資料 dqueue雙端佇列,快速刪除 插入node 簡單的lru是存在缺點的,比如有某一次快取操作是完全隨機的,但是lru快取中替換為了這一次隨機的訪問資料 指的是,只有這...

快取策略之LRU和LFU

快取,就是把資料儲存在本地,簡單實用key value做乙個對映就好了。但為什麼還要快取策略,因為快取的大小需要限制,否則儲存的東西只增不減,時間一長就有很多記憶體浪費。因為資源總是有限,所以優化,因為優化所以複雜 這個是least recently used的縮寫,即最近最少使用。它的邏輯很簡單 ...