头文件:
#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;
}
};