说明
笔试和面试的时候,经常需要手写LRU,这是一个非常好的数据结构,可以O(1)获取数据,而且还可以自动删除最久未使用的元素。
需求,LRU最多可以存储K个元素,有两个操作get和set:
get存在返回结果,并且更新到最新。
set不存在插入,存在修改值并且更新到最新。
测试数据:
第一行N,K,分别表示接下来多少行,以及LRU最大节点数量。
接下来每一行
1表示set,2表示get
7 2
1 1 1
1 2 2
1 3 3
2 1
2 2
1 4 4
2 3
应该输出 -1 2 -1
新版(用官方的list作为双lian表,易懂)
注意了,list<Node*>::iterator 相当于指向list元素的指针,*it解引用就是一个Node*
struct Node{
int k, v;
};
struct LRU{
map<int, list<Node*>::iterator> mp;
list<Node*> li;
int K;
LRU(int k): K(k){}
void set(int k, int v){
// 如果不存在 插入 并且 判断是否删除最后
if(mp.count(k)==0){
Node* cur = new Node{k, v};
li.push_front(cur);
mp.insert({k, li.begin()});
if(mp.size()>K){
// delete mp
auto del = li.back();
auto it = mp[del->k];
mp.erase(del->k);
// del list
li.pop_back();
}
}
//否则更新
else{
list<Node*>::iterator it = mp[k];
(*it) -> v = v;
get(k);
}
}
int get(int k){
// 如果存在 更新
if(mp.count(k)){
list<Node*>::iterator it = mp[k];
// 摘除
Node* cur = *it;
li.erase(it);
// 插入front
li.push_front(cur);
mp[k] = li.begin(); // mp也要更新
return cur->v;
}
// 否则
return -1;
}
};
int main(int argc, char *argv[])
{
//将标准输入流重定向到 in.txt 文件
// freopen("input.txt", "r", stdin);
int N, K;
cout << "N, K=";
cin >> N >> K;
LRU lru(K);
while(N--){
int op, k, v;
cin >> op;
if(op == 1){
cin >> k >> v;
lru.set(k,v);
}else{
cin >> k;
int ret=lru.get(k);
cout << ret << endl;
}
}
return 0;
}
///
// g++ main.cpp -std=c++14 && ./a.out
代码 (旧版 原始 难懂)
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
using namespace std;
// 节点类型
struct Node
{
int k, v;
struct Node *pre, *nxt;
Node(int i, int j): k(i), v(j)
{
pre = nullptr;
nxt = nullptr;
}
};
// 别名
using MAP=map<int, Node*>;
// 真正的LRU
class LRU
{
int K_; // 最大节点数量
MAP M_; // map
Node* h_, *t_; // 指向头尾的额外节点
public:
LRU(int k){
K_ = k;
h_ = new Node(0,0);
t_ = new Node(0,0);
h_->nxt = t_; // 头尾节点需要互相连起来
t_->pre = h_;
}
void set(int k, int v){
auto it = M_.find(k);
if(it!=M_.end()){ // 如果存在
Node* cur=it->second;
cur->v = v; // update
get(k); //更新即可
return;
}else{ //否则
// new 创建
Node* cur=new Node(k,v);
Node* n = h_->nxt;
// insert
cur->nxt = n;
n->pre = cur;
h_->nxt = cur;
cur->pre = h_;
M_.insert({k, cur});
//need del ?
if (M_.size() > K_){
Node* del=t_->pre;
Node* p = del->pre;
p->nxt = t_;
t_->pre = p;
M_.erase(del->k); // 别忘了这个
delete del;
}
}
}
int get(int k){
auto it = M_.find(k);
if(it!=M_.end()){
// del 别忘了先移除
auto cur = it->second;
auto p = cur->pre;
auto n = cur->nxt;
p->nxt = n;
n->pre = p;
// re insert 再插入
n = h_->nxt;
cur->nxt=n;
n->pre =cur;
h_->nxt = cur;
cur->pre = h_;
return cur->v;
}
return -1;
}
};
int main(int argc, char *argv[])
{
//将标准输入流重定向到 in.txt 文件
// freopen("input.txt", "r", stdin);
int N, K;
cout << "N, K=";
cin >> N >> K;
LRU lru(K);
while(N--){
int op, k, v;
cin >> op;
if(op == 1){
cin >> k >> v;
lru.set(k,v);
}else{
cin >> k;
int ret=lru.get(k);
cout << ret << endl;
}
}
return 0;
}
///
// g++ main.cpp -std=c++14 && ./a.out