From ad50ed566ba52a55eb6b43e4ed78eb36ababae74 Mon Sep 17 00:00:00 2001 From: Smirnovvs Date: Fri, 4 Sep 2026 15:50:54 +0000 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=B2=20=C2=AB?= =?UTF-8?q?/=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- experiment.py | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 experiment.py diff --git a/experiment.py b/experiment.py new file mode 100644 index 0000000..63e0879 --- /dev/null +++ b/experiment.py @@ -0,0 +1,132 @@ +"""Экспериментальное сравнение структур данных.""" + +import argparse +import csv +import random +from pathlib import Path +from statistics import mean +from time import perf_counter + +from phonebook import ( + bst_delete, bst_find, bst_insert, + ht_delete, ht_find, ht_insert, + ll_delete, ll_find, ll_insert, +) + + +def generate_records(size): + return [(f"User_{index:05d}", f"+7{index:010d}") for index in range(size)] + + +def measure_once(structure, records, existing_names, missing_names, deleted_names, bucket_count): + started = perf_counter() + if structure == "LinkedList": + data = None + for name, phone in records: + data = ll_insert(data, name, phone) + insert_time = perf_counter() - started + + started = perf_counter() + for name in existing_names + missing_names: + ll_find(data, name) + find_time = perf_counter() - started + + started = perf_counter() + for name in deleted_names: + data = ll_delete(data, name) + delete_time = perf_counter() - started + elif structure == "HashTable": + data = [None] * bucket_count + for name, phone in records: + ht_insert(data, name, phone) + insert_time = perf_counter() - started + + started = perf_counter() + for name in existing_names + missing_names: + ht_find(data, name) + find_time = perf_counter() - started + + started = perf_counter() + for name in deleted_names: + ht_delete(data, name) + delete_time = perf_counter() - started + else: + data = None + for name, phone in records: + data = bst_insert(data, name, phone) + insert_time = perf_counter() - started + + started = perf_counter() + for name in existing_names + missing_names: + bst_find(data, name) + find_time = perf_counter() - started + + started = perf_counter() + for name in deleted_names: + data = bst_delete(data, name) + delete_time = perf_counter() - started + + return {"insert": insert_time, "find_110": find_time, "delete_50": delete_time} + + +def run_experiment(size=3000, repeats=5, seed=2026, output_dir="docs/data"): + rng = random.Random(seed) + sorted_records = generate_records(size) + shuffled_records = sorted_records.copy() + rng.shuffle(shuffled_records) + modes = {"shuffled": shuffled_records, "sorted": sorted_records} + rows = [] + + for mode, records in modes.items(): + names = [record[0] for record in records] + test_cases = [] + for run in range(1, repeats + 1): + test_cases.append(( + run, + rng.sample(names, min(100, size)), + [f"None_{index}" for index in range(10)], + rng.sample(names, min(50, size)), + )) + for structure in ("LinkedList", "HashTable", "BST"): + for run, existing, missing, deleted in test_cases: + timings = measure_once(structure, records, existing, missing, deleted, max(17, size * 2 + 1)) + for operation, elapsed in timings.items(): + rows.append({ + "structure": structure, + "mode": mode, + "operation": operation, + "run": run, + "time_seconds": elapsed, + }) + + output = Path(output_dir) + output.mkdir(parents=True, exist_ok=True) + raw_path = output / "results_raw.csv" + with raw_path.open("w", newline="", encoding="utf-8-sig") as file: + writer = csv.DictWriter(file, fieldnames=rows[0].keys()) + writer.writeheader() + writer.writerows(rows) + + groups = {} + for row in rows: + key = (row["structure"], row["mode"], row["operation"]) + groups.setdefault(key, []).append(row["time_seconds"]) + summary = [ + {"structure": key[0], "mode": key[1], "operation": key[2], "mean_seconds": mean(values)} + for key, values in groups.items() + ] + summary_path = output / "results_summary.csv" + with summary_path.open("w", newline="", encoding="utf-8-sig") as file: + writer = csv.DictWriter(file, fieldnames=summary[0].keys()) + writer.writeheader() + writer.writerows(summary) + return raw_path, summary_path + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Сравнение структур телефонного справочника") + parser.add_argument("--size", type=int, default=3000) + parser.add_argument("--repeats", type=int, default=5) + args = parser.parse_args() + raw, summary = run_experiment(args.size, args.repeats) + print(f"Полные замеры: {raw}\nСредние значения: {summary}")