import random import time import csv import os import matplotlib.pyplot as plt import numpy as np from sys import setrecursionlimit setrecursionlimit(20000) def ll_insert(head, name, phone): new_node = {'name': name, 'phone': phone, 'next': None} if head is None: return new_node current = head while current: if current['name'] == name: current['phone'] = phone return head if current['next'] is None: break current = current['next'] current['next'] = new_node return head def ll_find(head, name): current = head while current: 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'] prev = head current = head['next'] while current: if current['name'] == name: prev['next'] = current['next'] return head prev = current current = current['next'] return head def ll_list_all(head): records = [] current = head while current: records.append((current['name'], current['phone'])) current = current['next'] records.sort(key=lambda x: x[0]) return records def hash_function(name, size): return sum(ord(ch) for ch in name) % size def ht_create(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) 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) def ht_list_all(buckets): records = [] for head in buckets: current = head while current: records.append((current['name'], current['phone'])) current = current['next'] records.sort(key=lambda x: x[0]) return records 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): if root is None: return None if name == root['name']: return root['phone'] elif name < root['name']: return bst_find(root['left'], name) else: return bst_find(root['right'], name) def bst_min_node(node): current = node while current and current['left']: 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) elif name > root['name']: root['right'] = bst_delete(root['right'], name) else: if root['left'] is None: return root['right'] elif root['right'] is None: return root['left'] temp = bst_min_node(root['right']) root['name'] = temp['name'] root['phone'] = temp['phone'] root['right'] = bst_delete(root['right'], temp['name']) return root def bst_list_all(root, result=None): if result is None: result = [] if root: bst_list_all(root['left'], result) result.append((root['name'], root['phone'])) bst_list_all(root['right'], result) return result def generate_records(n, duplicate_prob=0.1): records = [] for i in range(n): if random.random() < duplicate_prob and i > 0: name = records[random.randint(0, i - 1)][0] else: name = f"User_{random.randint(0, n * 2)}" phone = f"+7-999-{random.randint(1000000, 9999999)}" records.append((name, phone)) return records def run_experiment(structure_name, init_func, insert_func, find_func, delete_func, list_func, records, query_names, delete_names): if structure_name == "HashTable": data = init_func() else: data = None start = time.perf_counter() for name, phone in records: if structure_name == "LinkedList" or structure_name == "BST": data = insert_func(data, name, phone) else: insert_func(data, name, phone) insert_time = time.perf_counter() - start start = time.perf_counter() for name in query_names: find_func(data, name) find_time = time.perf_counter() - start start = time.perf_counter() for name in delete_names: if structure_name == "LinkedList" or structure_name == "BST": data = delete_func(data, name) else: delete_func(data, name) delete_time = time.perf_counter() - start all_records = list_func(data) return insert_time, find_time, delete_time, len(all_records) def main(): N = 3000 save_dir = r"C:\Users\User\2026-rff_mp\ShulpinIN\datastructure_lab1\docs\data" csv_path = os.path.join(save_dir, "results.csv") graph_path = os.path.join(save_dir, "performance_comparison.png") records_original = generate_records(N, duplicate_prob=0.05) records_shuffled = records_original.copy() random.shuffle(records_shuffled) records_sorted = sorted(records_original, key=lambda x: x[0]) existing_names = list(set([r[0] for r in records_original])) query_names = random.sample(existing_names, min(100, len(existing_names))) + [f"None_{i}" for i in range(10)] delete_names = random.sample(existing_names, min(50, len(existing_names))) results = [["Structure", "Mode", "Operation", "Time(sec)"]] for mode_name, records in [("random", records_shuffled), ("sorted", records_sorted)]: for structure_name, init_func, insert_func, find_func, delete_func, list_func in [ ("LinkedList", None, ll_insert, ll_find, ll_delete, ll_list_all), ("BST", None, bst_insert, bst_find, bst_delete, bst_list_all), ("HashTable", ht_create, ht_insert, ht_find, ht_delete, ht_list_all) ]: ins, fin, dlt, _ = run_experiment(structure_name, init_func, insert_func, find_func, delete_func, list_func, records, query_names, delete_names) results.append([structure_name, mode_name, "insert", ins]) results.append([structure_name, mode_name, "search_110", fin]) results.append([structure_name, mode_name, "delete_50", dlt]) with open(csv_path, "w", newline="", encoding='utf-8') as f: writer = csv.writer(f) writer.writerows(results) print(f"Results saved to {csv_path}") structures = ["LinkedList", "HashTable", "BST"] random_insert = [] random_search = [] random_delete = [] sorted_insert = [] sorted_search = [] sorted_delete = [] for row in results[1:]: structure, mode, operation, time_val = row if mode == "random" and operation == "insert": random_insert.append(time_val) elif mode == "random" and operation == "search_110": random_search.append(time_val) elif mode == "random" and operation == "delete_50": random_delete.append(time_val) elif mode == "sorted" and operation == "insert": sorted_insert.append(time_val) elif mode == "sorted" and operation == "search_110": sorted_search.append(time_val) elif mode == "sorted" and operation == "delete_50": sorted_delete.append(time_val) # Построение и сохранение графика fig, axes = plt.subplots(1, 3, figsize=(18, 6)) x = np.arange(len(structures)) width = 0.35 axes[0].bar(x - width / 2, random_insert, width, label="Random", color="steelblue") axes[0].bar(x + width / 2, sorted_insert, width, label="Sorted", color="coral") axes[0].set_xticks(x) axes[0].set_xticklabels(structures) axes[0].set_ylabel("Time (sec)") axes[0].set_title("Insert") axes[0].legend() axes[0].grid(True) axes[1].bar(x - width / 2, random_search, width, label="Random", color="steelblue") axes[1].bar(x + width / 2, sorted_search, width, label="Sorted", color="coral") axes[1].set_xticks(x) axes[1].set_xticklabels(structures) axes[1].set_ylabel("Time (sec)") axes[1].set_title("Search") axes[1].legend() axes[1].grid(True) axes[2].bar(x - width / 2, random_delete, width, label="Random", color="steelblue") axes[2].bar(x + width / 2, sorted_delete, width, label="Sorted", color="coral") axes[2].set_xticks(x) axes[2].set_xticklabels(structures) axes[2].set_ylabel("Time (sec)") axes[2].set_title("Delete") axes[2].legend() axes[2].grid(True) plt.tight_layout() plt.savefig(graph_path, dpi=300) print(f"Graph saved to {graph_path}") plt.show() if __name__ == "__main__": main()