LRU缓存算法c++实现

    在如今的项目开发中,缓存是一种必不可少的存储方式,目前在各种后台开发中,比较常见的一种缓存算法就是LRU了,LRU名为最近最少使用算法。它会将最近不常用的缓存数据淘汰掉,是一种Cache替换算法。

     本文通过c++简单的实现这种算法,代码不长,但能很好的体现这种思想

     思路:  map  存储数据 ,实现查找效率O(1),双向链表实现算法逻辑
     算法逻辑: 1.新数据会插入到链表头部
                         2.当缓存数据被访问,将该缓存数据移到链表头部
                         3.当新数据插入时达到缓存上限了,将尾部数据删除掉(也就是最近最少使用的),新数据放在头部。

     直接上代码:
 

//********************
//**Filename:LRUCache.h
//**Discribe: LRUCache实现文件:双向链表+map
//**Date: 2018.7.26
//**@author: Mr.xiong
//*****
#include<iostream>
#include<map>  
using namespace std;


//** 链表节点结构体

struct ListNode
{
	int m_key;                //key,value 形式方便map存储。
	int m_value;
	ListNode* pPre;
	ListNode* pNext;
	
	ListNode(int key ,int value)
	{
		m_key = key;
		m_value=value;
		pPre=NULL;
		pNext=NULL;
	}
};

//*  LRU缓存实现类  双向链表。
class LRUCache
{
public:
	//** 构造函数初始化缓存大小
	LRUCache(int size)
	{
		m_capacity = size;
		pHead == NULL;
		pTail == NULL;
	}
	
	~LRUCache()
	{
		//**  一定要注意,map释放内存时,先释放内部new的内存,在释放map的内存
		map<int , ListNode*>::iterator it =mp.begin();
		for(;it!=mp.end();)
		{
			delete it->second;
			it->second = NULL;
			mp.erase(it++);    //** 注意:一定要这样写,it++ 放在其他任何一个地方都会导致其迭代器失效。
		}
		delete pHead;
		pHead == NULL;
		delete pTail;
		pTail ==NULL;
		
	}
	//** 这里只是移除,并不删除节点
	void Remove(ListNode* pNode)
	{
		// 如果是头节点
		if(pNode->pPre == NULL)
		{
			pHead = pNode->pNext;
			pHead->pPre = NULL;
		}
		
		// 如果是尾节点
		if(pNode->pNext == NULL)
		{
			pTail = pNode->pPre;
			pTail->pNext = NULL;
		}
		
		else
		{
			pNode->pPre->pNext=pNode->pNext;
			pNode->pNext->pPre = pNode->pPre;
		}
		 
	}
	//  将节点放到头部,最近用过的数据要放在队头。
	void SetHead(ListNode* pNode)
	{
		pNode->pNext = pHead;
		pNode->pPre = NULL;
		if(pHead == NULL)
		{
			pHead = pNode;
		}
		else
		{
			pHead->pPre=pNode;
			pHead = pNode;
			
		}
		if(pTail == NULL)
		{
			pTail = pHead;
		}
	}
	// * 插入数据,如果存在就只更新数据
	int Set(int key, int value)
	{
		map<int,ListNode*>::iterator it=mp.find(key);
		if(it != mp.end())
		{
			ListNode* Node=it->second;
			Node->m_value=value;
			Remove(Node);
			SetHead(Node);
		}
		else
		{
			ListNode* NewNode = new ListNode(key,value);
			if(mp.size() >= m_capacity)
			{
				map<int,ListNode*>::iterator it=mp.find(pTail->m_key);
				//从链表移除
				Remove(pTail);
				//删除指针指向的内存
				delete it->second;
				//删除map元素
				mp.erase(it);
			}
			//放到头部
			SetHead(NewNode);
			mp[key] = NewNode;
			
		}
	}
	
	
	
	//获取缓存里的数据
	int Get(int key)
	{
		map<int , ListNode*>:: iterator it = mp.find(key);
		if(it != mp.end())
		{
			ListNode* Node=it->second;
			Remove(Node);
			SetHead(Node);
			return Node->m_value;
		}
		else
		{
			return -1;       //这里不太好,有可能取得值也为-1
		}
	}
	
	int GetSize()
	{
		return mp.size();
	}
	
private:
	int m_capacity;    //缓存容量
	ListNode* pHead;   //头节点
	ListNode* pTail;   //尾节点
	map<int, ListNode*>  mp;   //mp用来存数据,达到find为o(1)级别。
	
};

  写了个测试文件:

#include<iostream>
#include"LRUCache.h"

using namespace std;

int main()
{
	LRUCache* lruCache = new LRUCache(3);
	lruCache->Set(1,1);
	lruCache->Set(2,3);
	cout<<lruCache->GetSize()<<endl;
	lruCache->Set(3,5);
	cout<<lruCache->GetSize()<<endl;
	cout<< lruCache->Get(1)<<endl;
	lruCache->Set(6,3);
	cout<<lruCache->GetSize()<<endl;
	cout<< lruCache->Get(3)<<endl;
	cout<< lruCache->Get(1)<<endl;
	cout<< lruCache->Get(2)<<endl;
	
	return 0;
	
}

 其输出结果如下:

      可以看到,当size满了后会把最近未使用的删除掉,这时get到的为-1.代码运行机理正常。

      本代码只是为了更加深入理解学习LRU的一种方式,在实际运用中,还需要考虑很多,也不会这么简单,但基本思路就是这么多了,希望对大家学习LRU有些许帮助。同时,对大家学习c++也有一定的帮助,个人认为在内存管理上还是花费了很多时间去考虑的~

猜你喜欢

转载自blog.csdn.net/qq_38506897/article/details/81218683
今日推荐