import time import random import csv import os def create_node(name, phone): return {'name': name, 'phone': phone, 'next': None} def ll_insert(head, name, phone): if head is None: return create_node(name, phone) if head['name'] == name: head['phone'] = phone return head current = head while current['next'] is not None: if current['next']['name'] == name: current['next']['phone'] = phone return head current = current['next'] current['next'] = create_node(name, phone) return head def ll_find(head, name): current = head while current is not None: if current['name'] == name: return current['phone'] current = current['next'] return None def ll_delete(head, name): if head is None: return None if head['name'] == name: return head['next'] current = head while current['next'] is not None: if current['next']['name'] == name: current['next'] = current['next']['next'] return head current = current['next'] return head def ll_list_all(head): records = [] current = head while current is not None: records.append((current['name'], current['phone'])) current = current['next'] records.sort(key=lambda x: x[0]) return records def hash_function(name, table_size): hash_value = 0 for char in name: hash_value = (hash_value * 31 + ord(char)) % table_size return hash_value def create_hash_table(size=1000): return [None] * size def ht_insert(buckets, name, phone): index = hash_function(name, len(buckets)) buckets[index] = ll_insert(buckets[index], name, phone) return buckets def ht_find(buckets, name): index = hash_function(name, len(buckets)) return ll_find(buckets[index], name) def ht_delete(buckets, name): index = hash_function(name, len(buckets)) buckets[index] = ll_delete(buckets[index], name) return buckets def ht_list_all(buckets): all_records = [] for bucket in buckets: if bucket is not None: records = ll_list_all(bucket) all_records.extend(records) all_records.sort(key=lambda x: x[0]) return all_records def bst_create_node(name, phone): return { 'name': name, 'phone': phone, 'left': None, 'right': None } def bst_insert(root, name, phone): if root is None: return bst_create_node(name, phone) current = root while True: if name < current['name']: if current['left'] is None: current['left'] = bst_create_node(name, phone) return root current = current['left'] elif name > current['name']: if current['right'] is None: current['right'] = bst_create_node(name, phone) return root current = current['right'] else: current['phone'] = phone return root def bst_find(root, name): current = root while current is not None: if name == current['name']: return current['phone'] elif name < current['name']: current = current['left'] else: current = current['right'] return None def bst_find_min(node): current = node while current['left'] is not None: current = current['left'] return current def bst_delete(root, name): if root is None: return None if name < root['name']: root['left'] = bst_delete(root['left'], name) return root elif name > root['name']: root['right'] = bst_delete(root['right'], name) return root if root['left'] is None: return root['right'] elif root['right'] is None: return root['left'] min_node = bst_find_min(root['right']) root['name'] = min_node['name'] root['phone'] = min_node['phone'] root['right'] = bst_delete(root['right'], min_node['name']) return root def bst_inorder_collect(root, records): stack = [] current = root while stack or current: while current is not None: stack.append(current) current = current['left'] current = stack.pop() records.append((current['name'], current['phone'])) current = current['right'] def bst_list_all(root): records = [] bst_inorder_collect(root, records) return records def generate_test_data(n=1000): names = [] for i in range(n): name = f"User_{i:06d}" phone = f"+7-999-{random.randint(1000000, 9999999)}" names.append((name, phone)) shuffled = names.copy() random.shuffle(shuffled) sorted_records = sorted(names, key=lambda x: x[0]) return shuffled, sorted_records def run_insert_benchmark(struct_type, data, struct_params=None): if struct_type == "LinkedList": head = None start = time.perf_counter() for name, phone in data: head = ll_insert(head, name, phone) end = time.perf_counter() return end - start, head elif struct_type == "HashTable": size = struct_params.get('size', 1000) if struct_params else 1000 buckets = create_hash_table(size) start = time.perf_counter() for name, phone in data: buckets = ht_insert(buckets, name, phone) end = time.perf_counter() return end - start, buckets elif struct_type == "BST": root = None start = time.perf_counter() for name, phone in data: root = bst_insert(root, name, phone) end = time.perf_counter() return end - start, root def run_find_benchmark(struct, struct_type, existing_names, non_existing_names): start = time.perf_counter() for name in existing_names: if struct_type == "LinkedList": result = ll_find(struct, name) elif struct_type == "HashTable": result = ht_find(struct, name) elif struct_type == "BST": result = bst_find(struct, name) for name in non_existing_names: if struct_type == "LinkedList": result = ll_find(struct, name) elif struct_type == "HashTable": result = ht_find(struct, name) elif struct_type == "BST": result = bst_find(struct, name) end = time.perf_counter() return end - start def run_delete_benchmark(struct, struct_type, names_to_delete): start = time.perf_counter() for name in names_to_delete: if struct_type == "LinkedList": struct = ll_delete(struct, name) elif struct_type == "HashTable": struct = ht_delete(struct, name) elif struct_type == "BST": struct = bst_delete(struct, name) end = time.perf_counter() return end - start, struct def run_experiment(n_records=1000, n_find=100, n_delete=50, n_repeats=3): print("Генерация тестовых данных...") shuffled_data, sorted_data = generate_test_data(n_records) all_names = [name for name, _ in shuffled_data] find_names = random.sample(all_names, min(n_find, len(all_names))) delete_names = random.sample(all_names, min(n_delete, len(all_names))) non_existing = [f"None_{i}" for i in range(10)] results = [] structures = ["LinkedList", "HashTable", "BST"] modes = ["random", "sorted"] print("\nНачало эксперимента...") print("=" * 80) for struct_type in structures: for mode in modes: data = shuffled_data if mode == "random" else sorted_data mode_rus = "случайный" if mode == "random" else "отсортированный" print(f"\nТестирование: {struct_type}, режим: {mode_rus}") for repeat in range(n_repeats): print(f" Повторение {repeat + 1}/{n_repeats}") insert_time, struct = run_insert_benchmark( struct_type, data, {'size': n_records} if struct_type == "HashTable" else None ) results.append([ struct_type, mode_rus, "вставка", repeat + 1, insert_time ]) find_time = run_find_benchmark( struct, struct_type, find_names, non_existing ) results.append([ struct_type, mode_rus, "поиск", repeat + 1, find_time ]) delete_time, struct = run_delete_benchmark( struct, struct_type, delete_names ) results.append([ struct_type, mode_rus, "удаление", repeat + 1, delete_time ]) return results def save_results_to_csv(results, filename="docs/data/results.csv"): os.makedirs("docs/data", exist_ok=True) with open(filename, 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerow(["Структура", "Режим", "Операция", "Повторение", "Время (сек)"]) writer.writerows(results) print(f"\nРезультаты сохранены в {filename}") def print_statistics(results): print("\n" + "=" * 80) print("СТАТИСТИКА РЕЗУЛЬТАТОВ") print("=" * 80) stats = {} for row in results: struct, mode, op, _, time_val = row key = (struct, mode, op) if key not in stats: stats[key] = [] stats[key].append(time_val) for (struct, mode, op), times in stats.items(): avg_time = sum(times) / len(times) min_time = min(times) max_time = max(times) print(f"\n{struct} - {mode} - {op}:") print(f" Среднее: {avg_time:.6f} сек") print(f" Мин: {min_time:.6f} сек") print(f" Макс: {max_time:.6f} сек") def verify_correctness(): print("\n" + "=" * 80) print("ПРОВЕРКА КОРРЕКТНОСТИ РАБОТЫ") print("=" * 80) test_data = [ ("Alice", "123-456"), ("Bob", "789-012"), ("Charlie", "345-678"), ("Alice", "999-999"), ] structures = { "LinkedList": (None, ll_insert, ll_find, ll_delete, ll_list_all), "HashTable": (create_hash_table(10), ht_insert, ht_find, ht_delete, ht_list_all), "BST": (None, bst_insert, bst_find, bst_delete, bst_list_all) } for name, (struct, insert_func, find_func, delete_func, list_func) in structures.items(): print(f"\n{name}:") for n, p in test_data: struct = insert_func(struct, n, p) print(f" Поиск Alice: {find_func(struct, 'Alice')}") print(f" Поиск Bob: {find_func(struct, 'Bob')}") print(f" Поиск Unknown: {find_func(struct, 'Unknown')}") struct = delete_func(struct, "Bob") print(f" После удаления Bob: {find_func(struct, 'Bob')}") all_records = list_func(struct) print(f" Все записи: {all_records}") def main(): print("ТЕЛЕФОННЫЙ СПРАВОЧНИК - СРАВНЕНИЕ СТРУКТУР ДАННЫХ") print("=" * 80) verify_correctness() print("\n" + "=" * 80) print("ЗАПУСК ЭКСПЕРИМЕНТА") print("=" * 80) N_RECORDS = 1000 N_FIND = 100 N_DELETE = 50 N_REPEATS = 3 print(f"\nПараметры эксперимента:") print(f" Количество записей: {N_RECORDS}") print(f" Поиск: {N_FIND} существующих + 10 отсутствующих") print(f" Удаление: {N_DELETE} записей") print(f" Повторений: {N_REPEATS}") results = run_experiment(N_RECORDS, N_FIND, N_DELETE, N_REPEATS) save_results_to_csv(results) print_statistics(results) print("\n" + "=" * 80) print("ЭКСПЕРИМЕНТ ЗАВЕРШЕН") print("=" * 80) if __name__ == "__main__": main()