C++实现LRU代码

头文件:

#pragma once
#include<map>
using std::map;
//双链表节点
template<typename ElemType>
struct CacheNode
{
	int key;	//页号
	ElemType data;	//值
	CacheNode* pre, * next;
	CacheNode(int k, const ElemType& d, CacheNode<ElemType>* p = nullptr, CacheNode<ElemType>* n = nullptr) :
		key{ k }, data{ d }, pre{ p }, next{ n } {}
	CacheNode() :key{}, data{}, pre{ nullptr }, next{ nullptr } {}
	CacheNode(const CacheNode<ElemType>&) = delete;
	CacheNode<ElemType>& operator=(const CacheNode<ElemType>&) = delete;
};

//双链表
template<typename ElemType>
class CacheLinkList
{
private:
	int maxSize;
	CacheNode<ElemType>* head, * tail;
	map<int, CacheNode<ElemType>*> table;
public:
	CacheLinkList(int size);
	~CacheLinkList();
	void put(int key,const ElemType& data);
	int get(int key);
	void remove(CacheNode<ElemType>* node);
	void setHeadNode(CacheNode<ElemType>* node);
};

//构造函数:初始化maxSize,创建头结点,尾节点
template<typename ElemType>
inline CacheLinkList<ElemType>::CacheLinkList(int size)
{
	maxSize = size;
	head = new CacheNode<ElemType>;
	tail = new CacheNode<ElemType>;

	head->next = tail;
	tail->pre = head;
}



//析构函数:如果头指针,尾指针非空,释放内存
template<typename ElemType>
inline CacheLinkList<ElemType>::~CacheLinkList()
{
	if (head != nullptr)
		delete head;
	if (tail != nullptr)
		delete tail;
}

//添加节点:如果节点已经存在于map中,更新值,设为头结点,否则创建新的节点,设置为
//头结点,设置之前判断缓存是否满
template<typename ElemType>
inline void CacheLinkList<ElemType>::put(int key, const ElemType& data)
{
	auto iter = table.find(key);
	if (iter != table.end())
	{
		//节点已经存在
		auto nodePtr = iter->second;
		nodePtr->data = data;	//更新值
		remove(nodePtr);		//移除当前节点
		setHeadNode(nodePtr);	//设置为头结点
	}
	else
	{
		//需要创建新的节点
		auto nodePtr = new CacheNode<ElemType>{ key,data };
		if (table.size() == maxSize)
			remove(tail->pre);
		setHeadNode(nodePtr);
		table[key] = nodePtr;
	}
}

//获取节点:如果节点不存在,返回-1;存在,返回data,并设置为头结点
template<typename ElemType>
inline int CacheLinkList<ElemType>::get(int key) 
{
	auto iter = table.find(key);
	if (iter == table.end())
		return -1;
	auto nodePtr = iter->second;
	setHeadNode(nodePtr);
	return nodePtr->data;
}

//从双链表中删除节点,参数为节点地址
template<typename ElemType>
inline void CacheLinkList<ElemType>::remove(CacheNode<ElemType>* node)
{
	if (node == nullptr)
		return;
	node->pre->next = node->next;
	node->next->pre = node->pre;
	auto iter = table.find(node->key);
	table.erase(iter);
	delete node;
}

//设置头结点
template<typename ElemType>
inline void CacheLinkList<ElemType>::setHeadNode(CacheNode<ElemType>* node)
{
	if (node == nullptr)
		return;
	node->next = head->next;
	head->next->pre = node;
	node->pre = head;
	head->next = node;
}

测试:

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

using std::cout;
using std::endl;

int main(int argc, char** argv)
{
    CacheLinkList<int>* lruCache = new CacheLinkList<int>(2);
    lruCache->put(2, 1);
    lruCache->put(1, 1);
    cout << lruCache->get(2) << endl;
    lruCache->put(4, 1);
    cout << lruCache->get(1) << endl;
    cout << lruCache->get(2) << endl;
}

上面的这份代码中存在问题:remove函数中进行delete要分情况,只有在put操作时,并且key不在map中,这时才需要delete。否则,在其他测试例子下,会调用已经释放的指针。下面的代码为正确的:

#include<map>
using std::map;

struct CacheNode
{
    int key;
    int val;
    CacheNode* pre,*next;
    CacheNode():key{},val{},pre{nullptr},next{nullptr}{}
    CacheNode(int k,int v):key{k},val{v},pre{nullptr},next{nullptr}{}
};


class LRUCache {
private:
    int maxSize;
    CacheNode* head,*tail;
    map<int,CacheNode*> mp;

public:
    LRUCache(int capacity) 
    {
        head=new CacheNode();
        tail=new CacheNode();
        head->pre=nullptr;
        tail->next=nullptr;
        head->next=tail;
        tail->pre=head;
        maxSize=capacity;
    }
    
    int get(int key)
    {
        auto iter=mp.find(key);
        if(iter==mp.end())
        {//要查找的节点,不存在链表中
            return -1;
        }
        else
        {
            //要查找的节点存在链表中,iter是map中该节点的迭代器
            auto node=iter->second;
            remove(node,false); //从链表中当前位置删除,不释放
            setHead(node);
            return node->val;
        }
    }
    
    void put(int key, int value)
    {
        auto iter=mp.find(key);
        if(iter==mp.end())
        {//节点不存在,需要创建新的节点
            auto node=new CacheNode(key,value);
            if(mp.size()>=maxSize)
            {
                //彻底删除,需要释放,并且从map中移除
                mp.erase(mp.find(tail->pre->key));
                remove(tail->pre,true);
            }
            setHead(node);
            mp[key]=node;
        }
        else
        {//节点已经存在,更新值,从当前位置移除,不释放
            auto node=iter->second;
            node->val=value;
            remove(node,false);
            setHead(node);
        }
    }
    void remove(CacheNode* node,bool isDelete)
    {//负责从链表中删除节点
        node->next->pre=node->pre;
        node->pre->next=node->next;
        if(isDelete)
        {
             delete node;
        }
          
    }
    void setHead(CacheNode* node)
    {
        node->next=head->next;
        head->next->pre=node;
        node->pre=head;
        head->next=node;
    }
};

参考:LRU算法(C++实现)_c++ lru_潇湘夜雨~的博客-CSDN博客

LRU算法详解_忧郁的叮当猫的博客-CSDN博客​​​​​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值