import sys sys.setrecursionlimit(30000) csv_path = '/stepinim/docs/data/lab1_results.csv' #Связный список def ll_insert(head, name, phone): new_node = {'name': name, 'phone': phone, 'next': None} if head is None: return new_node curr = head prev = None while curr is not None: if curr['name'] == name: curr['phone'] = phone return head prev = curr curr = curr['next'] prev['next'] = new_node return head def ll_find(head, name): curr = head while curr: if curr['name'] == name: return curr['phone'] curr = curr['next'] return None def ll_delete(head, name): if head is None: return None if head['name'] == name: return head['next'] curr = head while curr['next']: if curr['next']['name'] == name: curr['next'] = curr['next']['next'] return head curr = curr['next'] return head def ll_list_all(head): result = [] curr = head while curr: result.append((curr['name'], curr['phone'])) curr = curr['next'] result.sort(key=lambda x: x[0]) return result #Хэш-таблица HASH_SIZE = 1009 def _hash_name(name): return hash(name) % HASH_SIZE def ht_insert(buckets, name, phone): idx = _hash_name(name) buckets[idx] = ll_insert(buckets[idx], name, phone) def ht_find(buckets, name): idx = _hash_name(name) return ll_find(buckets[idx], name) def ht_delete(buckets, name): idx = _hash_name(name) buckets[idx] = ll_delete(buckets[idx], name) def ht_list_all(buckets): all_entries = [] for bucket in buckets: if bucket is not None: curr = bucket while curr: all_entries.append((curr['name'], curr['phone'])) curr = curr['next'] all_entries.sort(key=lambda x: x[0]) return all_entries #Двоичное дерево поиска def bst_insert(root, name, phone): if root is None: return {'name': name, 'phone': phone, 'left': None, 'right': None} if name < root['name']: root['left'] = bst_insert(root['left'], name, phone) elif name > root['name']: root['right'] = bst_insert(root['right'], name, phone) else: root['phone'] = phone return root def bst_find(root, name): curr = root while curr: if name == curr['name']: return curr['phone'] elif name < curr['name']: curr = curr['left'] else: curr = curr['right'] return None def bst_delete(root, name): if root is None: return None if name < root['name']: root['left'] = bst_delete(root['left'], name) elif name > root['name']: root['right'] = bst_delete(root['right'], name) else: if root['left'] is None: return root['right'] if root['right'] is None: return root['left'] min_node = root['right'] while min_node['left']: min_node = min_node['left'] root['name'] = min_node['name'] root['phone'] = min_node['phone'] root['right'] = bst_delete(root['right'], min_node['name']) return root def bst_list_all(root): result = [] def inorder(node): if node: inorder(node['left']) result.append((node['name'], node['phone'])) inorder(node['right']) inorder(root) return result # ============================================================ # TECT # ============================================================ import os import random import time import csv import pandas as pd import matplotlib.pyplot as plt # ============================================================ # ПОДГОТОВКА ПАПОК # ============================================================ DATA_DIR = os.path.join("docs", "data") os.makedirs(DATA_DIR, exist_ok=True) csv_path = os.path.join(DATA_DIR, "lab1_results.csv") graph_path = os.path.join(DATA_DIR, "lab1_graph.png") # ============================================================ # ТЕСТОВЫЕ ДАННЫЕ # ============================================================ random.seed(42) N = 3000 base_records = [ (f"User_{i:05d}", f"123-{i:05d}") for i in range(N) ] records_shuffled = base_records.copy() random.shuffle(records_shuffled) records_sorted = sorted(base_records, key=lambda x: x[0]) # Поиск search_existing = [ name for name, _ in random.sample(base_records, 100) ] search_nonexist = [ f"None_{i}" for i in range(10) ] # Удаление delete_names = [ name for name, _ in random.sample(base_records, 50) ] # ============================================================ # СОЗДАНИЕ СТРУКТУР # ============================================================ def build_structure(records, struct_type): if struct_type == "ll": structure = None for name, phone in records: structure = ll_insert(structure, name, phone) return structure elif struct_type == "ht": structure = [None] * HASH_SIZE for name, phone in records: ht_insert(structure, name, phone) return structure elif struct_type == "bst": structure = None for name, phone in records: structure = bst_insert(structure, name, phone) return structure # ============================================================ # INSERT # ============================================================ def measure_insert(records, struct_type): start = time.perf_counter() build_structure(records, struct_type) end = time.perf_counter() return end - start # ============================================================ # SEARCH # ============================================================ def measure_search(records, struct_type): structure = build_structure(records, struct_type) start = time.perf_counter() if struct_type == "ll": for name in search_existing + search_nonexist: ll_find(structure, name) elif struct_type == "ht": for name in search_existing + search_nonexist: ht_find(structure, name) elif struct_type == "bst": for name in search_existing + search_nonexist: bst_find(structure, name) end = time.perf_counter() return end - start # ============================================================ # DELETE # ============================================================ def measure_delete(records, struct_type): structure = build_structure(records, struct_type) start = time.perf_counter() if struct_type == "ll": for name in delete_names: structure = ll_delete(structure, name) elif struct_type == "ht": for name in delete_names: ht_delete(structure, name) elif struct_type == "bst": for name in delete_names: structure = bst_delete(structure, name) end = time.perf_counter() return end - start # ============================================================ # ЗАМЕРЫ # ============================================================ all_data = [] experiments = [ ("LinkedList", "ll"), ("HashTable", "ht"), ("BST", "bst") ] modes = [ ("shuffled", records_shuffled), ("sorted", records_sorted) ] for struct_name, struct_type in experiments: for mode_name, records in modes: for rep in range(1, 4): insert_time = measure_insert(records, struct_type) search_time = measure_search(records, struct_type) delete_time = measure_delete(records, struct_type) all_data.append([ struct_name, mode_name, rep, "insert", insert_time ]) all_data.append([ struct_name, mode_name, rep, "search", search_time ]) all_data.append([ struct_name, mode_name, rep, "delete", delete_time ]) # ============================================================ # CSV # ============================================================ with open(csv_path, "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow([ "Структура", "Режим", "Повтор", "Операция", "Время (сек)" ]) writer.writerows(all_data) print(f"CSV сохранён: {csv_path}") # ============================================================ # ГРАФИК # ============================================================ df = pd.read_csv(csv_path) df_avg = ( df.groupby( ["Структура", "Режим", "Операция"] )["Время (сек)"] .mean() .reset_index() ) fig, ax = plt.subplots(figsize=(12, 6)) ops = ["insert", "search", "delete"] x = range(len(ops)) width = 0.12 configs = [ ("LinkedList", "shuffled"), ("LinkedList", "sorted"), ("HashTable", "shuffled"), ("HashTable", "sorted"), ("BST", "shuffled"), ("BST", "sorted") ] for i, (struct, mode) in enumerate(configs): subset = df_avg[ (df_avg["Структура"] == struct) & (df_avg["Режим"] == mode) ] times = [ subset[ subset["Операция"] == op ]["Время (сек)"].values[0] for op in ops ] ax.bar( [p + i * width for p in x], times, width, label=f"{struct} ({mode})" ) ax.set_xticks([p + 2.5 * width for p in x]) ax.set_xticklabels(ops) ax.set_ylabel("Среднее время (сек)") ax.set_title("Сравнение структур данных") ax.legend( bbox_to_anchor=(1.05, 1), loc="upper left" ) plt.tight_layout() plt.savefig(graph_path) print(f"График сохранён: {graph_path}") plt.show()