diff --git a/SolovevDS/docs/data/data_for_task1/data_structures.py b/SolovevDS/docs/data/data_for_task1/data_structures.py new file mode 100644 index 0000000..0f5879a --- /dev/null +++ b/SolovevDS/docs/data/data_for_task1/data_structures.py @@ -0,0 +1,203 @@ +#--------------------------------------Связный список-------------------------- +def ll_insert(head, name, phone): + # 1. если список пуст → новый элемент становится head + if head is None: + return {'name': name, 'phone': phone,'next': None} + + current = head + # 2. сначала проверим — может имя уже есть → тогда просто обновим + while current is not None: + if current['name'] == name: + current['phone'] = phone + return head + current = current['next'] + # 3. идём до конца списка + current = head + while current['next'] is not None: + current = current['next'] + # 4. добавляем новый узел в конец + current['next'] = {'name': name,'phone': phone,'next': None} + + 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): + current = head + previous = None + + while current is not None: + if current['name'] == name: + + # 1. удаляем голову списка + if previous is None: + return current['next'] + + # 2. удаляем середину или конец + previous['next'] = current['next'] + return head + + previous = current + current = current['next'] + + return head # если не нашли + +def ll_list_all(head): + result = [] + current = head + # 1. проходим по списку + while current is not None: + result.append((current['name'], current['phone'])) + current = current['next'] + # 2. сортируем по имени + result.sort(key=lambda x: x[0]) + + return result + + +#----------------------------------HASH-таблица-------------------------------- +def my_hash(s, M): + B = 31 + n = len(s) + h = 0 + for i in range(n): + h += ord(s[i]) * (B ** (n - 1 - i)) + return h % M + +def ht_insert(buckets, name, phone): + index = my_hash(name, len(buckets)) + buckets[index] = ll_insert(buckets[index], name, phone) + return buckets + + +def ht_find(buckets, name): + index = my_hash(name, len(buckets)) + return ll_find(buckets[index], name) + +def ht_delete(buckets, name): + index = my_hash(name, len(buckets)) + buckets[index] = ll_delete(buckets[index], name) + return buckets + +def ht_list_all(buckets): + result = [] + for i in range(len(buckets)): + result += ll_list_all(buckets[i]) + result.sort(key=lambda x: x[0]) + return result + +#---------------------------Двоичное дерево поиска----------------------------- +def bst_insert(root, name, phone): + if root is None: + return {'name': name, 'phone': phone,'left': None, 'right': None} + + current = root + while True: + # если такое имя уже есть — меняем телефон + if name == current['name']: + current['phone'] = phone + return root + + # если новое имя меньше — идём влево + if name < current['name']: + if current['left'] is None: + current['left'] = {'name': name, 'phone': phone,'left': None, 'right': None} + return root + current = current['left'] + + # если новое имя больше — идём вправо + else: + if current['right'] is None: + current['right'] = {'name': name, 'phone': phone,'left': None, 'right': None} + return root + current = current['right'] + +def bst_find(root, name): + current = root + + while current is not None: + if name == current['name']: + return current['phone'] + + if name < current['name']: + current = current['left'] + else: + current = current['right'] + + return None + +def bst_delete(root, name): + current = root + previous = None + + while current is not None and current['name'] != name: + previous = current + + if name < current['name']: + current = current['left'] + else: + current = current['right'] + + # если не нашли + if current is None: + return root + + # 2. Если у узла два потомка + if current['left'] is not None and current['right'] is not None: + successor_parent = current + successor = current['right'] + + # ищем минимальный узел в правом поддереве + while successor['left'] is not None: + successor_parent = successor + successor = successor['left'] + + # копируем данные successor в current + current['name'] = successor['name'] + current['phone'] = successor['phone'] + + # теперь удаляем successor + current = successor + previous = successor_parent + #3 + if current['left'] is not None: + child = current['left'] + else: + child = current['right'] + + # 4. Если удаляем корень + if previous is None: + return child + + # 5. Переподключаем родителя + if previous['left'] is current: + previous['left'] = child + else: + previous['right'] = child + + return root + +def bst_list_all(root): + result = [] + + def inorder(node): + if node is None: + return + + inorder(node['left']) + result.append((node['name'], node['phone'])) + inorder(node['right']) + + inorder(root) + return result + diff --git a/SolovevDS/docs/data/data_for_task1/delete_chart.svg b/SolovevDS/docs/data/data_for_task1/delete_chart.svg new file mode 100644 index 0000000..a76383b --- /dev/null +++ b/SolovevDS/docs/data/data_for_task1/delete_chart.svg @@ -0,0 +1,1298 @@ + + + + + + + + 2026-05-01T11:55:48.214974 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SolovevDS/docs/data/data_for_task1/diagramm.py b/SolovevDS/docs/data/data_for_task1/diagramm.py new file mode 100644 index 0000000..222ff2d --- /dev/null +++ b/SolovevDS/docs/data/data_for_task1/diagramm.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +""" +Created on Fri May 1 11:42:31 2026 + +@author: ddima +""" + +import matplotlib.pyplot as plt +import numpy as np + +data = { + ("LinkedList", "shuffled", "insert"): 3.46348492, + ("HashTable", "shuffled", "insert"): 0.01967166, + ("BST", "shuffled", "insert"): 0.01715242, + + ("LinkedList", "shuffled", "find"): 0.0301834, + ("HashTable", "shuffled", "find"): 0.0002298400002, + ("BST", "shuffled", "find"): 0.0002346200003, + + ("LinkedList", "shuffled", "delete"): 0.01254974, + ("HashTable", "shuffled", "delete"): 0.0001220800004, + ("BST", "shuffled", "delete"): 0.0001421199995, + + ("LinkedList", "sorted", "insert"): 3.2739972, + ("HashTable", "sorted", "insert"): 0.01923022, + ("BST", "sorted", "insert"): 4.01406982, + + ("LinkedList", "sorted", "find"): 0.0252881, + ("HashTable", "sorted", "find"): 0.0002579799999, + ("BST", "sorted", "find"): 0.0369953, + + ("LinkedList", "sorted", "delete"): 0.01326564, + ("HashTable", "sorted", "delete"): 0.0001182399996, + ("BST", "sorted", "delete"): 0.02074794, +} + +structures = ["BST", "LinkedList", "HashTable"] +structure_labels = ["Бинарное дерево", "Связный список", "Хэш-таблица"] + +operations = [("insert", "Вставка"), ("find", "Поиск"), ("delete", "Удаление"),] + +for op_key, op_title in operations: + shuffled_values = [data[(s, "shuffled", op_key)] for s in structures] + sorted_values = [data[(s, "sorted", op_key)] for s in structures] + + x = np.arange(len(structures)) + width = 0.35 + + plt.figure(figsize=(8, 5)) + + plt.bar(x - width / 2, shuffled_values, width, label="Случайный") + plt.bar(x + width / 2, sorted_values, width, label="Отсортированный") + + plt.title(op_title) + plt.ylabel("Время (сек)") + plt.xticks(x, structure_labels) + plt.legend() + plt.grid(axis="y", alpha=0.3) + plt.tight_layout() + + plt.savefig(f"{op_key}_chart.svg", format="svg") + plt.show() \ No newline at end of file diff --git a/SolovevDS/docs/data/data_for_task1/experements_with_structures.py b/SolovevDS/docs/data/data_for_task1/experements_with_structures.py new file mode 100644 index 0000000..3aaf000 --- /dev/null +++ b/SolovevDS/docs/data/data_for_task1/experements_with_structures.py @@ -0,0 +1,240 @@ +import data_structures as st +import time +import random +import csv + + +def generate_records(N): + records = [] + + for i in range(N): + name = f"User_{i:05d}" + phone = f"+7{random.randint(10**9, 10**10 - 1)}" + records.append((name, phone)) + + records_shuffled = records[:] + random.shuffle(records_shuffled) + + records_sorted = sorted(records, key=lambda x: x[0]) + + return records_shuffled, records_sorted + +def linked_list_build_structure(records): + head = None + + for name, phone in records: + head = st.ll_insert(head, name, phone) + + return head + +def hash_table_build_structure(records): + buckets = [None] * 10007 + + for name, phone in records: + buckets = st.ht_insert(buckets, name, phone) + + return buckets + +def bst_build_structure(records): + root = None + + for name, phone in records: + root = st.bst_insert(root, name, phone) + + return root + +def measure_time(func, *args): + start = time.perf_counter() + result = func(*args) + end = time.perf_counter() + + return result, end - start + +def prepare_find_names(records): + existing_names = [name for name, phone in records] + + find_existing = random.sample(existing_names, 100) + + find_missing = [] + for i in range(10): + find_missing.append(f"None_{i}") + find_names = find_existing + find_missing + return find_names + + +def linked_list_find(head, find_names): + results = [] + for name in find_names: + phone = st.ll_find(head, name) + results.append(phone) + return results + +def hash_table_find(buckets, find_names): + results = [] + for name in find_names: + phone = st.ht_find(buckets, name) + results.append(phone) + return results + +def bst_find(root, find_names): + results = [] + for name in find_names: + phone = st.bst_find(root, name) + results.append(phone) + return results + +def prepare_delete_names(records): + existing_names = [name for name, phone in records] + delete_names = random.sample(existing_names, 50) + return delete_names + + +def linked_list_delete(head, delete_names): + for name in delete_names: + head = st.ll_delete(head, name) + return head + +def hash_table_delete(buckets, delete_names): + for name in delete_names: + buckets = st.ht_delete(buckets, name) + return buckets + +def bst_delete(root, delete_names): + for name in delete_names: + root = st.bst_delete(root, name) + return root + + +def run_one_experiment(records_shuffled, records_sorted, find_names, delete_names): + one_run_results = [] + #------------------------ создание структур + замер времени заполнения ------------------------- + # ------------------- shuffled ------------------- + head_shuffled, ll_insert_time_shuffled = measure_time(linked_list_build_structure,records_shuffled) + + buckets_shuffled, ht_insert_time_shuffled = measure_time(hash_table_build_structure,records_shuffled) + + root_shuffled, bst_insert_time_shuffled = measure_time(bst_build_structure,records_shuffled) + + + # ------------------- sorted ------------------- + + head_sorted, ll_insert_time_sorted = measure_time(linked_list_build_structure,records_sorted) + + buckets_sorted, ht_insert_time_sorted = measure_time(hash_table_build_structure,records_sorted) + + root_sorted, bst_insert_time_sorted = measure_time(bst_build_structure,records_sorted) + + + + # ------------------- поиск в shuffled ------------------- + + ll_find_results_shuffled, ll_find_time_shuffled = measure_time(linked_list_find,head_shuffled,find_names) + + ht_find_results_shuffled, ht_find_time_shuffled = measure_time(hash_table_find,buckets_shuffled,find_names) + + bst_find_results_shuffled, bst_find_time_shuffled = measure_time(bst_find,root_shuffled,find_names) + + + # ------------------- поиск в sorted ------------------- + + ll_find_results_sorted, ll_find_time_sorted = measure_time(linked_list_find,head_sorted,find_names) + + ht_find_results_sorted, ht_find_time_sorted = measure_time(hash_table_find,buckets_sorted,find_names) + + bst_find_results_sorted, bst_find_time_sorted = measure_time(bst_find,root_sorted,find_names) + + + + # ------------------- удаление в shuffled ------------------- + + head_shuffled, ll_delete_time_shuffled = measure_time(linked_list_delete,head_shuffled,delete_names) + + buckets_shuffled, ht_delete_time_shuffled = measure_time(hash_table_delete,buckets_shuffled,delete_names) + + root_shuffled, bst_delete_time_shuffled = measure_time(bst_delete,root_shuffled,delete_names) + + # ------------------- удаление в sorted ------------------- + + head_sorted, ll_delete_time_sorted = measure_time(linked_list_delete,head_sorted,delete_names) + + buckets_sorted, ht_delete_time_sorted = measure_time(hash_table_delete,buckets_sorted,delete_names) + + root_sorted, bst_delete_time_sorted = measure_time(bst_delete,root_sorted,delete_names) + + one_run_results.append(["LinkedList", "shuffled", "insert", ll_insert_time_shuffled]) + one_run_results.append(["HashTable", "shuffled", "insert", ht_insert_time_shuffled]) + one_run_results.append(["BST", "shuffled", "insert", bst_insert_time_shuffled]) + + one_run_results.append(["LinkedList", "shuffled", "find", ll_find_time_shuffled]) + one_run_results.append(["HashTable", "shuffled", "find", ht_find_time_shuffled]) + one_run_results.append(["BST", "shuffled", "find", bst_find_time_shuffled]) + + one_run_results.append(["LinkedList", "shuffled", "delete", ll_delete_time_shuffled]) + one_run_results.append(["HashTable", "shuffled", "delete", ht_delete_time_shuffled]) + one_run_results.append(["BST", "shuffled", "delete", bst_delete_time_shuffled]) + + one_run_results.append(["LinkedList", "sorted", "insert", ll_insert_time_sorted]) + one_run_results.append(["HashTable", "sorted", "insert", ht_insert_time_sorted]) + one_run_results.append(["BST", "sorted", "insert", bst_insert_time_sorted]) + + one_run_results.append(["LinkedList", "sorted", "find", ll_find_time_sorted]) + one_run_results.append(["HashTable", "sorted", "find", ht_find_time_sorted]) + one_run_results.append(["BST", "sorted", "find", bst_find_time_sorted]) + + one_run_results.append(["LinkedList", "sorted", "delete", ll_delete_time_sorted]) + one_run_results.append(["HashTable", "sorted", "delete", ht_delete_time_sorted]) + one_run_results.append(["BST", "sorted", "delete", bst_delete_time_sorted]) + + return one_run_results + + +N = 10000 +REPEATS = 5 +records_shuffled, records_sorted = generate_records(N) +find_names = prepare_find_names(records_sorted) +delete_names = prepare_delete_names(records_sorted) + +results = [["Запуск", "Структура", "Режим", "Операция", "Время (сек)"]] + +for run in range(1, REPEATS + 1): + print("Запуск эксперимента:", run) + + one_run_results = run_one_experiment(records_shuffled,records_sorted,find_names,delete_names) + + for row in one_run_results: + structure = row[0] + mode = row[1] + operation = row[2] + elapsed = row[3] + + results.append([run, structure, mode, operation, elapsed]) + +groups = {} + +for row in results[1:]: + structure = row[1] + mode = row[2] + operation = row[3] + elapsed = row[4] + + key = (structure, mode, operation) + + if key not in groups: + groups[key] = [] + + groups[key].append(elapsed) + + +for key, times in groups.items(): + structure, mode, operation = key + avg_time = sum(times) / len(times) + + results.append(["average", structure, mode, operation, avg_time]) + + +with open("results.csv", "w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerows(results) + +print("Результаты сохранены в results.csv") + diff --git a/SolovevDS/docs/data/data_for_task1/find_chart.svg b/SolovevDS/docs/data/data_for_task1/find_chart.svg new file mode 100644 index 0000000..24d75bf --- /dev/null +++ b/SolovevDS/docs/data/data_for_task1/find_chart.svg @@ -0,0 +1,1282 @@ + + + + + + + + 2026-05-01T11:55:48.061991 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SolovevDS/docs/data/data_for_task1/insert_chart.svg b/SolovevDS/docs/data/data_for_task1/insert_chart.svg new file mode 100644 index 0000000..dc6bc2b --- /dev/null +++ b/SolovevDS/docs/data/data_for_task1/insert_chart.svg @@ -0,0 +1,1296 @@ + + + + + + + + 2026-05-01T11:55:47.872131 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SolovevDS/docs/data/data_for_task1/results.csv b/SolovevDS/docs/data/data_for_task1/results.csv new file mode 100644 index 0000000..9e8a000 --- /dev/null +++ b/SolovevDS/docs/data/data_for_task1/results.csv @@ -0,0 +1,109 @@ +Запуск,Структура,Режим,Операция,Время (сек) +1,LinkedList,shuffled,insert,3.4127272000005178 +1,HashTable,shuffled,insert,0.019356400000106078 +1,BST,shuffled,insert,0.01772239999991143 +1,LinkedList,shuffled,find,0.029260500003147172 +1,HashTable,shuffled,find,0.00023599999985890463 +1,BST,shuffled,find,0.00022670000180369243 +1,LinkedList,shuffled,delete,0.011755700001231162 +1,HashTable,shuffled,delete,0.00011840000297524966 +1,BST,shuffled,delete,0.00014689999807160348 +1,LinkedList,sorted,insert,3.2256927999987965 +1,HashTable,sorted,insert,0.019139899999572663 +1,BST,sorted,insert,4.1095220999995945 +1,LinkedList,sorted,find,0.024785800000245217 +1,HashTable,sorted,find,0.00022289999833446927 +1,BST,sorted,find,0.03631210000094143 +1,LinkedList,sorted,delete,0.012450800000806339 +1,HashTable,sorted,delete,0.00011539999832166359 +1,BST,sorted,delete,0.0211152999982005 +2,LinkedList,shuffled,insert,3.3890004999993835 +2,HashTable,shuffled,insert,0.019052899999223882 +2,BST,shuffled,insert,0.01668930000232649 +2,LinkedList,shuffled,find,0.028735200001392514 +2,HashTable,shuffled,find,0.00022629999875789508 +2,BST,shuffled,find,0.00024219999977503903 +2,LinkedList,shuffled,delete,0.01258820000293781 +2,HashTable,shuffled,delete,0.00011489999815239571 +2,BST,shuffled,delete,0.00014340000052470714 +2,LinkedList,sorted,insert,3.256336700000247 +2,HashTable,sorted,insert,0.018892399999458576 +2,BST,sorted,insert,3.978548999999475 +2,LinkedList,sorted,find,0.02532219999920926 +2,HashTable,sorted,find,0.00022780000290367752 +2,BST,sorted,find,0.036961199999495875 +2,LinkedList,sorted,delete,0.013499500000762055 +2,HashTable,sorted,delete,0.00011860000086016953 +2,BST,sorted,delete,0.02029960000072606 +3,LinkedList,shuffled,insert,3.4580803999997443 +3,HashTable,shuffled,insert,0.019483100000798004 +3,BST,shuffled,insert,0.017162699998152675 +3,LinkedList,shuffled,find,0.029887100001360523 +3,HashTable,shuffled,find,0.00023090000104275532 +3,BST,shuffled,find,0.00023660000078962184 +3,LinkedList,shuffled,delete,0.01279649999924004 +3,HashTable,shuffled,delete,0.00014880000162520446 +3,BST,shuffled,delete,0.0001424999973096419 +3,LinkedList,sorted,insert,3.3060915999994904 +3,HashTable,sorted,insert,0.020634799999243114 +3,BST,sorted,insert,3.999759400001494 +3,LinkedList,sorted,find,0.025299299999460345 +3,HashTable,sorted,find,0.00022419999731937423 +3,BST,sorted,find,0.03626530000110506 +3,LinkedList,sorted,delete,0.012905700001283549 +3,HashTable,sorted,delete,0.00012069999866071157 +3,BST,sorted,delete,0.020299800002248958 +4,LinkedList,shuffled,insert,3.490586699997948 +4,HashTable,shuffled,insert,0.020179600000119535 +4,BST,shuffled,insert,0.017119400003139162 +4,LinkedList,shuffled,find,0.030576699999073753 +4,HashTable,shuffled,find,0.00022309999985736795 +4,BST,shuffled,find,0.00023399999918183312 +4,LinkedList,shuffled,delete,0.012583200001245132 +4,HashTable,shuffled,delete,0.00011319999975967221 +4,BST,shuffled,delete,0.00013839999883202836 +4,LinkedList,sorted,insert,3.2922638000018196 +4,HashTable,sorted,insert,0.018590499999845633 +4,BST,sorted,insert,4.008463900001516 +4,LinkedList,sorted,find,0.025681600000098115 +4,HashTable,sorted,find,0.0002204000011261087 +4,BST,sorted,find,0.0370997999998508 +4,LinkedList,sorted,delete,0.013347899999644142 +4,HashTable,sorted,delete,0.00011789999916800298 +4,BST,sorted,delete,0.021108500000991626 +5,LinkedList,shuffled,insert,3.567029800000455 +5,HashTable,shuffled,insert,0.020286300001316704 +5,BST,shuffled,insert,0.017068300003302284 +5,LinkedList,shuffled,find,0.0324575000013283 +5,HashTable,shuffled,find,0.00023290000171982683 +5,BST,shuffled,find,0.00023359999977401458 +5,LinkedList,shuffled,delete,0.013025099997321377 +5,HashTable,shuffled,delete,0.00011509999967529438 +5,BST,shuffled,delete,0.00013940000280854292 +5,LinkedList,sorted,insert,3.289601099997526 +5,HashTable,sorted,insert,0.01889350000055856 +5,BST,sorted,insert,3.9740547000001243 +5,LinkedList,sorted,find,0.02535160000115866 +5,HashTable,sorted,find,0.00039459999970858917 +5,BST,sorted,find,0.038338099999236874 +5,LinkedList,sorted,delete,0.014124299999821233 +5,HashTable,sorted,delete,0.00011860000086016953 +5,BST,sorted,delete,0.0209164999978384 +average,LinkedList,shuffled,insert,3.4634849199996096 +average,HashTable,shuffled,insert,0.01967166000031284 +average,BST,shuffled,insert,0.01715242000136641 +average,LinkedList,shuffled,find,0.030183400001260453 +average,HashTable,shuffled,find,0.00022984000024734997 +average,BST,shuffled,find,0.0002346200002648402 +average,LinkedList,shuffled,delete,0.012549740000395104 +average,HashTable,shuffled,delete,0.00012208000043756329 +average,BST,shuffled,delete,0.00014211999950930476 +average,LinkedList,sorted,insert,3.273997199999576 +average,HashTable,sorted,insert,0.01923021999973571 +average,BST,sorted,insert,4.014069820000441 +average,LinkedList,sorted,find,0.02528810000003432 +average,HashTable,sorted,find,0.0002579799998784438 +average,BST,sorted,find,0.036995300000126005 +average,LinkedList,sorted,delete,0.013265640000463463 +average,HashTable,sorted,delete,0.00011823999957414344 +average,BST,sorted,delete,0.02074794000000111 diff --git a/SolovevDS/docs/data/data_for_task2/diagrams.py b/SolovevDS/docs/data/data_for_task2/diagrams.py new file mode 100644 index 0000000..7ff2bde --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/diagrams.py @@ -0,0 +1,76 @@ +import pandas as pd +import matplotlib.pyplot as plt +import numpy as np + +df = pd.read_csv("results.csv") + +maze_order = ["small_10", "medium_50", "large_100", "empty", "no_path"] +strategy_order = ["BFS", "DFS", "AStar"] + +maze_labels = { + "small_10": "10×10", + "medium_50": "50×50", + "large_100": "100×100", + "empty": "Пустой", + "no_path": "Без выхода" +} + +df["maze"] = pd.Categorical(df["maze"], categories=maze_order, ordered=True) +df["strategy"] = pd.Categorical(df["strategy"], categories=strategy_order, ordered=True) +df = df.sort_values(["maze", "strategy"]) + + +def plot_grouped_bar(df, value_col, ylabel, title, filename): + mazes = maze_order + strategies = strategy_order + + x = np.arange(len(mazes)) + width = 0.25 + + plt.figure(figsize=(11, 6)) + + for i, strategy in enumerate(strategies): + values = [] + + for maze in mazes: + row = df[(df["maze"] == maze) & (df["strategy"] == strategy)] + values.append(row[value_col].values[0]) + + plt.bar(x + (i - 1) * width, values, width, label=strategy) + + plt.xlabel("Лабиринт") + plt.ylabel(ylabel) + plt.title(title) + + plt.xticks(x, [maze_labels[m] for m in mazes], rotation=20) + plt.legend(title="Стратегия") + plt.grid(axis="y", alpha=0.3) + + plt.tight_layout() + plt.savefig(filename, format="svg") + plt.show() + + +plot_grouped_bar( + df, + value_col="time_ms", + ylabel="Время, мс", + title="Сравнение времени выполнения BFS, DFS и A*", + filename="time_comparison.svg" +) + +plot_grouped_bar( + df, + value_col="cells_visited", + ylabel="Количество посещённых клеток", + title="Сравнение количества посещённых клеток", + filename="visited_cells_comparison.svg" +) + +plot_grouped_bar( + df, + value_col="way_len", + ylabel="Длина пути, клеток", + title="Сравнение длины найденного пути", + filename="path_length_comparison.svg" +) \ No newline at end of file diff --git a/SolovevDS/docs/data/data_for_task2/maze10.txt b/SolovevDS/docs/data/data_for_task2/maze10.txt new file mode 100644 index 0000000..8ffe41a --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/maze10.txt @@ -0,0 +1,10 @@ +########## +#S ### +###### ### +# ### +# #### ### +# # ### +# # ###### +# # # +# ######E# +########## diff --git a/SolovevDS/docs/data/data_for_task2/maze100.txt b/SolovevDS/docs/data/data_for_task2/maze100.txt new file mode 100644 index 0000000..2bd6ce0 --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/maze100.txt @@ -0,0 +1,100 @@ +#################################################################################################### +#S # # # # # # # # # ## +## ############### # ## ## ###### # ### ### ### ########### ### # ## # ####### # ### # # # ## +# # # # # # # # # # # # # # # # # # # ## +# ### # ##### # #### ##### ######### # ##### # ##### # ### ##### ### # # ### # ####### ##### # ## +# # # # # # # # # # # # # # # # # # # # # # # # # ## +# ##### ### ##### ##### # # ### # ##### # ##### # ####### ######### ##### # # # # ### ### # # ## +# # # # # # # # # # # # # # # # # # # # # # # # # ## +# # # ### # # # ### # ##### ### ### # # ##### # # # ### # # ##### ### ##### ### ########### ### ## +# # # # # # # # # # # # # # # # # # # # # # # # # ## +# # ### ########### # # ### # ### # # ### # ### # ##### # ####### #### ## # ### ######### ####### ## +# # # # # # # # # # # # # # # # # # ## +# ####### ### # # # ### # ### ################# ############# # ### ## ### ## # ### ### # # # # #### +# # # # # # # # # # # # # # # # # # # # # # ## +####### ### ### ##### ### # # ########### # ####### ### # ### # ##### # # ##### ### # ### ##### ## +# # # # # # # # # # # # # # # # # # # # # # # # # ## +# ### # # ### ####### # # ##### ### # ### ### # ### # # # # ##### # # ########### # ##### # # ###### +# # # # # # # # # # # # # # # # # # # # # # # # # # ## +# # ##### #### # # # # # # ## ## # # ### ##### ### # ####### ### ####### # # # # ### # # ##### ## +# # # # # # # # # # # # # # # # # # # # # # # # # ## +# # ## # # # ### ####### # # # ##### # # ## # # # ######### ### ####### # ### ### # # # ### # # ## +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## +# ##### ### # # ##### # ### ##### # ### ### ### ##### # # # ### ###### ##### # # # # ##### ### # ## +# # # # # # # # # # # # # # # # # # # # # ## +# ##### # ######### # ######### ### # ## #### ### ############### # ########### ######### ## # # ## +# # # # # # # # # # # # # # # # ## +# ####### # # ##### ### # #### # ### # ### # # # ############# # # # # # # # ####### ### # # ### ## +# # # # # # # # # # # # # # # # # # # # # # # # # ## +####### ### ### # # ##### # # ### # # ### ##### ########### # ### ####### ####### # # ### # # # ## +# # # # # # # # # # # # # # # # # # # # # ## +# ### ## ##### ###### ## # ##### ### ### ##### ### ############# # ### # ##### ####### ### ##### ## +# # # # # # # # # # # # # # # # # # # # # ## +# # ### ## ###### # # # #### ### ### # # # ####### # ##### # ### # ####### ### ### ### ### ###### +# # # # # # # # # # # # # # # # # # # # # # # # # ## +# ### # # ##### # ###### #### # # ### # # # # ### # # # ######### # ### ### # # ## ## # ### # ## +# # # # # # # # # # # # # # # # # # # # # # # # # # # # ## +# # ### ### # ##### # ## # # # ### ##### # # # # # # # ### #### # ### # # ####### # # # ### # #### +# # # # # # # # # # # # # # # # # # # # # # # # # # # ## +# ### ### ### # ### # ####### # ### # # ##### # ### # ### # ##### ### ### # ##### # ### # ### ## +# # # # # # # # # # # # # # # # # # # # # # # # # # ## +# ##### ### # # ### # # # #### ## # # # ### # # ### # ### ### ### # # # # # ####### ######### # #### +# # # # # # # # # # # # # # # # # # # # # # # # # # ## +# # # # # ##### # # ### # ### # # ### # ### # # # ### ### ############# # ### # ######### # ### ## +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## +# ### # # # # # ##### ### # # # # # # ##### # # # ##### # ##### # # ## # ### # # # ### ##### #### +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## +### ##### ### ### # # # ### # ### # # ### # ### # # # # ### ### # # # ### ####### ## ## ### ## +# # # # # # # # # # # # # # # # # # # # # # # # # # # ## +# # # # ## ### # ##### # # ### # # ##### # ### ### # # ### ### ##### ### # ##### ## ### ####### ## +# # # # # # # # # # # # # # # # # # # # # # # # # ## +# ####### ### ### # ####### ####### # # ### # # ####### ### ### # # # ##### ##### ### ### # # #### +# # # # # # # # # # # # # # # # # # # # # ## +# # ####### ####### ### # ### ### # # # ##### ########## # # # ####### # # ######### # # ### # # ## +# # # # # # # # # # # # # # # # # # # # # # # # # # ## +# # # # # ##### # ### ##### ### ##### # ##### ### # # # ### # ### # ### # # #### ## ### ### # # # ## +# # # # # # # # # # # # # # # # # # # # # # # # # # # ## +# # # ##### ### ####### ##### ### # ### ## ### # # # ####### # # # # # ##### ##### # ### # ##### ## +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## +##### # # ### ### # # # ##### # # # ### # # # # ##### ### # ### # # # # ##### # ### # ### # # # ## +# # # # # # # # # # # # # # # # # # # # # # # # # # # # ## +# # ### # # ##### # ############ # ##### # #### ## # ##### # # ######### # ####### ## # # # # # ## +# # # # # # # # # # # # # # # # # # # ## +# ##### # ##### # ### ### # # ##### # ############### # # ### ######### # ### # ##### ### # ##### ## +# # # # # # # # # # # # # # # # # # # # # # # # # ## +# # # # ### # # # # ## ### ##### # ### ## ######## ### ########## # # ### # # ####### ### ##### ## +# # # # # # # # # # # # # # # # # # # ## +# ### # # # ### ##### ##### # # # ############### ######### ### # # ################ # # ### ###### +# # # # # # # # # # # # # # # # # # # ## +# # # ### ### ######### # # # ####### ### #### # ### ##### ######### # # # ##### # ##### # ######## +# # # # # # # # # # # # # # # # # # # # # # # # # # ## +### # # # ##### # # # # # # # ### # # ### # ### # ## # ## # ####### ######### ##### # # # ### ## +# # # # # # # # # # # # # # # # # # # # # # # ## +# ##### ##### # # ### ### ### # ##### # # # ### # ############ ## ######### ### # ### ### # # # # ## +# # # # # # # # # # # # # # # # # # # # # # # # ## +# # ##### # # ##### # ### # #### ### # ######### ### # # ##### # ### ### # ### ### #### ## # ## +# # # # # # # # # # # # # # # # # # # # # # # # ## +# ##### ### #### # # ########### ### # # # # # # # ### # # # # # # ### # ### ##### ### # ### # # ## +# # # # # # # # # # # # # # # # # # # # # # # # # ## +# # # # # ### # ### # # ####### #### ######### ####### ### ####### # # ####### ### ### # ##### ## +# # # # # # # # # # # # # # # # # # # # # # # ## +# # ##### ##### # ####### ### ################# # # ### # # ### # # ### # # ### # ######### ##### ## +# # # # # # # # # # # # # # # # # # # # # # # # ## +### # ### # # ##### # # # # ### ### # ##### ####### ### ### # # ### ####### ####### ### ########## +# # # # # # # # # # # # # # # # # # # # # ## +# ######### # ##### ### ############# # ####### ##### ### ### # # ### # ### ##### # # ### ### # ## +# # # # # # # # # # # # # # # # # # # # # ## +# # # # # # ##### ##### # ######### # ### ### ### # ####### # # ### # ####### ##### ### # ### ## +# # # # # # # # # # # # # # # # # # # # ## +# ### # # # ##### # ###### #### # ##### # ### # # ### ######### ### ####### # ### ### ### ####### ## +# # # # # # # # # # # # # # # # # # # # # # # ## +# # ########### ### # ##### # # # # # ### # ### ### ### ##### ### ##### # ####### # ###### # # #### +# # # # # # # # # # # # # # # # # # # # # # # ## +# # # ###### # ### # # ########### ## ### ##### # # # # # # # # # ########### ### ######### ### ## +# # # # # # # # # # # # # # # # # # # # # # # # # # # ## +# ### ### # ### # ### # # ### # # ### # ### # ### # ##### # # # # ### # # ###### # ### # # ### # ## +# # # # # # # # # # # # # # # # # # # # # # # # # # # ## +### # # ##### ##### ### # # ####### ##### # # # ########### ######### ### # # ### ##### # # # # ## +# # # # # # # # E## +#################################################################################################### +#################################################################################################### diff --git a/SolovevDS/docs/data/data_for_task2/maze50.txt b/SolovevDS/docs/data/data_for_task2/maze50.txt new file mode 100644 index 0000000..b574296 --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/maze50.txt @@ -0,0 +1,50 @@ +################################################## +#S # # # # # ## +##### ##### ### ######### ### ### # ### # ### # ## +# # # # # # # # # # # # ## +### ######### ############# ### # # # ##### ### ## +# # # # # # # # # # ## +# ########### # ### # # ##### # ##### # ### # ## +# # # # # # # # # # # ## +### # # ### ### # ### # ######### # ####### ### ## +# # # # # # # # # # ## +# ##### # ### ##### # ##### ##### ########### #### +# # # # # # # # # # ## +##### # ### ##### # ########### ##### ##### ### ## +# # # # # # # # # # ## +# ####### # ####### # ####### ### # ### # ### # ## +# # # # # # # # # # # # ## +# # # # ################### # # ### # # # ### # ## +# # # # # # # # # # # # # ## +### # ### ### # # ########### ### # # # ### ### ## +# # # # # # # # # # # # # # ## +# ##### ### ######### ##### ### # ### # # ### # ## +# # # # # # # # # # # # # ## +# # # ####### ### ### # ### # # ### # # # # # #### +# # # # # # # # # # # # # # ## +# # ########### ####### # ### # # ######### ### ## +# # # # # # # # ## +# ### ####### # ##### ##### # ####### ### ### #### +# # # # # # # # # # # # ## +# ######### ####### # # # # ### # ####### # ### ## +# # # # # # # # # # # # ## +### # ### ##### ####### # # # # ### # # ####### ## +# # # # # # # # # # # # # # ## +# # # # ### # ####### # # # ##### # # ### ### # ## +# # # # # # # # # # # # # # # # ## +# # # ######### # # # ### ### ### ### # ### # # ## +# # # # # # # # # # # # # ## +# ### # ####### # ######### # ####### ### # ### ## +# # # # # # # # # # # # # ## +# ##### # # # ##### # # ####### ### # # ### # #### +# # # # # # # # # # # # # # ## +##### ### # # # ##### ########### # # # # # ### ## +# # # # # # # # # # # ## +# ############# # ### ##### ##### # ### # ##### ## +# # # # # # # # # # # ## +# # ####### ### # # ### # ### ### ### # ##### # ## +# # # # # # # # # # # # # ## +# ##### ##### ### # # ##### ### ### ##### ##### ## +# # # # # # E## +################################################## +################################################## diff --git a/SolovevDS/docs/data/data_for_task2/maze_empty.txt b/SolovevDS/docs/data/data_for_task2/maze_empty.txt new file mode 100644 index 0000000..a92cf1d --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/maze_empty.txt @@ -0,0 +1,50 @@ +S + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + E diff --git a/SolovevDS/docs/data/data_for_task2/maze_no_path.txt b/SolovevDS/docs/data/data_for_task2/maze_no_path.txt new file mode 100644 index 0000000..03906b4 --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/maze_no_path.txt @@ -0,0 +1,10 @@ +########## +#S # +# ###### # +# # # # +# # ## # # +# # ## # # +# # # # +# ######## +# #E# +########## diff --git a/SolovevDS/docs/data/data_for_task2/path_length_comparison.svg b/SolovevDS/docs/data/data_for_task2/path_length_comparison.svg new file mode 100644 index 0000000..f3af08a --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/path_length_comparison.svg @@ -0,0 +1,1536 @@ + + + + + + + + 2026-05-23T13:53:58.910555 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SolovevDS/docs/data/data_for_task2/results.csv b/SolovevDS/docs/data/data_for_task2/results.csv new file mode 100644 index 0000000..8bc14f3 --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/results.csv @@ -0,0 +1,16 @@ +maze,strategy,time_ms,cells_visited,way_len +small_10,BFS,0.00724,31.00000,21.00000 +small_10,DFS,0.00360,31.00000,21.00000 +small_10,AStar,0.00519,24.00000,21.00000 +medium_50,BFS,0.04465,505.00000,145.00000 +medium_50,DFS,0.03666,385.00000,361.00000 +medium_50,AStar,0.05370,319.00000,145.00000 +large_100,BFS,0.44010,4534.00000,245.00000 +large_100,DFS,0.09760,816.00000,703.00000 +large_100,AStar,0.37331,1298.00000,245.00000 +empty,BFS,0.15303,2500.00000,99.00000 +empty,DFS,0.09335,1275.00000,1275.00000 +empty,AStar,0.17047,341.00000,99.00000 +no_path,BFS,0.00259,25.00000,0.00000 +no_path,DFS,0.00244,25.00000,0.00000 +no_path,AStar,0.00494,25.00000,0.00000 diff --git a/SolovevDS/docs/data/data_for_task2/task2.cpp b/SolovevDS/docs/data/data_for_task2/task2.cpp new file mode 100644 index 0000000..07f957c --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/task2.cpp @@ -0,0 +1,934 @@ +#include +#include +#include +#include /*для ошибок*/ +#include +#include /*мерит время*/ +#include /*волшебная отрисовка*/ +#include +#include +#include + +class cell{ + private: + int x, y; + bool isWall; + bool isExit; + bool isStart; + + public: + cell() {x=0; y=0; isWall=false; isExit=false; isStart = false;} + cell(int x, int y, bool isWall, bool isExit, bool isStart) + { + this->x = x; + this->y = y; + this->isWall = isWall; + this->isExit = isExit; + this->isStart = isStart; + } + + bool isPassable() {return !isWall;} + + void setStart(bool value) {isStart = value;} + void setExit(bool value) {isExit = value;} + void setX(int x) {this->x = x;} + void setY(int y) {this->y = y;} + void setIsWall(bool isWall) {this->isWall = isWall;} + + + int getX() {return x;} + int getY() {return y;} + bool getIsWall() {return isWall;} + bool getIsExit() {return isExit;} + bool getIsStart() {return isStart;} + +}; + +class maze{ + private: + int width; + int height; + cell** matrix; + + cell* start; + cell* exit; + + public: + maze(int width, int height) + { + this->width = width; + this->height = height; + this->start = nullptr; + this->exit = nullptr; + + matrix = new cell*[width]; + + for (int x = 0; x < width; ++x) { + matrix[x] = new cell[height]; + for (int y = 0; y < height; ++y) + matrix[x][y] = cell(x, y, false, false, false); + } + } + maze(int width, int height, int startX, int startY, int exitX, int exitY) + { + this->width = width; + this->height = height; + this->start = nullptr; + this->exit = nullptr; + + matrix = new cell*[width]; + for (int x = 0; x < width; ++x) { + matrix[x] = new cell[height]; + for (int y = 0; y < height; ++y) { + matrix[x][y] = cell(x, y, false, false, false); + } + } + + + matrix[startX][startY].setStart(true); + matrix[exitX][exitY].setExit(true); + + start = &matrix[startX][startY]; + exit = &matrix[exitX][exitY]; + } + + ~maze() + { + for (int i = 0; i < width; ++i) + delete[] matrix[i]; + delete[] matrix; + } + + cell* getCell(int x, int y) { + if (x < 0 || x >= width || y < 0 || y >= height) + return nullptr; + + return &matrix[x][y]; + } + void setCell(int x, int y, cell newCell) { + if (x < 0 || x >= width || y < 0 || y >= height) + return; + + matrix[x][y] = newCell; + + if (matrix[x][y].getIsStart()) + start = &matrix[x][y]; + + if (matrix[x][y].getIsExit()) + exit = &matrix[x][y]; + } + + cell** getNeighbors(cell* current) { /*ДЕЛАТЬ delete[] neighbors; !!!!!!!!!!!!!!!*/ + cell** neighbors = new cell*[5]; + int count = 0; + + int x = current->getX(); + int y = current->getY(); + + cell* up = getCell(x, y - 1); + cell* down = getCell(x, y + 1); + cell* left = getCell(x - 1, y); + cell* right = getCell(x + 1, y); + + if (up != nullptr && up->isPassable()) { + neighbors[count] = up; + count++;} + + if (down != nullptr && down->isPassable()) { + neighbors[count] = down; + count++;} + + if (left != nullptr && left->isPassable()) { + neighbors[count] = left; + count++;} + + if (right != nullptr && right->isPassable()) { + neighbors[count] = right; + count++;} + + neighbors[count] = nullptr; + + return neighbors; + } + + cell* getStart() {return start;} + cell* getExit() {return exit;} + int getWidth() {return width;} + int getHeight() {return height;} +}; + +class MazeBuilder { + public: + virtual maze* buildFromFile(const std::string& filename) = 0; + virtual ~MazeBuilder() {} +}; + +class TextFileMazeBuilder : public MazeBuilder { + public: + maze* buildFromFile(const std::string& filename) override + { + + std::ifstream file(filename); + if (!file.is_open()) + throw std::runtime_error("Ошибка: Не удалось открыть файл!"); + + std::string line; + int width = 0; + int height = 0; + + while (std::getline(file, line)) { + if (height == 0) { + width = line.length(); + } + else { + if (line.length() != width) + throw std::runtime_error("Ошибка: строки лабиринта разной длины!"); + } + height++; + } + + if (width == 0 || height == 0) { + throw std::runtime_error("Ошибка: файл пустой!"); + } + + file.clear(); + file.seekg(0); + + maze* labirint = new maze(width, height); + bool hasStart = false; + bool hasExit = false; + int y = 0; + + + while (std::getline(file, line)) { + + for (int x = 0; x < width; x++) { + char ch = line[x]; + + bool isWall = false; + bool isStart = false; + bool isExit = false; + + switch(ch){ + case '#': + isWall = true; + break; + case ' ': + isWall = false; + break; + case 'S': + isStart = true; + + if (hasStart) + throw std::runtime_error("Ошибка: в лабиринте больше одного старта!"); + + hasStart = true; + break; + case 'E': + isExit = true; + + if (hasExit) + throw std::runtime_error("Ошибка: в лабиринте больше одного выхода!"); + hasExit = true; + break; + default: + throw std::runtime_error("Ошибка: неизвестный символ в файле!"); + break; + } + + cell current(x, y, isWall, isExit, isStart); + labirint->setCell(x, y, current); + } + + y++; + } + file.close(); + if (!hasStart) + throw std::runtime_error("Ошибка: в лабиринте нет старта!"); + if (!hasExit) + throw std::runtime_error("Ошибка: в лабиринте нет выхода!"); + return labirint; + } +}; + + +class PathFindingStrategy { + public: + virtual cell** findPath(maze* m, cell* start, cell* exit) = 0; + virtual int getVisitedCells() = 0; /*для посещенных клеток*/ + virtual ~PathFindingStrategy() {} +}; + +class PathBuilder { + public: + static cell** buildPath(cell* start, cell* exit, cell*** parent) { + int length = 0; + cell* current = exit; + + while (current != nullptr) { + length++; + if (current == start) + break; + current = parent[current->getX()][current->getY()]; + } + + cell** path = new cell*[length + 1]; + current = exit; + + for (int i = length - 1; i >= 0; i--) { + path[i] = current; + if (current == start) + break; + current = parent[current->getX()][current->getY()]; + } + path[length] = nullptr; + return path; + } +}; + +class BFSStrategy : public PathFindingStrategy { + private: + int visitedCells; + public: + + BFSStrategy() {visitedCells = 0;} + + int getVisitedCells() override {return visitedCells;} + + cell** findPath(maze* m, cell* start, cell* exit) override { + visitedCells = 0; + int width = m->getWidth(); + int height = m->getHeight(); + bool** visited = new bool*[width]; + cell*** parent = new cell**[width]; + + for (int x = 0; x < width; x++) { + visited[x] = new bool[height]; + parent[x] = new cell*[height]; + + for (int y = 0; y < height; y++) { + visited[x][y] = false; + parent[x][y] = nullptr; + } + } + + cell** deque = new cell*[width * height]; + int head = 0; + int tail = 0; + + deque[tail] = start; + tail++; + visited[start->getX()][start->getY()] = true; + bool found = false; + + while (head < tail) { + cell* current = deque[head]; + head++; + visitedCells++; + + if (current == exit) { //сравниваются указатели + found = true; + break; + } + + cell** neighbors = m->getNeighbors(current); + + for (int i = 0; neighbors[i] != nullptr; i++) { + cell* next = neighbors[i]; + + int nx = next->getX(); + int ny = next->getY(); + + if (!visited[nx][ny]) { + visited[nx][ny] = true; + parent[nx][ny] = current; + + deque[tail] = next; + tail++; + } + } + delete[] neighbors; + } + + cell** path; + + if (found) { + path = PathBuilder::buildPath(start, exit, parent); + } + else { + path = new cell*[1]; + path[0] = nullptr; + } + + delete[] deque; + + for (int x = 0; x < width; x++) { + delete[] visited[x]; + delete[] parent[x]; + } + delete[] visited; + delete[] parent; + return path; + } +}; + +class DFSStrategy : public PathFindingStrategy { + private: + int visitedCells; + public: + DFSStrategy() {visitedCells = 0;} + + int getVisitedCells() override {return visitedCells;} + + cell** findPath(maze* m, cell* start, cell* exit) override { + visitedCells = 0; + int width = m->getWidth(); + int height = m->getHeight(); + bool** visited = new bool*[width]; + cell*** parent = new cell**[width]; + + for (int x = 0; x < width; x++) { + visited[x] = new bool[height]; + parent[x] = new cell*[height]; + + for (int y = 0; y < height; y++) { + visited[x][y] = false; + parent[x][y] = nullptr; + } + } + + cell** stack = new cell*[width * height]; + int top = 0; + stack[top] = start; + top++; + visited[start->getX()][start->getY()] = true; + bool found = false; + + while (top > 0) { + top--; + cell* current = stack[top]; + visitedCells++; + + if (current == exit) { //сравниваются указатели + found = true; + break; + } + + cell** neighbors = m->getNeighbors(current); + + for (int i = 0; neighbors[i] != nullptr; i++) { + cell* next = neighbors[i]; + + int nx = next->getX(); + int ny = next->getY(); + + if (!visited[nx][ny]) { + visited[nx][ny] = true; + parent[nx][ny] = current; + + stack[top] = next; + top++; + } + } + delete[] neighbors; + } + + cell** path; + + if (found) { + path = PathBuilder::buildPath(start, exit, parent); + } + else { + path = new cell*[1]; + path[0] = nullptr; + } + + delete[] stack; + + for (int x = 0; x < width; x++) { + delete[] visited[x]; + delete[] parent[x]; + } + delete[] visited; + delete[] parent; + return path; + } +}; + +class AStarStrategy : public PathFindingStrategy { + private: + int heuristic(cell* current, cell* exit) {return std::abs(current->getX() - exit->getX()) + std::abs(current->getY() - exit->getY());} + int visitedCells; + + public: + AStarStrategy() {visitedCells = 0;} + + int getVisitedCells() override {return visitedCells;} + + cell** findPath(maze* m, cell* start, cell* exit) override { + visitedCells = 0; + int width = m->getWidth(); + int height = m->getHeight(); + + bool** closed = new bool*[width]; /*клетка [x][y] посещена (да/нет)*/ + bool** inOpen = new bool*[width]; /*клетка [x][y] имеет потенциал к посещению (да/нет)*/ + int** gScore = new int*[width]; /* до клетка [x][y] от старта gSchore[x][y] шагов*/ + int** fScore = new int*[width]; /*f = h + g, где h - эвристика клетки[x][y]*/ + + cell*** parent = new cell**[width]; + + + for (int x = 0; x < width; x++) { + closed[x] = new bool[height]; + inOpen[x] = new bool[height]; + gScore[x] = new int[height]; + fScore[x] = new int[height]; + + parent[x] = new cell*[height]; + + for (int y = 0; y < height; y++) { + closed[x][y] = false; + inOpen[x][y] = false; + + gScore[x][y] = width * height + 100000; /*тупо большое число чтоб было больше чем клеток в лаберинте*/ + fScore[x][y] = width * height + 100000; + + parent[x][y] = nullptr; + } + } + + cell** open = new cell*[width * height]; /*клетки с потенциалом на посещение*/ + int openCount = 0; /*это количество потенц клеток, а также индекс следующего незанятого места*/ + + int sx = start->getX(); + int sy = start->getY(); + + gScore[sx][sy] = 0; + fScore[sx][sy] = heuristic(start, exit); + + open[openCount] = start; + openCount++; + + inOpen[sx][sy] = true; + bool found = false; + + while (openCount > 0) { + int bestIndex = 0; + + for (int i = 1; i < openCount; i++) { + int ix = open[i]->getX(); + int iy = open[i]->getY(); + + int bx = open[bestIndex]->getX(); + int by = open[bestIndex]->getY(); + + if (fScore[ix][iy] < fScore[bx][by]) { + bestIndex = i; /*(fSchore наименьший в [bestIndex])*/ + } + } + + cell* current = open[bestIndex]; + + if (current == exit) { + found = true; + visitedCells++; /*чтоб выход засчитывался*/ + break; + } + + int cx = current->getX(); + int cy = current->getY(); + + open[bestIndex] = open[openCount - 1]; + openCount--; + + inOpen[cx][cy] = false; + closed[cx][cy] = true; + visitedCells++; + + cell** neighbors = m->getNeighbors(current); + + for (int i = 0; neighbors[i] != nullptr; i++) { + cell* next = neighbors[i]; + + int nx = next->getX(); + int ny = next->getY(); + + if (closed[nx][ny]) { + continue; + } + + int tentativeG = gScore[cx][cy] + 1; + + if (tentativeG < gScore[nx][ny]) { + parent[nx][ny] = current; + + gScore[nx][ny] = tentativeG; + fScore[nx][ny] = gScore[nx][ny] + heuristic(next, exit); + + if (!inOpen[nx][ny]) { + open[openCount] = next; + openCount++; + + inOpen[nx][ny] = true; + } + } + } + delete[] neighbors; + } + + cell** path; + if (found) { + path = PathBuilder::buildPath(start, exit, parent); + } + else { + path = new cell*[1]; + path[0] = nullptr; + } + + delete[] open; + + for (int x = 0; x < width; x++) { + delete[] closed[x]; + delete[] inOpen[x]; + delete[] gScore[x]; + delete[] fScore[x]; + delete[] parent[x]; + } + delete[] closed; + delete[] inOpen; + delete[] gScore; + delete[] fScore; + delete[] parent; + + return path; + } +}; + +class SearchStats { +public: + double timeMs; + int visitedCells; + int pathLength; + + SearchStats(double timeMs, int visitedCells, int pathLength) { + this->timeMs = timeMs; + this->visitedCells = visitedCells; + this->pathLength = pathLength; + } +}; + +class MazeSolver{ + private: + maze* labirint; + PathFindingStrategy* strategy; + public: + MazeSolver(maze* labirint) {this->labirint = labirint; this->strategy = nullptr;} + + void setStrategy(PathFindingStrategy* strategy){ + this->strategy = strategy; + } + + SearchStats solve(){ + auto start = std::chrono::high_resolution_clock::now(); + cell** path = strategy->findPath(labirint,labirint->getStart(),labirint->getExit()); + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration duration = end - start; + + int pathLength = 0; + + if (path[0] != nullptr) + while (path[pathLength] != nullptr) {pathLength++;} + + int visitedCells = 0; + visitedCells = strategy->getVisitedCells(); + delete[] path; + + SearchStats stats(duration.count(), visitedCells, pathLength); + return stats; + } +}; + +class Player{ + private: + cell* current; + public: + Player(cell* current) {this->current = current;} + + cell* getCurrent() {return current;} + void moveTo(cell* cell) {this->current = cell;} +}; + +class Direction{ + private: + int dx; + int dy; + + public: + Direction(int dx, int dy) { + this->dx = dx; + this->dy = dy; + } + + int getDx() {return dx;} + int getDy() {return dy;} +}; + +class Command { + public: + virtual void execute() = 0; + virtual void undo() = 0; + virtual ~Command() {} +}; + +class MoveCommand : public Command{ + private: + Player* player; + Direction dir; + cell* previousCell; + maze* labirint; + public: + MoveCommand(Player* player, maze* labirint, Direction dir) : dir(dir) { + this->player = player; + this->labirint = labirint; + this->previousCell = nullptr; + } + + void execute() override { + cell* currentCell = player->getCurrent(); + + int newX = currentCell->getX() + dir.getDx(); + int newY = currentCell->getY() + dir.getDy(); + + cell* nextCell = labirint->getCell(newX, newY); + + if (nextCell != nullptr && nextCell->isPassable()) { + previousCell = currentCell; + player->moveTo(nextCell); + } + else { + std::cout << "Нельзя сделать ход!" << std::endl; + } + } + + void undo() override { + if (previousCell != nullptr) { + player->moveTo(previousCell); + previousCell = nullptr; + } + } + +}; + +class ConsolController{ + private: + maze* labirint; + Player* player; + Command* lastCommand; /*указатель на последнюю команду(на объект класса command)*/ + bool running; + public: + ConsolController(maze* labirint, Player* player) { + this->labirint = labirint; + this->player = player; + this->lastCommand = nullptr; + this->running = false; + } + + ~ConsolController() { + if (lastCommand != nullptr) { + delete lastCommand; + } + } + + void run() { + running = true; + + while (running) { + clearConsole(); + drawMaze(); + + std::cout << "W/A/S/D - ход, Z - отмена, Q - выход" << std::endl; + char ch; + std::cin >> ch; + + handleInput(ch); + } + } + + void handleInput(char ch) { + switch(ch){ + case 'q': + case 'Q': + running = false; + break; + case 'z': + case 'Z': + undoLastMove(); + break; + default: + handleMove(ch); + break; + } + } + + void handleMove(char ch) { + Direction dir(0, 0); + + switch (ch) { + case 'w': + case 'W': + dir = Direction(0, -1); + break; + case 's': + case 'S': + dir = Direction(0, 1); + break; + case 'a': + case 'A': + dir = Direction(-1, 0); + break; + case 'd': + case 'D': + dir = Direction(1, 0); + break; + default: + return; + } + + if (lastCommand != nullptr) { + delete lastCommand; + lastCommand = nullptr; + } + + lastCommand = new MoveCommand(player, labirint, dir); + lastCommand->execute(); + } + + void undoLastMove() { + if (lastCommand != nullptr) { + lastCommand->undo(); + delete lastCommand; + lastCommand = nullptr; /*можно отменить только одну команду назад, указатель делаем 0, чтобы не долбится в отмену уже отмененной команды*/ + } + } + + void clearConsole() { + #ifdef _WIN32 + system("cls"); + #else + system("clear"); + #endif + } + + void drawMaze() { + for (int y = 0; y < labirint->getHeight(); y++) { + for (int x = 0; x < labirint->getWidth(); x++) { + cell* currentCell = labirint->getCell(x, y); + + if (currentCell == player->getCurrent()) + std::cout << "P"; + else if (currentCell->getIsWall()) + std::cout << "#"; + else if (currentCell->getIsStart()) + std::cout << "S"; + else if (currentCell->getIsExit()) + std::cout << "E"; + else + std::cout << " "; + } + std::cout << std::endl; + } + } +}; + +class Benchmark { + private: + int RUNS = 10; + public: + Benchmark(int runs) {this->RUNS = runs;} + void benchmark(){ + std::string mazeFiles[] = { + "SolovevDS/docs/data/data_for_task2/maze10.txt", + "SolovevDS/docs/data/data_for_task2/maze50.txt", + "SolovevDS/docs/data/data_for_task2/maze100.txt", + "SolovevDS/docs/data/data_for_task2/maze_empty.txt", + "SolovevDS/docs/data/data_for_task2/maze_no_path.txt" + }; + + std::string mazeNames[] = { + "small_10", + "medium_50", + "large_100", + "empty", + "no_path" + }; + + std::ofstream csv("SolovevDS/docs/data/data_for_task2/results.csv"); + + if (!csv.is_open()) + throw std::runtime_error("Ошибка: не удалось создать results.csv!"); + + csv << "maze,strategy,time_ms,cells_visited,way_len\n"; + + TextFileMazeBuilder builder; + + for (int i = 0; i < 5; i++) { + maze* labirint = builder.buildFromFile(mazeFiles[i]); + + MazeSolver solver(labirint); + + BFSStrategy bfs; + DFSStrategy dfs; + AStarStrategy astar; + + PathFindingStrategy* strategies[] = {&bfs, &dfs, &astar}; + std::string strategyNames[] = {"BFS", "DFS", "AStar"}; + + for (int s = 0; s < 3; s++) { + double sumTime = 0; + double sumVisited = 0; + double sumPathLength = 0; + + for (int run = 0; run < RUNS; run++) { + solver.setStrategy(strategies[s]); + + SearchStats stats = solver.solve(); + + sumTime += stats.timeMs; + sumVisited += stats.visitedCells; + sumPathLength += stats.pathLength; + } + + double avgTime = sumTime / RUNS; + double avgVisited = sumVisited / RUNS; + double avgPathLength = sumPathLength / RUNS; + + csv << mazeNames[i] << "," + << strategyNames[s] << "," + << std::fixed << std::setprecision(5) << avgTime << "," + << avgVisited << "," + << avgPathLength << "\n"; + } + delete labirint; + } + + csv.close(); + } +}; + + +int main(){ + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + setlocale(LC_ALL, ".UTF-8"); + Benchmark ben(10); + ben.benchmark(); + + TextFileMazeBuilder builder; + maze* labirint = builder.buildFromFile("SolovevDS/docs/data/data_for_task2/maze10.txt"); + Player player(labirint->getStart()); + ConsolController controller(labirint, &player); + controller.run(); + delete labirint; + + return 0; +} diff --git a/SolovevDS/docs/data/data_for_task2/time_comparison.svg b/SolovevDS/docs/data/data_for_task2/time_comparison.svg new file mode 100644 index 0000000..d50a3e3 --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/time_comparison.svg @@ -0,0 +1,1582 @@ + + + + + + + + 2026-05-23T13:53:58.486270 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SolovevDS/docs/data/data_for_task2/visited_cells_comparison.svg b/SolovevDS/docs/data/data_for_task2/visited_cells_comparison.svg new file mode 100644 index 0000000..05def5c --- /dev/null +++ b/SolovevDS/docs/data/data_for_task2/visited_cells_comparison.svg @@ -0,0 +1,1530 @@ + + + + + + + + 2026-05-23T13:53:58.677345 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SolovevDS/docs/laba_1_report.pdf b/SolovevDS/docs/laba_1_report.pdf new file mode 100644 index 0000000..f0f277d Binary files /dev/null and b/SolovevDS/docs/laba_1_report.pdf differ diff --git a/SolovevDS/docs/laba_2_report.pdf b/SolovevDS/docs/laba_2_report.pdf new file mode 100644 index 0000000..005e523 Binary files /dev/null and b/SolovevDS/docs/laba_2_report.pdf differ