LRU算法

3 篇文章 0 订阅

LRU算法是关于内存页替换的一种有效算法。此处借用到地图数据管理中。
基本流程:定义内存中可以存储的地图块个数为16。
1,当加载的地图块个数<=16时,直接插入到list列表中;
2, 当地图块个数达到16后,再加载新的地图块,需要从list中删除最近最少使用的地图块,即list列表尾部的节点数据;
3,当需要查询的地图块在list中,将对应的地图块从list中移动到表头;
4,若查询的地图块不再list,则从底层数据库中加载,之后转步骤1,2.
该算法采用list和under_map实现。list中的节点为地图块(id,value),under_map存储地图块id和地图块的指针,方便实现O(1)查询。
以下是详细代码。

//最近最少使用算法,使用双向链表存储key-value数据,使用哈希表存储索引
#ifndef LRUCACHE_H
#define LRUCACHE_H

#include <unordered_map>
template<class Key,class Value>
//存储数据的节点
struct Node
{
	//关键字
	Key iKey;
	//值
	Value iValue;
	//前后节点指针
	Node* pParent;
	Node* pNext;

	Node():iKey(0),iValue(0),pParent(nullptr),pNext(nullptr)
	{

	}
	Node(const Key& key, const Value& value):iKey(key),iValue(value),pParent(nullptr),pNext(nullptr)
	{

	}
	~Node()
	{

	}
};
template<class Key,class Value>
class LRUCache
{
public:
	//初始化函数
	//nums: 内存中存储数据个数
	LRUCache(int nums);
	~LRUCache(void);
public:
	//根据key获取值
	Value get(const Key& key);
	//插入值
	void set(Key key,Value value);
	void show();
private:
	//将当前节点pNode从列表中移出
	void remove(Node<Key,Value>* pNode);
	void setHead(Node<Key,Value>* pNode);
	void pop_back();
	//清空所有数据
	void clear();
private:
	//数据总节点个数
	int m_iNum;
	//链表根节点。采用循环链表
	Node<Key,Value>* m_pRoot;
	//Node* m_pTail;
	//哈希表,存储数据所在地址<key,Node*>
	std::unordered_map<Key, Node<Key,Value>*> m_mapHash;
	

};
//初始化函数
//nums: 内存中存储数据个数
template<class Key,class Value>
LRUCache<Key,Value>::LRUCache(int nums):m_pRoot(nullptr)
{
	m_iNum = nums;
	m_pRoot = new Node<Key,Value> ();
	//初始化时,根节点的父节点和子节点都指向本身
	m_pRoot->pParent = m_pRoot;
	m_pRoot->pNext = m_pRoot;
}
template<class Key,class Value>
void LRUCache<Key,Value>::clear()
{
	std::unordered_map<int, Node<Key,Value> *>::iterator it = m_mapHash.begin();
	for (;it != m_mapHash.end();++it)
	{
		delete it->second;
	}
	delete m_pRoot;
}
template<class Key,class Value>
LRUCache<Key,Value>::~LRUCache(void)
{
	clear();
}
//根据key获取值
template<class Key,class Value>
Value LRUCache<Key,Value>::get(const Key& key)
{

	std::unordered_map<int, Node<Key,Value> *>::iterator it = m_mapHash.find(key);
	if (it == m_mapHash.end())
	{
		return -1;
	}
	Node<Key,Value> * pNode = it->second;
	if (pNode != nullptr)
	{
		//从当前位置移除
		remove(pNode);
		//移动到头结点
		setHead(pNode);
		return pNode->iValue;
	}
	else
	{
		return -1;
	}


}



