diff --git a/MylnikovAS/task_1/docs/data/experiment_part.py b/MylnikovAS/task_1/docs/data/experiment_part.py new file mode 100644 index 0000000..fb8b9dd --- /dev/null +++ b/MylnikovAS/task_1/docs/data/experiment_part.py @@ -0,0 +1,92 @@ +def main(): + N = 10000 + random.seed(42) + + records_sorted = [(f"User_{i:05d}", f"8-999-123-{i:04d}") for i in range(N)] + records_shuffled = records_sorted.copy() + random.shuffle(records_shuffled) + + search_existing = [random.choice(records_sorted)[0] for _ in range(100)] + search_non_existing = [f"None_{i}" for i in range(10)] + search_names = search_existing + search_non_existing + delete_names = [random.choice(records_sorted)[0] for _ in range(50)] + + csv_rows = [["Structure", "Mode", "Operation", "Time (sec)"]] + plot_data = [] + + def run_experiment(struct_type, mode, dataset): + print(f"Start: {struct_type} | Mode: {mode}...") + times_insert, times_find, times_delete = [], [], [] + + for round_idx in range(1, 6): + if struct_type == "LinkedList": container = None + elif struct_type == "HashTable": container = ht_create(size=1000) + elif struct_type == "BST": container = None + + # А. Вставка + start = time.perf_counter() + if struct_type == "LinkedList": + for name, phone in dataset: container = ll_insert(container, name, phone) + elif struct_type == "HashTable": + for name, phone in dataset: ht_insert(container, name, phone) + elif struct_type == "BST": + for name, phone in dataset: container = bst_insert(container, name, phone) + t_ins = time.perf_counter() - start + times_insert.append(t_ins) + csv_rows.append([struct_type, mode, f"insert (number {round_idx})", f"{t_ins:.6f}"]) + + # Б. Поиск + start = time.perf_counter() + if struct_type == "LinkedList": + for name in search_names: ll_find(container, name) + elif struct_type == "HashTable": + for name in search_names: ht_find(container, name) + elif struct_type == "BST": + for name in search_names: bst_find(container, name) + t_find = time.perf_counter() - start + times_find.append(t_find) + csv_rows.append([struct_type, mode, f"find (number {round_idx})", f"{t_find:.6f}"]) + + # В. Удаление + start = time.perf_counter() + if struct_type == "LinkedList": + for name in delete_names: container = ll_delete(container, name) + elif struct_type == "HashTable": + for name in delete_names: ht_delete(container, name) + elif struct_type == "BST": + for name in delete_names: container = bst_delete(container, name) + t_del = time.perf_counter() - start + times_delete.append(t_del) + csv_rows.append([struct_type, mode, f"delete (number {round_idx})", f"{t_del:.6f}"]) + + # Запись средних значений + csv_rows.append([struct_type, mode, "Insert (average)", f"{sum(times_insert)/5:.6f}"]) + csv_rows.append([struct_type, mode, "Find (average)", f"{sum(times_find)/5:.6f}"]) + csv_rows.append([struct_type, mode, "Delete (average)", f"{sum(times_delete)/5:.6f}"]) + + avg_ins = sum(times_insert) / 5 + avg_find = sum(times_find) / 5 + avg_del = sum(times_delete) / 5 + + plot_data.append((struct_type, mode, avg_ins, avg_find, avg_del)) + + # Запуск всех тестов + run_experiment("LinkedList", "random", records_shuffled) + run_experiment("LinkedList", "sorted", records_sorted) + run_experiment("HashTable", "random", records_shuffled) + run_experiment("HashTable", "sorted", records_sorted) + run_experiment("BST", "random", records_shuffled) + run_experiment("BST", "sorted", records_sorted) + + # Сохранение в CSV + with open("results.csv", "w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerows(csv_rows) + print("\n[Успех] Все тесты завершены! Результаты сохранены в 'results.csv'.") + + generate_performance_charts(plot_data) + +if __name__ == '__main__': + experiment_thread = threading.Thread(target=main) + experiment_thread.start() + experiment_thread.join() \ No newline at end of file diff --git a/MylnikovAS/task_1/docs/data/ll_ht_bst.py b/MylnikovAS/task_1/docs/data/ll_ht_bst.py new file mode 100644 index 0000000..a2058f7 --- /dev/null +++ b/MylnikovAS/task_1/docs/data/ll_ht_bst.py @@ -0,0 +1,153 @@ +import csv +import random +import sys +import time +import threading + + +sys.setrecursionlimit(30000) +threading.stack_size(64*1024*1024) + + +def ll_insert(head, name, phone): + """Добавляет запись или обновляет телефон, если имя уже существует. Возвращает новую голову списка.""" + curr = head + while curr is not None: + if curr["name"] == name: + curr["phone"] = phone + return head + curr = curr["next"] + + new_node = {"name": name, "phone": phone, "next": head} + return new_node + +def ll_find(head, name): + """Ищет узел по имени. Возвращает телефон или None.""" + curr = head + while curr is not None: + if curr["name"] == name: + return curr["phone"] + curr = curr["next"] + return None + +def ll_delete(head, name): + """Удаляет узел по имени. Возвращает новую голову списка.""" + curr = head + prev = None + + while curr is not None: + if curr["name"] == name: + if prev is None: + return curr["next"] + else: + prev["next"] = curr["next"] + return head + prev = curr + curr = curr["next"] + + return head + +def ll_list_all(head): + """Собирает все записи в список и сортирует их по имени.""" + records = [] + curr = head + while curr is not None: + records.append((curr["name"], curr["phone"])) + curr = curr["next"] + records.sort(key=lambda x: x[0]) + return records + + +def ht_create(size=1000): + """Создает пустую хеш-таблицу заданного размера.""" + return [None] * size + +def ht_insert(buckets, name, phone): + """Вычисляет индекс бакета и вызывает ll_insert.""" + idx = abs(hash(name)) % len(buckets) + buckets[idx] = ll_insert(buckets[idx], name, phone) + +def ht_find(buckets, name): + """Вычисляет индекс бакета и вызывает ll_find.""" + idx = abs(hash(name)) % len(buckets) + return ll_find(buckets[idx], name) + +def ht_delete(buckets, name): + """Вычисляет индекс бакета и вызывает ll_delete.""" + idx = abs(hash(name)) % len(buckets) + buckets[idx] = ll_delete(buckets[idx], name) + +def ht_list_all(buckets): + """Собирает записи из всех бакетов и сортирует их по имени.""" + records = [] + for head in buckets: + curr = head + while curr is not None: + records.append((curr["name"], curr["phone"])) + curr = curr["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["phone"] = phone + elif name < root["name"]: + root["left"] = bst_insert(root["left"], name, phone) + else: + root["right"] = bst_insert(root["right"], name, 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_delete(root, name): + """Рекурсивное удаление узла из BST.""" + 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"] is not None: + 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): + """Центрированный обход дерева для сбора записей.""" + records = [] + def _inorder(node): + if node is not None: + _inorder(node["left"]) + records.append((node["name"], node["phone"])) + _inorder(node["right"]) + + _inorder(root) + return records \ No newline at end of file diff --git a/MylnikovAS/task_1/docs/data/performance.png b/MylnikovAS/task_1/docs/data/performance.png new file mode 100644 index 0000000..88d8a28 Binary files /dev/null and b/MylnikovAS/task_1/docs/data/performance.png differ diff --git a/MylnikovAS/task_1/docs/data/results.csv b/MylnikovAS/task_1/docs/data/results.csv new file mode 100644 index 0000000..ea90170 --- /dev/null +++ b/MylnikovAS/task_1/docs/data/results.csv @@ -0,0 +1,109 @@ +Structure,Mode,Operation,Time (sec) +LinkedList,random,insert (number 1),4.815837 +LinkedList,random,find (number 1),0.052892 +LinkedList,random,delete (number 1),0.027702 +LinkedList,random,insert (number 2),4.566321 +LinkedList,random,find (number 2),0.049406 +LinkedList,random,delete (number 2),0.024055 +LinkedList,random,insert (number 3),4.912175 +LinkedList,random,find (number 3),0.048987 +LinkedList,random,delete (number 3),0.025564 +LinkedList,random,insert (number 4),5.096061 +LinkedList,random,find (number 4),0.059990 +LinkedList,random,delete (number 4),0.026717 +LinkedList,random,insert (number 5),5.182869 +LinkedList,random,find (number 5),0.055768 +LinkedList,random,delete (number 5),0.027361 +LinkedList,random,Insert (average),4.914653 +LinkedList,random,Find (average),0.053409 +LinkedList,random,Delete (average),0.026280 +LinkedList,sorted,insert (number 1),4.635120 +LinkedList,sorted,find (number 1),0.057343 +LinkedList,sorted,delete (number 1),0.028141 +LinkedList,sorted,insert (number 2),4.673462 +LinkedList,sorted,find (number 2),0.058540 +LinkedList,sorted,delete (number 2),0.030570 +LinkedList,sorted,insert (number 3),4.720830 +LinkedList,sorted,find (number 3),0.050661 +LinkedList,sorted,delete (number 3),0.026368 +LinkedList,sorted,insert (number 4),4.413700 +LinkedList,sorted,find (number 4),0.061699 +LinkedList,sorted,delete (number 4),0.040006 +LinkedList,sorted,insert (number 5),4.487595 +LinkedList,sorted,find (number 5),0.054366 +LinkedList,sorted,delete (number 5),0.031918 +LinkedList,sorted,Insert (average),4.586142 +LinkedList,sorted,Find (average),0.056522 +LinkedList,sorted,Delete (average),0.031401 +HashTable,random,insert (number 1),0.013673 +HashTable,random,find (number 1),0.000142 +HashTable,random,delete (number 1),0.000081 +HashTable,random,insert (number 2),0.012924 +HashTable,random,find (number 2),0.000111 +HashTable,random,delete (number 2),0.000056 +HashTable,random,insert (number 3),0.013575 +HashTable,random,find (number 3),0.000178 +HashTable,random,delete (number 3),0.000090 +HashTable,random,insert (number 4),0.012327 +HashTable,random,find (number 4),0.000112 +HashTable,random,delete (number 4),0.000058 +HashTable,random,insert (number 5),0.012698 +HashTable,random,find (number 5),0.000151 +HashTable,random,delete (number 5),0.000055 +HashTable,random,Insert (average),0.013039 +HashTable,random,Find (average),0.000139 +HashTable,random,Delete (average),0.000068 +HashTable,sorted,insert (number 1),0.012770 +HashTable,sorted,find (number 1),0.000128 +HashTable,sorted,delete (number 1),0.000067 +HashTable,sorted,insert (number 2),0.030806 +HashTable,sorted,find (number 2),0.000143 +HashTable,sorted,delete (number 2),0.000074 +HashTable,sorted,insert (number 3),0.011925 +HashTable,sorted,find (number 3),0.000142 +HashTable,sorted,delete (number 3),0.000072 +HashTable,sorted,insert (number 4),0.012686 +HashTable,sorted,find (number 4),0.000263 +HashTable,sorted,delete (number 4),0.000114 +HashTable,sorted,insert (number 5),0.011504 +HashTable,sorted,find (number 5),0.000139 +HashTable,sorted,delete (number 5),0.000075 +HashTable,sorted,Insert (average),0.015938 +HashTable,sorted,Find (average),0.000163 +HashTable,sorted,Delete (average),0.000080 +BST,random,insert (number 1),0.042690 +BST,random,find (number 1),0.000424 +BST,random,delete (number 1),0.000232 +BST,random,insert (number 2),0.042969 +BST,random,find (number 2),0.000436 +BST,random,delete (number 2),0.000248 +BST,random,insert (number 3),0.041771 +BST,random,find (number 3),0.000462 +BST,random,delete (number 3),0.000280 +BST,random,insert (number 4),0.046081 +BST,random,find (number 4),0.000392 +BST,random,delete (number 4),0.000199 +BST,random,insert (number 5),0.042080 +BST,random,find (number 5),0.000404 +BST,random,delete (number 5),0.000213 +BST,random,Insert (average),0.043118 +BST,random,Find (average),0.000424 +BST,random,Delete (average),0.000234 +BST,sorted,insert (number 1),21.678231 +BST,sorted,find (number 1),0.198191 +BST,sorted,delete (number 1),0.080743 +BST,sorted,insert (number 2),25.945965 +BST,sorted,find (number 2),0.197616 +BST,sorted,delete (number 2),0.095071 +BST,sorted,insert (number 3),25.663677 +BST,sorted,find (number 3),0.194259 +BST,sorted,delete (number 3),0.081219 +BST,sorted,insert (number 4),22.098788 +BST,sorted,find (number 4),0.197365 +BST,sorted,delete (number 4),0.090777 +BST,sorted,insert (number 5),22.467530 +BST,sorted,find (number 5),0.168119 +BST,sorted,delete (number 5),0.071693 +BST,sorted,Insert (average),23.570838 +BST,sorted,Find (average),0.191110 +BST,sorted,Delete (average),0.083900 diff --git a/MylnikovAS/task_1/docs/Отчёт по лабораторной работе.docx b/MylnikovAS/task_1/docs/Отчёт по лабораторной работе.docx new file mode 100644 index 0000000..aacfac1 Binary files /dev/null and b/MylnikovAS/task_1/docs/Отчёт по лабораторной работе.docx differ