使用散列表和鏈表實現LRU緩存淘汰算法

LRU和LFU

LRU是最近最少使用頁面置換算法(Least Recently Used),也就是首先淘汰最長時間未被使用的頁面!node

LFU是最近最不經常使用頁面置換算法(Least Frequently Used),也就是淘汰必定時期內被訪問次數最少的頁!ios

frist,如何使用鏈表實現LRU(簡單)

咱們維護一個有序單鏈表,越靠近鏈表尾部的結點是越早以前訪問的。當有一個新的數據被訪問時,咱們從鏈表頭開始順序遍歷鏈表。web

  1. 若是此數據以前已經被緩存在鏈表中了,咱們遍歷獲得這個數據對應的結點,並將其從原來的位置刪除,而後再插入到鏈表的頭部。算法

  2. 若是此數據沒有在緩存鏈表中,又能夠分爲兩種狀況:緩存

  • 若是此時緩存未滿,則將此結點直接插入到鏈表的頭部
  • 若是此時緩存已滿,則鏈表尾結點刪除,將新的數據結點插入鏈表的頭部。 這樣咱們就用鏈表實現了一個 LRU 緩存,是否是很簡單?
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
using namespace std;
void print(list<int> &physical_block)
{
	for (auto tmp : physical_block)
		cout << tmp << " ";
	cout << endl;
}
int main(void)
{
	// 規定緩存中放置的頁面不超過 4 (也就是list不超過 4)
	list<int> physical_block;
	vector<int> pages = {7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 
	0, 3, 2, 1, 2, 0, 1, 7, 0, 1};

	for (auto i : pages) //依次訪問頁面
	{
		/*先看在沒在緩存中*/
		auto it = std::find(physical_block.begin(), physical_block.end(), i);
		if (it != physical_block.end())
		{
			cout << i << "在緩存中" << endl;
			physical_block.erase(it);
			physical_block.push_front(i);
		}
		/*沒在*/
		else
		{
			cout << i << "不在緩存中" << endl;
			/*頁面滿了就得刪除並添加*/
			if (physical_block.size() >= 4)
				physical_block.pop_back();

			physical_block.push_front(i);
		}
		/*打印緩存中的頁面*/
		print(physical_block);
		cout << "********************************" << endl;
	}
}

second,結合散列表實現LRU(優化)

使用STL hash_map(即unordered_map)實現

#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <string>
#include <functional>
#include <unordered_map>
using namespace std;
class Node
{
  public:
	Node(std::string str)
		: data_(str) {}
	std::string data_;
};

namespace std
{
template <>
class hash<Node>
{
  public:
	int operator()(const Node &s) const
	{
		return stoi(s.data_);
	}
};

} // namespace std

class LruCache
{
  public:
	LruCache() : capacity_(0) {}
	// cpu 訪問數據,須要動態更新緩存
	bool PutCache(std::string &str)
	{
		Node node(str);
		int key = hash_fn_(node);

		auto it = hash_table_.find(key);

		if (it != hash_table_.end())
		{
			auto list_iter = it->second;
			cout << node.data_ << "數據已經在內存中...." << endl;
			double_list_.splice(double_list_.begin(), double_list_, list_iter);
		}
		else
		{
			cout << node.data_ << "數據未在內存中...." << endl;
			/*頁面滿了就得刪除並添加*/
			if (capacity_ >= 4)
			{
				int key = hash_fn_(double_list_.back());
				double_list_.pop_back();
				hash_table_.erase(key);
				capacity_--;
			}

			double_list_.push_front(node);
			hash_table_.insert({key, double_list_.begin()});
			capacity_++;
		}
		for (auto &tt : double_list_)
			cout << tt.data_ << " ";
		cout << endl;
	}

  private:
	std::hash<Node> hash_fn_;
	int capacity_ = 0; //cache capacity,其實就是 list 的容量
	//注意是:只用了一條 std::list
	//對於list中只有元素的刪除操做會致使指向該元素的迭代器失效,其餘元素迭代器不受影響,當刪除元素時,將迭代器置爲空就好了
	//或者直接在 hash_map 中 erase 便可

	std::list<Node> double_list_;
	std::unordered_map<int, std::list<Node>::iterator> hash_table_;
};

int main(void)
{
	std::string str[] = {"7", "0", "1", "2", "0", "3", "0", "4", "2", "3", "0", "3", "2", "1", "2", "0", "1", "7", "0"};
	std::vector<std::string> pages(str, str + 19);

	LruCache lru;
	for (auto tt : pages)
	{
		lru.PutCache(tt);
	}
}

組織結構以下:
在這裏插入圖片描述svg

相關文章
相關標籤/搜索