#include #include #include #include #include #include #include "solution.cpp" static int failures = 0; #define CHECK(cond, name) do { if (cond) std::printf("ok %s\n", name); \ else { std::printf("FAIL %s (line %d)\n", name, __LINE__); ++failures; } } while (0) int main() { { HashTable t; CHECK(t.size() == 0, "новая таблица пуста"); CHECK(t.capacity() >= 16 && (t.capacity() & (t.capacity() - 1)) == 0, "capacity — степень двойки и >= 16"); int v = -1; CHECK(t.get(42, v) == false, "get по отсутствующему ключу -> false"); CHECK(t.erase(42) == false, "erase отсутствующего -> false"); } { HashTable t; for (int i = 0; i < 1000; ++i) t.put(i, i * 7); CHECK(t.size() == 1000, "1000 ключей: size == 1000"); bool all = true; for (int i = 0; i < 1000; ++i) { int v = -1; if (!t.get(i, v) || v != i * 7) all = false; } CHECK(all, "1000 ключей: все значения читаются"); t.put(500, 999); int v = -1; CHECK(t.get(500, v) && v == 999, "повторный put обновляет значение"); CHECK(t.size() == 1000, "повторный put не увеличивает size"); } { // ключи с одинаковыми младшими битами — проверка зондирования HashTable t; for (int i = 0; i < 512; ++i) t.put(i * 16, i); bool all = true; for (int i = 0; i < 512; ++i) { int v = -1; if (!t.get(i * 16, v) || v != i) all = false; } CHECK(all, "512 ключей, кратных 16: все находятся (линейное зондирование)"); int missing = -1; CHECK(t.get(15, missing) == false, "нечётный отсутствующий ключ -> false"); } { // удаление посреди цепочки зондирования HashTable t; for (int i = 0; i < 200; ++i) t.put(i * 16, i); CHECK(t.erase(0) == true, "erase существующего -> true"); int v = -1; CHECK(t.get(0, v) == false, "удалённый ключ не найден"); bool rest = true; for (int i = 1; i < 200; ++i) { int x = -1; if (!t.get(i * 16, x) || x != i) rest = false; } CHECK(rest, "остальные ключи из цепочки живы после удаления"); CHECK(t.size() == 199, "size после удаления == 199"); } { const int N = 100000; HashTable t; std::mt19937 rng(4242); std::vector keys(N); for (auto& k : keys) k = int(rng() % 1000000); auto t0 = std::chrono::steady_clock::now(); for (int i = 0; i < N; ++i) t.put(keys[i], i); double sec = std::chrono::duration(std::chrono::steady_clock::now() - t0).count(); std::printf(" (100k вставок: time=%.3fs, capacity=%zu, size=%zu)\n", sec, t.capacity(), t.size()); CHECK(sec < 2.0, "100k вставок за < 2 c"); CHECK(t.size() >= 95000 && t.size() <= 100000, "size в разумных пределах"); CHECK(t.capacity() >= 131072 && t.capacity() <= 262144, "capacity выросла (загрузка <= 0.7)"); bool all = true; for (int i = 0; i < N; ++i) { int v = -1; if (!t.get(keys[i], v)) all = false; } CHECK(all, "все 100k ключей читаются"); int v = -1; CHECK(t.get(-12345, v) == false, "отсутствующий ключ -> false"); } std::printf(failures ? "\nFAILURES: %d\n" : "\nALL PASS\n", failures); return failures ? 1 : 0; }