整个程序看起来颇为复杂。
如果不考虑效率的话,可以只用一个双向链表。
最近访问的节点就放到队尾。
加入新节点时,也直接放到队尾;如果容量不够就先把队首节点删掉,再把新节点加入队尾。
但是如果考虑到效率。
每次获取和加入节点时,都要判断该节点是否存在(O(n)
)。
因此使用一个hash表来存储key,可以以O(1)
来判断节点是否存在。
并且hash表的value就是对应节点。
//双向链表节点
struct DoubleListNode{
int _key;
int _val;
DoubleListNode* pre;
DoubleListNode* next;
DoubleListNode(int key, int value):_key(key),_val(value),pre(nullptr),next(nullptr){}
};
class LRUCache {
public:
//首尾节点不存储信息,只方便在队首取出节点,在队尾插入节点
LRUCache(int capacity):_capacity(capacity) {
_head = new DoubleListNode(-1,-1);
_tail = new DoubleListNode(-1,-1);
_head->next = _tail;
_tail->pre = _head;
}
int get(int key) {
//如果不存在就返回-1
if(_map.count(key) == 0) return -1;
//如果存在就把节点移到队尾
DoubleListNode* node = _map[key];
kick_node(node);
push_back(node);
return node->_val;
}
void put(int key, int value) {
//如果存在,就更新value,把节点移到队尾
if(_map.count(key)){
DoubleListNode* node = _map[key];
node->_val = value;
kick_node(node);
push_back(node);
}
//如果不存在就准备新建节点,插入到队尾
else{
//如果满了就把删掉队首节点
if(_map.size()==_capacity)
pop_front();
//把新节点加入到hash表以及队尾
DoubleListNode* node = new DoubleListNode(key,value);
_map[key] = node;
push_back(node);
}
}
private:
//从链表以及hash表删去队首节点
void pop_front(){
DoubleListNode* del = _head->next;
_head->next = del->next;
del->next->pre = _head;
_map.erase(del->_key);
delete del;
del = nullptr;
}
//将node加入到队尾
void push_back(DoubleListNode* node){
node->pre = _tail->pre;
node->next = _tail;
_tail->pre->next = node;
_tail->pre = node;
}
//将node从链表移出来(不删除)
void kick_node(DoubleListNode* node){
node->next->pre = node->pre;
node->pre->next = node->next;
node->next = nullptr;
node->pre = nullptr;
}
int _capacity;
map<int,DoubleListNode*> _map;
DoubleListNode* _head;
DoubleListNode* _tail;
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/