必须构造含时间局部性的工作集模型访问序列才能真实暴露fifo与lru差距;采用std::mt19937均匀生成页号,冷启动阶段跳过前framecount次访问;通过pagereplacementalgo基类统一接口,fifo用queue+unordered_set或循环数组实现,lru用list+unordered_map实现,避免o(n)操作。

准备带局部性的访问序列
用纯随机数生成的页号序列无法暴露 FIFO 和 LRU 的真实差距,必须构造含时间局部性的访问流,否则两者命中率会趋近一致。
创建 std::mt19937 引擎并绑定 std::uniform_int_distribution
采用“工作集模型”:维护一个当前窗口 vector
【必须跳过前 frameCount 次访问不计入命中统计】——冷启动阶段全是缺页,若参与计算会系统性压低 LRU 优势,导致对比失真。
统一接口抽象与算法基类
不为每个算法写独立主循环,定义抽象基类 PageReplacementAlgo,含纯虚函数 access(int page_id) 和 get_hit_count(),强制所有实现遵循同一行为契约。
在构造函数中预分配 std::vector
所有子类(FIFOAlgo、LRUAlgo)必须在 access() 内部完成三件事:查 resident → 更新计数器 → 若缺页则执行置换逻辑;外部调用者只看到 for (int pg : trace) { algo->access(pg); } 这一行。
FIFO 算法实现要点
方法一:std::queue + std::unordered_set 协同
声明 queue
缺页时先 pageFaults++,再判断 if (q.size() == frameCount),满则取 int victim = q.front(); q.pop(); inMemory.erase(victim);最后 q.push(page); inMemory.insert(page)。
【调用 q.front() 前必须断言 !q.empty(),尤其 frameCount == 0 或 trace 极短时,否则未定义行为】
方法二:手写循环数组模拟
用 std::vector
缺页且已满时:int victim = frames[cur]; frames[cur] = page; cur = (cur + 1) % frameCount;同步操作 inMemory.erase(victim); inMemory.insert(page)。
LRU 算法实现要点
用 std::list
命中时:auto it = page_to_iter.find(page); lru_list.splice(lru_list.begin(), lru_list, it->second); page_to_iter[page] = lru_list.begin();注意 splice 后原迭代器失效,必须重赋值。
缺页时:若已满,先 int victim = lru_list.back(); lru_list.pop_back(); page_to_iter.erase(victim);再 lru_list.push_front(page); page_to_iter[page] = lru_list.begin()。
别用 std::vector 模拟 LRU:erase 中间元素是 O(n),10 万次访问下性能断崖式下降。
运行对比与结果输出
初始化帧数为 4,用同一份 trace 调用 FIFOAlgo 和 LRUAlgo 实例;总访问次数固定为 trace.size(),命中率 = (总访问数 − 缺页数) / 总访问数。
输出格式严格为:总访问数: 1000, FIFO缺页: 621, LRU缺页: 487, FIFO命中率: 0.379, LRU命中率: 0.513。
切换算法只需修改构造语句:auto algo = std::make_unique
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











