题目
机器翻译
先进先出 ( F I F O ) (FIFO) (FIFO) 的内存置换算法、队列、哈希表
思路
题目很直观,有一个大小受限的内存,如果内存没装满就装,装满了则将最先装入的那一块换掉,再装新的。
这是一种先进先出 ( F I F O ) (FIFO) (FIFO) 的模式,使用队列来模拟再合适不过了。
不过题目又提到在装入内存之前还要先判断一下内存中是否已经存在,如果存在的话就忽略,否则再装。
如果使用队列的话,判断某个元素是否在队列中需要的时间复杂度为 O ( n ) O(n) O(n),这显然不是一种好的算法,所以引入哈希集合来进行优化。
总体思路就是:
- 设置一个计数值,初始为 0
- 读入一个元素,判断其是否在哈希集合中(这个操作的时间复杂度很低,可近似看作 O ( 1 ) O(1) O(1)
2.1 如果在,则忽略
2.2 如果不在,则将其加入哈希集合和队列:如果队列不满,则直接加入;如果队列已满,则先将队首元素移出哈希集合,然后再将队首元素出队,然后再将当前元素入队,并将计数值加一- 重复这个操作直到数据读取完毕。
- 输出计数值
注意
队列和哈希集合可以使用 STL 封装的。但既然是学习,何不自己手搓呢?正好练习一下循环队列。至于哈希集合,这道题的数据很小,直接用数组模拟即可(数据如果很大的话使用库封装的哈希集合比自己手搓的好用)
代码
// 纯C语言
#include <stdio.h>
#define N 1005
#define M 105// 注意C语言中全局变量是会自动初始化为0的
int q[M], h, r; // 队列及其头尾指针,初始 h = r = 0
int set[N]; // 哈希集合,初始全为0,表示没有元素int main(void) {int n = 0, m = 0, x = 0, ans = 0;scanf("%d%d", &m, &n);while (n--) {scanf("%d", &x);if (!set[x]) {// 如果哈希表中不存在,则说明要到外存中找,答案加一ans++;// 加入队列和哈希表set[x] = 1;if ((r + 1) % (m + 1) == h) {// 如果队列是满的,则要先将队首元素出队// 不过在这之前要先将哈希表中的元素删除set[q[h++]] = 0;// 循环if (h == m + 1) h = 0;}// 不管队列是不是满的,都要将当前元素入队// 新元素加入队列q[r++] = x;// 循环if (r == m + 1) r = 0;}}printf("%d\n", ans);return 0;
}