题目描述
小明的计网实验需要设计一个邻区关系缓存表,用于快速通过本小区LocalCell
查询到邻小区NeighborCell
。缓存表有以下规格限制:
- 当缓存表达到容量限制且需要插入新数据时,需要删除邻区数据。
- 删除策略:
- 使用次数最少的邻区数据。
- 如果有多个使用次数最少的数据,则选择最久未使用的数据。
假设每个LocalCell
至多只有一个NeighborCell
。
输入描述
- 首行:以
capacity:
标识,后跟一个整数表示缓存表的容量。 - 写入操作:以
write:
标识,后跟若干组[LocalCell, NeighborCell]
邻区数据,每组数据占一行。- 如果
LocalCell
已存在,更新其对应的NeighborCell
,并刷新使用时间和次数加1。 - 如果邻区数据被删除,缓存表不再保留其记录。
- 如果
- 读取操作:以
read:
标识,后跟一个LocalCell
,表示读取操作,刷新使用时间和次数加1。 - 查询操作:以
query:
标识,后跟一个LocalCell
,查询其对应的NeighborCell
。
注:
- 写入和读取都表示对
LocalCell
的使用操作。 capacity
、LocalCell
和NeighborCell
都是正整数,范围在[1, 10000]
。- 输入的总行数不超过
30000
行。
输出描述
对于每个查询操作,输出对应的NeighborCell
:
- 如果找到,则返回
NeighborCell
。 - 如果未找到,则返回
-1
。
用例输入
capacity:
3
write:
3
1 2
4 3
2 3
read:
2
write:
1
3 1
query:
1
-1
- 设定容量
capacity
为3
。 - 写入
3
组数据。 - 读取
2
,刷新该邻区对的使用时间和次数。 - 再写入
1
组数据,因为已经超了容量3
,所以把最早输入且未使用的数据"1 2"
剔除。 - 查询
1
,因为已经被剔除了,所以返回-1
。
解题思路
-
数据结构设计:
- 使用
list
存储邻区数据,方便在末尾插入和删除。 - 使用
map<int, map<int, list<node>::iterator>>
记录每个使用次数对应的节点及其使用时间,用于快速找到使用次数最少且最久未使用的节点。 - 使用
map<int, list<node>::iterator>
记录每个LocalCell
对应的节点,方便快速访问和更新。
- 使用
-
操作实现:
- 写入操作:
- 如果
LocalCell
已存在,更新其NeighborCell
,并刷新使用时间和次数。 - 如果缓存表已满,删除使用次数最少且最久未使用的节点。
- 如果
- 读取操作:
- 刷新指定
LocalCell
的使用时间和次数。
- 刷新指定
- 查询操作:
- 如果
LocalCell
存在,返回其对应的NeighborCell
;否则返回-1
。
- 如果
- 写入操作:
-
时间戳管理:
- 使用全局变量
local_time
记录操作的时间戳,确保每次操作的时间唯一。
- 使用全局变量
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
#include<string>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<set>
#include<list>
#include<sstream>
#include<bitset>
#include<stack>
#include<climits>
#include<iomanip>
#include<cstdint>
using namespace std;
struct node {
int local, neighbor;
int nums, times; // 使用次数,对应时间
};
int n; // 关系缓存表大小
list<node> l; // 存放数据
map<int, map<int, list<node>::iterator>> priority; // 使用次数 -> 使用时间 -> 具体节点
map<int, list<node>::iterator> mp; // LocalCell -> 对应节点
int local_time = 0; // 全局时间戳
void change(int k, int v) {
if (mp.find(k) != mp.end()) { // 如果是更新
list<node>::iterator cur = mp[k];
(*cur).neighbor = v;
int nums = (*cur).nums;
int times = (*cur).times;
priority[nums].erase(times); // 更新priority
(*cur).nums++;
(*cur).times = ++local_time;
priority[(*cur).nums][local_time] = cur;
} else { // 插入新数据
if (l.size() == n) { // 如果缓存表已满
list<node>::iterator cur = (*(*priority.begin()).second.begin()).second;
int ck = (*cur).local;
int nums = (*cur).nums;
int times = (*cur).times;
priority[nums].erase(times); // 删除关联数据
mp.erase(ck);
l.erase(cur);
++local_time;
}
if (l.size() < n) { // 插入新节点
node temp;
temp.local = k;
temp.neighbor = v;
temp.nums = 1;
temp.times = ++local_time;
l.push_front(temp);
list<node>::iterator cur = l.begin();
priority[temp.nums][local_time] = cur;
mp[k] = cur;
}
}
}
void read(int k) {
if (mp.find(k) != mp.end()) { // 刷新使用次数和时间
list<node>::iterator cur = mp[k];
int nums = (*cur).nums;
int times = (*cur).times;
priority[nums].erase(times);
(*cur).nums++;
(*cur).times = ++local_time;
priority[(*cur).nums][local_time] = cur;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string input;
cin >> input;
cin >> n;
cin.ignore();
while (cin >> input) {
if (input[0] == 'w') {
int m; // m个数据
cin >> m;
for (int i = 0; i < m; i++) {
int k, v;
cin >> k >> v;
change(k, v);
}
} else if (input[0] == 'r') {
int m;
cin >> m;
read(m);
} else {
int m;
cin >> m;
if (mp.find(m) != mp.end()) {
cout << (*mp[m]).neighbor;
} else {
cout << -1;
}
}
}
return 0;
}