4 条题解
-
0
这是一个完整的 C++ 数据生成器。它不仅生成
.in输入文件,还会利用 STL 的unordered_map作为“标准答案”生成对应的.out输出文件。该生成器包含 10 个测试点,设计逻辑覆盖了:小数据、大数据压测、大量哈希冲突(针对模数攻击)、频繁增删改、扩容触发测试以及边界值测试。
使用说明
- 将下方代码保存为
gen.cpp。 - 编译:
g++ gen.cpp -o gen -O2 -std=c++14 - 运行:
./gen - 运行结束后,当前目录下会生成
1.in/1.out到10.in/10.out。
数据生成器代码 (C++14)
#include <iostream> #include <fstream> #include <vector> #include <string> #include <random> #include <unordered_map> #include <algorithm> #include <chrono> using namespace std; // 配置参数 const int TOTAL_POINTS = 10; const int MAX_KEY = 1000000000; // 随机数生成器初始化 mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); // 生成指定范围内的随机整数 [l, r] int rand_int(int l, int r) { uniform_int_distribution<int> dist(l, r); return dist(rng); } // --------------------------------------------------------- // 标准答案模拟器 (用于生成 .out 文件) // 使用 std::unordered_map 保证逻辑正确性 // --------------------------------------------------------- class StdSolver { unordered_map<int, int> mp; public: void put(int k, int v) { mp[k] = v; } int get(int k) { if (mp.find(k) != mp.end()) { return mp[k]; } return -1; } void remove(int k) { mp.erase(k); } void clear() { mp.clear(); } }; // --------------------------------------------------------- // 测试点生成逻辑 // --------------------------------------------------------- void generate_point(int point_id) { string in_file = to_string(point_id) + ".in"; string out_file = to_string(point_id) + ".out"; ofstream fin(in_file); ofstream fout(out_file); StdSolver solver; vector<int> known_keys; // 用于记录已知存在的key,方便生成有效的get/remove操作 int N; // 操作数量 // 针对不同测试点的策略配置 if (point_id <= 2) { // Points 1-2: 小规模数据,基础功能测试 N = 100; int key_range = 50; fin << N << endl; for (int i = 0; i < N; ++i) { int op = rand_int(0, 2); // 0: put, 1: get, 2: remove if (op == 0) { int k = rand_int(1, key_range); int v = rand_int(1, 1000); fin << "put " << k << " " << v << endl; solver.put(k, v); known_keys.push_back(k); } else if (op == 1) { // 50% 概率查存在的,50% 概率查随机的 int k = (known_keys.empty() || rand_int(0, 1)) ? rand_int(1, key_range) : known_keys[rand_int(0, known_keys.size()-1)]; fin << "get " << k << endl; fout << solver.get(k) << endl; } else { int k = (known_keys.empty() || rand_int(0, 1)) ? rand_int(1, key_range) : known_keys[rand_int(0, known_keys.size()-1)]; fin << "remove " << k << endl; solver.remove(k); } } } else if (point_id <= 4) { // Points 3-4: 纯插入与查询,主要测试扩容后的查找 N = 100000; fin << N << endl; // 前 70% 是插入,后 30% 是查询 for (int i = 0; i < N; ++i) { if (i < N * 0.7) { int k = rand_int(1, MAX_KEY); int v = rand_int(1, MAX_KEY); fin << "put " << k << " " << v << endl; solver.put(k, v); known_keys.push_back(k); } else { int k = (known_keys.empty() || rand_int(0, 3)) ? rand_int(1, MAX_KEY) : known_keys[rand_int(0, known_keys.size()-1)]; fin << "get " << k << endl; fout << solver.get(k) << endl; } } } else if (point_id <= 6) { // Points 5-6: 频繁更新与删除,测试内存复用和链表删除逻辑 N = 100000; fin << N << endl; int key_range = 5000; // 较小的 Key 范围意味着高重复率(Update) for (int i = 0; i < N; ++i) { int op = rand_int(0, 9); // 40% put, 30% get, 30% remove if (op < 4) { int k = rand_int(1, key_range); int v = rand_int(1, MAX_KEY); fin << "put " << k << " " << v << endl; solver.put(k, v); known_keys.push_back(k); } else if (op < 7) { int k = rand_int(1, key_range); fin << "get " << k << endl; fout << solver.get(k) << endl; } else { int k = rand_int(1, key_range); fin << "remove " << k << endl; solver.remove(k); } } } else if (point_id == 7) { // Point 7: 扩容触发测试 (Rehash Stress Test) // 持续插入不同的 Key,强制哈希表从 16 -> 32 -> ... -> 大容量 N = 100000; fin << N << endl; for(int i = 0; i < N; ++i) { // 每隔 100 次做一次查询,其余全插入 if (i % 100 == 0 && !known_keys.empty()) { int k = known_keys[rand_int(0, known_keys.size()-1)]; fin << "get " << k << endl; fout << solver.get(k) << endl; } else { int k = i; // 连续的 key int v = i * 10; fin << "put " << k << " " << v << endl; solver.put(k, v); known_keys.push_back(k); } } } else if (point_id == 8) { // Point 8: 哈希冲突攻击 (Collision Test) // 构造容易冲突的数据。题目初始容量 16,扩容通常是 2 的幂次。 // 生成大量 2^k 倍数的 key,使它们在 key % capacity 时容易撞车。 N = 100000; fin << N << endl; int step = 256; // 2^8, 对低位取模容易冲突 for(int i = 0; i < N; ++i) { int op = rand_int(0, 2); if (op == 0) { int k = (i + 1) * step; // 256, 512, 768... int v = i; fin << "put " << k << " " << v << endl; solver.put(k, v); known_keys.push_back(k); } else if (op == 1) { // 查询操作 int k = (known_keys.empty()) ? step : known_keys[rand_int(0, known_keys.size()-1)]; fin << "get " << k << endl; fout << solver.get(k) << endl; } else { // 删除操作 int k = (known_keys.empty()) ? step : known_keys[rand_int(0, known_keys.size()-1)]; fin << "remove " << k << endl; solver.remove(k); } } } else if (point_id == 9) { // Point 9: 边界情况 (Edge Cases) // Key = 0, Key = MAX_INT, 重复删除不存在的 Key N = 50000; fin << N << endl; vector<int> special_keys = {0, 1, 2, MAX_KEY, MAX_KEY - 1}; for(int i = 0; i < N; ++i) { int op = rand_int(0, 2); int k = special_keys[rand_int(0, special_keys.size() - 1)]; if (op == 0) { int v = rand_int(0, 100); fin << "put " << k << " " << v << endl; solver.put(k, v); } else if (op == 1) { fin << "get " << k << endl; fout << solver.get(k) << endl; } else { fin << "remove " << k << endl; solver.remove(k); } } } else { // Point 10: 综合随机大数据 (Mixed Large) N = 100000; fin << N << endl; for(int i = 0; i < N; ++i) { int op = rand_int(0, 2); int k = (op == 0 || known_keys.empty() || rand_int(0, 3) == 0) ? rand_int(0, MAX_KEY) : known_keys[rand_int(0, known_keys.size()-1)]; if (op == 0) { int v = rand_int(0, MAX_KEY); fin << "put " << k << " " << v << endl; solver.put(k, v); known_keys.push_back(k); } else if (op == 1) { fin << "get " << k << endl; fout << solver.get(k) << endl; } else { fin << "remove " << k << endl; solver.remove(k); } } } fin.close(); fout.close(); cout << "Test point " << point_id << " generated." << endl; } int main() { // 提升 IO 效率,虽然对生成器不是必须的 ios_base::sync_with_stdio(false); cin.tie(NULL); cout << "Generating " << TOTAL_POINTS << " test cases..." << endl; for (int i = 1; i <= TOTAL_POINTS; ++i) { generate_point(i); } cout << "Done! Files 1.in/out through 10.in/out created." << endl; return 0; }数据点设计策略详解
测试点 ID 数据规模 N 说明 考察点 1-2 100 小范围 Key,少量操作 算法正确性,基本逻辑 3-4 100,000 大范围 Key,主要是 put和get大数据量下的基本哈希性能 5-6 Key 范围小 (5000),高频重复 哈希冲突处理 (拉链法)、值更新、链表节点查找 7 连续 Key,只增不减 扩容 (Rehash) 逻辑是否正确,是否因扩容导致超时 8 Key 为 256 的倍数 哈希攻击,测试哈希函数是否均匀,或链表过长时的性能 9 50,000 包含 0, INT_MAX, 不存在的 Key 边界条件,删除不存在的元素,查询空元素 10 100,000 纯随机大数据 综合稳定性测试 注意事项
- 文件大小:输入文件中全是整数和简单的指令字符串。对于 ,每行平均约 15 字节,总大小约 1.5MB,符合 2MB 的限制。
- 效率:使用了
std::unordered_map作为参考答案,其本身效率极高,生成 10 组数据在现代 CPU 上通常在 1 秒内完成。 - 安全性:代码中避免了除以 0,且使用了
vector记录已生成的 key 来保证get和remove操作有较高的命中率(避免全部输出 -1 导致测试无效)。
- 将下方代码保存为
信息
- ID
- 19472
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 5
- 已通过
- 2
- 上传者