//插入值
template<class Key,class Value>
void LRUCache<Key,Value>::set(Key key,Value value)
{
	//查找是否已经存在
	std::unordered_map<int, Node<Key,Value> *>::iterator it = m_mapHash.find(key);
	//如果已经存在,则移动到头结点
	if (it != m_mapHash.end())
	{
		//更新key对应的值
		it->second->iValue = value;
		//从列表中移出
		remove(it->second);
		//移动到头结点
		setHead(it->second);
	}
	else
	{
		//否则,如果已满,则删除尾结点
		if (m_mapHash.size()>= size_t(m_iNum))
		{
			pop_back();
		}
		std::cout<<"插入新节点("<<key<<","<<value<<")"<<std::endl;
		//插入新的节点作为头结点
		Node<Key,Value> * pNewNode = new Node<Key,Value>(key,value);
		setHead(pNewNode);
		//在hashMap中添加对应索引
		m_mapHash.insert(std::make_pair(key,pNewNode));

	}
}
//将当前节点pNode从列表中移出
template<class Key,class Value>
void LRUCache<Key,Value>::remove(Node<Key,Value>* pNode)
{
	if(pNode==nullptr)
	{
		return;
	}
	else
	{
		//如果当前节点是头结点
		if(pNode->pParent == m_pRoot)
		{
			return;
		}
		//把当前节点的子节点付给当前节点父节点子节点
		pNode->pParent->pNext = pNode->pNext;
		//把当前节点的父节点赋值给当前节点子节点的父节点
		pNode->pNext->pParent = pNode->pParent;
	}
}
//插入到头结点
template<class Key,class Value>
void LRUCache<Key,Value>::setHead(Node<Key,Value>* pNode)
{
	if (pNode==nullptr)
	{
		return;
	}
	else
	{
		//如果是头结点,直接返回
		if (pNode->pParent == m_pRoot)
		{
			return;
		}
		else
		{
			std::cout<<"移动到头结点("<<pNode->iKey<<","<<pNode->iValue<<")"<<std::endl;
			//旧的头结点赋值给当前节点在子节点
			pNode->pNext = m_pRoot->pNext;
			//旧的头结点的父节点赋值给当前节点的父节点
			pNode->pParent = m_pRoot->pNext->pParent;
			//设置旧节点的父节点为当前节点
			m_pRoot->pNext->pParent = pNode;
			//根节点的子节点为新的头节点
			m_pRoot->pNext = pNode;

		}
	}

}
//删除尾结点
template<class Key,class Value>
void LRUCache<Key,Value>::pop_back()
{
	//m_pRoot->pParent为尾结点
	if (m_mapHash.size()==0)
	{
		return;
	}
	else
	{
		//获取尾结点
		Node<Key,Value>* pTail = m_pRoot->pParent;
		std::cout<<"移除尾结点("<<pTail->iKey<<","<<pTail->iValue<<")"<<std::endl;
		//从hash表中删除尾结点的索引
		m_mapHash.erase(pTail->iKey);
		//尾结点的头结点的子节点为根节点
		pTail->pParent->pNext = m_pRoot;
		//新的尾结点为旧尾结点的父节点
		m_pRoot->pParent = pTail->pParent;
	}
}
template<class Key,class Value>
void LRUCache<Key,Value>::show()
{
	//获取头结点
	Node<Key,Value>* pNode = m_pRoot->pNext;
	while(pNode != m_pRoot)
	{
		std::cout<<"Key-Value("<<pNode->iKey<<","<<pNode->iValue<<")"<<std::endl;
		pNode = pNode->pNext;
	}
	std::cout<<std::endl;
}
#endif //LRUCACHE_H


// LRUAlg.cpp : 定义控制台应用程序的入口点。
//

#include "LRUCache.h"
#include <iostream>
int main(int argc, char* argv[])
{
	LRUCache<int,int>* pCach = new LRUCache<int,int>(5);
	for (int i=0;i<=10;++i)
	{
		pCach->set(i,i);
		pCach->show();
	}
	int iValue = 0;
	iValue = pCach->get(7);
	std::cout<<"获取的值为:"<<iValue<<std::endl;
	/*pCach->set(1,1);
	pCach->set(2,2);
	pCach->show();
	iValue = pCach->get(2);
	std::cout<<"获取的值为:"<<iValue<<std::endl;

	pCach->set(3,3);*/
	pCach->show();

	iValue= pCach->get(6);
	std::cout<<"获取的值为:"<<iValue<<std::endl;
	pCach->show();

	iValue= pCach->get(8);
	std::cout<<"获取的值为:"<<iValue<<std::endl;
	pCach->show();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值