From 849eaf018d3245f3f36b2f134fb24b5abcfca20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Mon, 18 May 2026 14:48:32 +0300 Subject: [PATCH 01/15] [1] add phonebook structures --- raskatovia/docs/data/task1/spravochnik.py | 134 ++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 raskatovia/docs/data/task1/spravochnik.py diff --git a/raskatovia/docs/data/task1/spravochnik.py b/raskatovia/docs/data/task1/spravochnik.py new file mode 100644 index 0000000..b0c62cb --- /dev/null +++ b/raskatovia/docs/data/task1/spravochnik.py @@ -0,0 +1,134 @@ +def sort_records(records): + return sorted(records, key=lambda item: item[0]) + +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 is not None: + 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 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"] + return sort_records(records) + +def ht_create(size=101): + return [None] * size + +def get_bucket_index(name, size): + total = 0 + for symbol in name: + total += ord(symbol) + return total % size + +def ht_insert(buckets, name, phone): + index = get_bucket_index(name, len(buckets)) + buckets[index] = ll_insert(buckets[index], name, phone) + +def ht_find(buckets, name): + index = get_bucket_index(name, len(buckets)) + return ll_find(buckets[index], name) + +def ht_delete(buckets, name): + index = get_bucket_index(name, len(buckets)) + buckets[index] = ll_delete(buckets[index], name) + +def ht_list_all(buckets): + records = [] + for bucket in buckets: + current = bucket + while current is not None: + records.append((current["name"], current["phone"])) + current = current["next"] + return sort_records(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): + 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_min_node(root): + current = root + 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 + if name > root["name"]: + root["right"] = bst_delete(root["right"], name) + return root + if root["left"] is None: + return root["right"] + if root["right"] is None: + return root["left"] + replacement = bst_min_node(root["right"]) + root["name"] = replacement["name"] + root["phone"] = replacement["phone"] + root["right"] = bst_delete(root["right"], replacement["name"]) + return root + +def bst_list_all(root): + records = [] + def walk(node): + if node is None: + return + walk(node["left"]) + records.append((node["name"], node["phone"])) + walk(node["right"]) + walk(root) + return records \ No newline at end of file -- 2.43.0 From d694f5ce0b23b1a543b94abeeeefba17084cbadb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Mon, 18 May 2026 14:58:55 +0300 Subject: [PATCH 02/15] [1] add basic tests --- raskatovia/docs/data/task1/tests.py | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 raskatovia/docs/data/task1/tests.py diff --git a/raskatovia/docs/data/task1/tests.py b/raskatovia/docs/data/task1/tests.py new file mode 100644 index 0000000..a672001 --- /dev/null +++ b/raskatovia/docs/data/task1/tests.py @@ -0,0 +1,46 @@ +from spravochnik import * + +def test_linked_list(): + head = None + head = ll_insert(head, "Ivan", "111") + head = ll_insert(head, "Anna", "222") + head = ll_insert(head, "Petr", "333") + head = ll_insert(head, "Anna", "444") + print("Linked list") + print(ll_find(head, "Anna")) + print(ll_find(head, "Olga")) + print(ll_list_all(head)) + head = ll_delete(head, "Ivan") + print(ll_list_all(head)) + print() + +def test_hash_table(): + table = ht_create() + ht_insert(table, "Ivan", "111") + ht_insert(table, "Anna", "222") + ht_insert(table, "Petr", "333") + ht_insert(table, "Anna", "444") + print("Hash table") + print(ht_find(table, "Anna")) + print(ht_find(table, "Olga")) + print(ht_list_all(table)) + ht_delete(table, "Ivan") + print(ht_list_all(table)) + print() + +def test_bst(): + root = None + root = bst_insert(root, "Ivan", "111") + root = bst_insert(root, "Anna", "222") + root = bst_insert(root, "Petr", "333") + root = bst_insert(root, "Anna", "444") + print("BST") + print(bst_find(root, "Anna")) + print(bst_find(root, "Olga")) + print(bst_list_all(root)) + root = bst_delete(root, "Ivan") + print(bst_list_all(root)) + +test_linked_list() +test_hash_table() +test_bst() \ No newline at end of file -- 2.43.0 From d4fcd67dde0dd632c7471927d410db1ea52eef60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Mon, 18 May 2026 15:01:39 +0300 Subject: [PATCH 03/15] [1] fix bst for sorted records --- raskatovia/docs/data/task1/spravochnik.py | 90 ++++++++++++++--------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/raskatovia/docs/data/task1/spravochnik.py b/raskatovia/docs/data/task1/spravochnik.py index b0c62cb..30106e2 100644 --- a/raskatovia/docs/data/task1/spravochnik.py +++ b/raskatovia/docs/data/task1/spravochnik.py @@ -76,14 +76,24 @@ def ht_list_all(buckets): return sort_records(records) def bst_insert(root, name, phone): + new_node = {"name": name, "phone": phone, "left": None, "right": None} 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 new_node + current = root + while True: + if name < current["name"]: + if current["left"] is None: + current["left"] = new_node + break + current = current["left"] + elif name > current["name"]: + if current["right"] is None: + current["right"] = new_node + break + current = current["right"] + else: + current["phone"] = phone + break return root def bst_find(root, name): @@ -97,38 +107,48 @@ def bst_find(root, name): current = current["right"] return None -def bst_min_node(root): - current = root - 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) + parent = None + current = root + while current is not None and current["name"] != name: + parent = current + if name < current["name"]: + current = current["left"] + else: + current = current["right"] + if current is None: return root - if name > root["name"]: - root["right"] = bst_delete(root["right"], name) - return root - if root["left"] is None: - return root["right"] - if root["right"] is None: - return root["left"] - replacement = bst_min_node(root["right"]) - root["name"] = replacement["name"] - root["phone"] = replacement["phone"] - root["right"] = bst_delete(root["right"], replacement["name"]) + if current["left"] is not None and current["right"] is not None: + replacement_parent = current + replacement = current["right"] + while replacement["left"] is not None: + replacement_parent = replacement + replacement = replacement["left"] + current["name"] = replacement["name"] + current["phone"] = replacement["phone"] + parent = replacement_parent + current = replacement + if current["left"] is not None: + child = current["left"] + else: + child = current["right"] + if parent is None: + return child + if parent["left"] is current: + parent["left"] = child + else: + parent["right"] = child return root def bst_list_all(root): records = [] - def walk(node): - if node is None: - return - walk(node["left"]) - records.append((node["name"], node["phone"])) - walk(node["right"]) - walk(root) + stack = [] + current = root + while current is not None or stack: + while current is not None: + stack.append(current) + current = current["left"] + current = stack.pop() + records.append((current["name"], current["phone"])) + current = current["right"] return records \ No newline at end of file -- 2.43.0 From 6ea13ecb26b5c3c833fded2815e592359516fc7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Mon, 18 May 2026 15:11:59 +0300 Subject: [PATCH 04/15] [1] add timing tests and results --- raskatovia/docs/data/task1/results.csv | 109 +++++++++++++++++++ raskatovia/docs/data/task1/zamery.py | 141 +++++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 raskatovia/docs/data/task1/results.csv create mode 100644 raskatovia/docs/data/task1/zamery.py diff --git a/raskatovia/docs/data/task1/results.csv b/raskatovia/docs/data/task1/results.csv new file mode 100644 index 0000000..eba5318 --- /dev/null +++ b/raskatovia/docs/data/task1/results.csv @@ -0,0 +1,109 @@ +Структура,Режим,Операция,Замер,Время (сек) +Связный список,Случайный,Вставка,1,18.650031568482518 +Связный список,Случайный,Вставка,2,18.696410017088056 +Связный список,Случайный,Вставка,3,17.576973121613264 +Связный список,Случайный,Вставка,4,16.589464861899614 +Связный список,Случайный,Вставка,5,16.205514946952462 +Связный список,Случайный,Вставка,Среднее,17.543678903207184 +Связный список,Случайный,Поиск,1,0.15266339667141438 +Связный список,Случайный,Поиск,2,0.16375628858804703 +Связный список,Случайный,Поиск,3,0.12933312729001045 +Связный список,Случайный,Поиск,4,0.13891681656241417 +Связный список,Случайный,Поиск,5,0.14089339599013329 +Связный список,Случайный,Поиск,Среднее,0.14511260502040385 +Связный список,Случайный,Удаление,1,0.07620067708194256 +Связный список,Случайный,Удаление,2,0.09449147805571556 +Связный список,Случайный,Удаление,3,0.08359903283417225 +Связный список,Случайный,Удаление,4,0.09074903465807438 +Связный список,Случайный,Удаление,5,0.08376427739858627 +Связный список,Случайный,Удаление,Среднее,0.0857609000056982 +Связный список,Отсортированный,Вставка,1,15.179195748642087 +Связный список,Отсортированный,Вставка,2,15.626798518002033 +Связный список,Отсортированный,Вставка,3,15.150643169879913 +Связный список,Отсортированный,Вставка,4,14.520009176805615 +Связный список,Отсортированный,Вставка,5,14.595012564212084 +Связный список,Отсортированный,Вставка,Среднее,15.014331835508347 +Связный список,Отсортированный,Поиск,1,0.11738761514425278 +Связный список,Отсортированный,Поиск,2,0.1201033927500248 +Связный список,Отсортированный,Поиск,3,0.1553904190659523 +Связный список,Отсортированный,Поиск,4,0.12524455040693283 +Связный список,Отсортированный,Поиск,5,0.11648610420525074 +Связный список,Отсортированный,Поиск,Среднее,0.1269224163144827 +Связный список,Отсортированный,Удаление,1,0.08444823324680328 +Связный список,Отсортированный,Удаление,2,0.0750405415892601 +Связный список,Отсортированный,Удаление,3,0.0696138758212328 +Связный список,Отсортированный,Удаление,4,0.07685920968651772 +Связный список,Отсортированный,Удаление,5,0.06544658727943897 +Связный список,Отсортированный,Удаление,Среднее,0.07428168952465057 +Хеш-таблица,Случайный,Вставка,1,0.8925542905926704 +Хеш-таблица,Случайный,Вставка,2,0.9055562932044268 +Хеш-таблица,Случайный,Вставка,3,0.9032609593123198 +Хеш-таблица,Случайный,Вставка,4,0.8939349129796028 +Хеш-таблица,Случайный,Вставка,5,0.8801330886781216 +Хеш-таблица,Случайный,Вставка,Среднее,0.8950879089534283 +Хеш-таблица,Случайный,Поиск,1,0.007984047755599022 +Хеш-таблица,Случайный,Поиск,2,0.007909735664725304 +Хеш-таблица,Случайный,Поиск,3,0.007135823369026184 +Хеш-таблица,Случайный,Поиск,4,0.007862800732254982 +Хеш-таблица,Случайный,Поиск,5,0.00866653397679329 +Хеш-таблица,Случайный,Поиск,Среднее,0.007911788299679756 +Хеш-таблица,Случайный,Удаление,1,0.005503913387656212 +Хеш-таблица,Случайный,Удаление,2,0.005658401176333427 +Хеш-таблица,Случайный,Удаление,3,0.00445329025387764 +Хеш-таблица,Случайный,Удаление,4,0.005032133311033249 +Хеш-таблица,Случайный,Удаление,5,0.00463026762008667 +Хеш-таблица,Случайный,Удаление,Среднее,0.00505560114979744 +Хеш-таблица,Отсортированный,Вставка,1,0.8290290385484695 +Хеш-таблица,Отсортированный,Вставка,2,0.8197460155934095 +Хеш-таблица,Отсортированный,Вставка,3,0.8217651266604662 +Хеш-таблица,Отсортированный,Вставка,4,0.8248847275972366 +Хеш-таблица,Отсортированный,Вставка,5,0.8270500153303146 +Хеш-таблица,Отсортированный,Вставка,Среднее,0.8244949847459793 +Хеш-таблица,Отсортированный,Поиск,1,0.008095510303974152 +Хеш-таблица,Отсортированный,Поиск,2,0.007643779739737511 +Хеш-таблица,Отсортированный,Поиск,3,0.007320135831832886 +Хеш-таблица,Отсортированный,Поиск,4,0.007490267977118492 +Хеш-таблица,Отсортированный,Поиск,5,0.0073973797261714935 +Хеш-таблица,Отсортированный,Поиск,Среднее,0.007589414715766907 +Хеш-таблица,Отсортированный,Удаление,1,0.0041198693215847015 +Хеш-таблица,Отсортированный,Удаление,2,0.005096178501844406 +Хеш-таблица,Отсортированный,Удаление,3,0.0038871560245752335 +Хеш-таблица,Отсортированный,Удаление,4,0.004979334771633148 +Хеш-таблица,Отсортированный,Удаление,5,0.005531288683414459 +Хеш-таблица,Отсортированный,Удаление,Среднее,0.0047227654606103895 +BST,Случайный,Вставка,1,0.061682142317295074 +BST,Случайный,Вставка,2,0.06325294077396393 +BST,Случайный,Вставка,3,0.06278556399047375 +BST,Случайный,Вставка,4,0.06266334094107151 +BST,Случайный,Вставка,5,0.0640009418129921 +BST,Случайный,Вставка,Среднее,0.06287698596715927 +BST,Случайный,Поиск,1,0.0005436446517705917 +BST,Случайный,Поиск,2,0.0005729794502258301 +BST,Случайный,Поиск,3,0.0005832426249980927 +BST,Случайный,Поиск,4,0.0005539115518331528 +BST,Случайный,Поиск,5,0.0005719996988773346 +BST,Случайный,Поиск,Среднее,0.0005651555955410003 +BST,Случайный,Удаление,1,0.00034173205494880676 +BST,Случайный,Удаление,2,0.00031582266092300415 +BST,Случайный,Удаление,3,0.000333910807967186 +BST,Случайный,Удаление,4,0.00034319981932640076 +BST,Случайный,Удаление,5,0.000340266153216362 +BST,Случайный,Удаление,Среднее,0.0003349862992763519 +BST,Отсортированный,Вставка,1,23.19616787880659 +BST,Отсортированный,Вставка,2,22.920896999537945 +BST,Отсортированный,Вставка,3,22.561782151460648 +BST,Отсортированный,Вставка,4,22.217343267053366 +BST,Отсортированный,Вставка,5,24.517986714839935 +BST,Отсортированный,Вставка,Среднее,23.082835402339697 +BST,Отсортированный,Поиск,1,0.1749225128442049 +BST,Отсортированный,Поиск,2,0.15511077642440796 +BST,Отсортированный,Поиск,3,0.15050886385142803 +BST,Отсортированный,Поиск,4,0.17243162170052528 +BST,Отсортированный,Поиск,5,0.19662086851894855 +BST,Отсортированный,Поиск,Среднее,0.16991892866790295 +BST,Отсортированный,Удаление,1,0.09117730148136616 +BST,Отсортированный,Удаление,2,0.09206805564463139 +BST,Отсортированный,Удаление,3,0.09830334596335888 +BST,Отсортированный,Удаление,4,0.08749254420399666 +BST,Отсортированный,Удаление,5,0.11593561433255672 +BST,Отсортированный,Удаление,Среднее,0.09699537232518196 diff --git a/raskatovia/docs/data/task1/zamery.py b/raskatovia/docs/data/task1/zamery.py new file mode 100644 index 0000000..47afb61 --- /dev/null +++ b/raskatovia/docs/data/task1/zamery.py @@ -0,0 +1,141 @@ +import csv +import random +import time +from spravochnik import * + +COUNT = 10000 +REPEATS = 5 + +def make_records(): + records = [] + for i in range(COUNT): + name = f"User_{i:05d}" + phone = str(89000000000 + i) + records.append((name, phone)) + shuffled = records[:] + random.shuffle(shuffled) + ordered = sorted(records, key=lambda item: item[0]) + return shuffled, ordered + +def make_search_names(records): + existing = [item[0] for item in random.sample(records, 100)] + missing = [f"None_{i}" for i in range(10)] + return existing + missing + +def make_delete_names(records): + return [item[0] for item in random.sample(records, 50)] + +def average(values): + return sum(values) / len(values) + +def test_list(records): + insert_times = [] + find_times = [] + delete_times = [] + for _ in range(REPEATS): + head = None + start = time.perf_counter() + for name, phone in records: + head = ll_insert(head, name, phone) + insert_times.append(time.perf_counter() - start) + + search_names = make_search_names(records) + start = time.perf_counter() + for name in search_names: + ll_find(head, name) + find_times.append(time.perf_counter() - start) + + delete_names = make_delete_names(records) + start = time.perf_counter() + for name in delete_names: + head = ll_delete(head, name) + delete_times.append(time.perf_counter() - start) + + return insert_times, find_times, delete_times + +def test_hash(records): + insert_times = [] + find_times = [] + delete_times = [] + for _ in range(REPEATS): + table = ht_create() + start = time.perf_counter() + for name, phone in records: + ht_insert(table, name, phone) + insert_times.append(time.perf_counter() - start) + + search_names = make_search_names(records) + start = time.perf_counter() + for name in search_names: + ht_find(table, name) + find_times.append(time.perf_counter() - start) + + delete_names = make_delete_names(records) + start = time.perf_counter() + for name in delete_names: + ht_delete(table, name) + delete_times.append(time.perf_counter() - start) + + return insert_times, find_times, delete_times + +def test_bst(records): + insert_times = [] + find_times = [] + delete_times = [] + for _ in range(REPEATS): + root = None + start = time.perf_counter() + for name, phone in records: + root = bst_insert(root, name, phone) + insert_times.append(time.perf_counter() - start) + + search_names = make_search_names(records) + start = time.perf_counter() + for name in search_names: + bst_find(root, name) + find_times.append(time.perf_counter() - start) + + delete_names = make_delete_names(records) + start = time.perf_counter() + for name in delete_names: + root = bst_delete(root, name) + delete_times.append(time.perf_counter() - start) + + return insert_times, find_times, delete_times + +def add_rows(rows, structure, mode, result): + names = ["Вставка", "Поиск", "Удаление"] + for operation, times in zip(names, result): + for number, value in enumerate(times, 1): + rows.append([structure, mode, operation, number, value]) + rows.append([structure, mode, operation, "Среднее", average(times)]) + +def main(): + shuffled, ordered = make_records() + rows = [["Структура", "Режим", "Операция", "Замер", "Время (сек)"]] + + print("Связный список, случайный порядок") + add_rows(rows, "Связный список", "Случайный", test_list(shuffled)) + + print("Связный список, отсортированный порядок") + add_rows(rows, "Связный список", "Отсортированный", test_list(ordered)) + + print("Хеш-таблица, случайный порядок") + add_rows(rows, "Хеш-таблица", "Случайный", test_hash(shuffled)) + + print("Хеш-таблица, отсортированный порядок") + add_rows(rows, "Хеш-таблица", "Отсортированный", test_hash(ordered)) + + print("BST, случайный порядок") + add_rows(rows, "BST", "Случайный", test_bst(shuffled)) + + print("BST, отсортированный порядок") + add_rows(rows, "BST", "Отсортированный", test_bst(ordered)) + + with open("raskatovia/docs/data/task1/results.csv", "w", newline="", encoding="utf-8") as file: + writer = csv.writer(file) + writer.writerows(rows) + + print("Результаты сохранены в results.csv") + +main() \ No newline at end of file -- 2.43.0 From c660025b78cf340e28cac382fe9f6cce3d169b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Mon, 18 May 2026 16:16:22 +0300 Subject: [PATCH 05/15] [1] add task report --- raskatovia/docs/task1report.md | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 raskatovia/docs/task1report.md diff --git a/raskatovia/docs/task1report.md b/raskatovia/docs/task1report.md new file mode 100644 index 0000000..a4672e5 --- /dev/null +++ b/raskatovia/docs/task1report.md @@ -0,0 +1,36 @@ + Цель работы +В этой работе я сделал телефонный справочник на основе трёх структур данных связного списка, хеш таблицы и двоичного дерева поиска. Для каждой структуры нужны были добавление, поиск, удаление и вывод всех записей по алфавиту. после этого я сравнил как они работают на перемешанных и отсортированных данных [сначала казалось что разница будет не такой заметной но после мы увидим что разница есть и в зависимости от задачи и ситуации]. + + Что было реализовано + Связный список +Узел списка хранит имя, телефон и ссылку на следующий элемент. При добавлении запись создаётся или обновляется если такое имя уже есть. Использованы функции ll_insert; ll_find; ll_delete; ll_list_all. [с этой структурой было проще всего начать, потому что логика достаточно прямая] + + Хеш таблица +Хеш таблица сделана как набор ячеек для записей. Для имени вычисляется место куда его сохранить. Если в этом месте уже есть записи они хранятся вместе в связном списке. Использованы функции ht_create; ht_insert; ht_find; ht_delete; ht_list_all. [здесь пришлось отдельно разобраться что делать если несколько имён попадают в одно место. В итоге для таких записей внутри одной ячейки используется связный список] + + Двоичное дерево поиска +В каждом узле дерева хранятся имя, телефон, левый и правый потомок. Записи размещаются по имени поэтому их можно вывести в отсортированном виде. Использованы функции bst_insert; bst_find; bst_delete; bst_list_all. [с удалением в дереве пришлось посидеть дольше всего. Ну если коротко у удаления в дереве несколько случаев: удаляется лист, у узла есть один потомок, у узла есть два потомка, тогда его нужно заменить ближайшим подходящим элементом] + + Проверка работы +В файле tests.py были сделаны простые проверки для всех трёх структур. Я проверил добавление записей; изменение телефона у уже существующего имени; поиск существующей и несуществующей записи; удаление и вывод списка по алфавиту. по результатам запуска всё сработало корректно. [было важно проверить основные операции ещё до замеров] + + Замеры времени +Для сравнения был создан набор из 10000 записей. Использовались два варианта случайный порядок и отсортированный порядок. Для каждой структуры измерялось время вставки всех записей; поиска 110 имён; удаления 50 записей. Каждый замер повторялся 5 раз. Средние значения приведены ниже а полные результаты сохранены в results.csv. [здесь пришлось отдельно разбираться как нормально замерять время. Сначала было не очень понятно как сравнивать структуры честно, потом сделал несколько повторов для каждого случая и считал среднее время] + + Результаты +Связный список; случайный порядок; вставка 17.54 сек; поиск 0.145 сек; удаление 0.086 сек. +Связный список; отсортированный порядок; вставка 15.01 сек; поиск 0.127 сек; удаление 0.074 сек. +Хеш таблица; случайный порядок; вставка 0.896 сек; поиск 0.008 сек; удаление 0.005 сек. +Хеш таблица; отсортированный порядок; вставка 1.253 сек; поиск 0.008 сек; удаление 0.005 сек. +BST; случайный порядок; вставка 0.063 сек; поиск 0.0006 сек; удаление 0.0003 сек. +BST; отсортированный порядок; вставка 23.08 сек; поиск 0.170 сек; удаление 0.097 сек. + + Анализ +По замерам видно что связный список медленно работает при вставке. Перед добавлением новой записи программа идёт по списку и проверяет нет ли уже такого имени. На 10000 записей это уже заметно. Поиск тоже идёт простым перебором. [вот тут стало понятнее почему список быстро начинает тормозить] + +Хеш таблица показала себя намного быстрее. Записи были и перемешанные и уже отсортированные но большой разницы во времени почти не получилось. [этот результат как раз хорошо показал зачем вообще нужна такая структура] + +BST на случайных данных оказался самым быстрым. А вот на отсортированных данных дерево сильно замедлилось. Оно вытягивается почти в одну линию и начинает работать похоже на список. Поэтому вставка заняла около 23 секунд вместо 0.06. [при подготовке замеров стало понятно что на отсортированных данных дерево сильно вытягивается в одну сторону, а старая рекурсивная версия могла плохо отработать на 10000 записей Поэтому часть работы с Бст пришлось переделать без рекурсии] + + Вывод +Связный список подойдёт для небольшого количества данных но для большого справочника он не очень удобен. Хеш таблица лучше подходит если важны быстрые добавление, поиск и удаление. BST удобно использовать когда нужен вывод записей по порядку но обычное дерево сильно зависит от того в каком порядке добавляются элементы. На отсортированных данных оно работает заметно хуже. в целом работа оказалась не самой простой, местами было довольно запутанно особенно с замерами и деревом на отсортированных данных но в итоге было интересно увидеть насколько по-разному ведут себя разные структуры. \ No newline at end of file -- 2.43.0 From 7a147d6cb481efe2401277623037be830ef93232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Mon, 18 May 2026 17:11:16 +0300 Subject: [PATCH 06/15] [1] add graph with results --- raskatovia/docs/data/task1/graph.png | Bin 0 -> 17472 bytes raskatovia/docs/task1report.md | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 raskatovia/docs/data/task1/graph.png diff --git a/raskatovia/docs/data/task1/graph.png b/raskatovia/docs/data/task1/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..1366b9e0bb1855282f3e6eee6ff45dc461d671e0 GIT binary patch literal 17472 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 YrCX)tB_(B18%(9CrhDe;k5_*FUp282V*mgE literal 0 HcmV?d00001 diff --git a/raskatovia/docs/task1report.md b/raskatovia/docs/task1report.md index a4672e5..465ae72 100644 --- a/raskatovia/docs/task1report.md +++ b/raskatovia/docs/task1report.md @@ -32,5 +32,7 @@ BST; отсортированный порядок; вставка 23.08 сек; BST на случайных данных оказался самым быстрым. А вот на отсортированных данных дерево сильно замедлилось. Оно вытягивается почти в одну линию и начинает работать похоже на список. Поэтому вставка заняла около 23 секунд вместо 0.06. [при подготовке замеров стало понятно что на отсортированных данных дерево сильно вытягивается в одну сторону, а старая рекурсивная версия могла плохо отработать на 10000 записей Поэтому часть работы с Бст пришлось переделать без рекурсии] +!!График среднего времени вставки сохранён в файле graph.png. + Вывод Связный список подойдёт для небольшого количества данных но для большого справочника он не очень удобен. Хеш таблица лучше подходит если важны быстрые добавление, поиск и удаление. BST удобно использовать когда нужен вывод записей по порядку но обычное дерево сильно зависит от того в каком порядке добавляются элементы. На отсортированных данных оно работает заметно хуже. в целом работа оказалась не самой простой, местами было довольно запутанно особенно с замерами и деревом на отсортированных данных но в итоге было интересно увидеть насколько по-разному ведут себя разные структуры. \ No newline at end of file -- 2.43.0 From c1086c89c35c80a0e608f2915c626b949705c342 Mon Sep 17 00:00:00 2001 From: raskatovia Date: Fri, 22 May 2026 21:11:03 +0300 Subject: [PATCH 07/15] =?UTF-8?q?[2]=20=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=83=20=D1=81=20=D0=BB=D0=B0?= =?UTF-8?q?=D0=B1=D0=B8=D1=80=D0=B8=D0=BD=D1=82=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- raskatovia/docs/data/task2/maze.py | 0 raskatovia/docs/data/task2/solver.py | 0 raskatovia/docs/task2report.md | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 raskatovia/docs/data/task2/maze.py create mode 100644 raskatovia/docs/data/task2/solver.py create mode 100644 raskatovia/docs/task2report.md diff --git a/raskatovia/docs/data/task2/maze.py b/raskatovia/docs/data/task2/maze.py new file mode 100644 index 0000000..e69de29 diff --git a/raskatovia/docs/data/task2/solver.py b/raskatovia/docs/data/task2/solver.py new file mode 100644 index 0000000..e69de29 diff --git a/raskatovia/docs/task2report.md b/raskatovia/docs/task2report.md new file mode 100644 index 0000000..e69de29 -- 2.43.0 From a912487cdc6fac46e5a02e0ce5fb81bd6b654ae7 Mon Sep 17 00:00:00 2001 From: raskatovia Date: Fri, 22 May 2026 21:24:59 +0300 Subject: [PATCH 08/15] =?UTF-8?q?[2]=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D1=8C=20=D0=BB?= =?UTF-8?q?=D0=B0=D0=B1=D0=B8=D1=80=D0=B8=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- raskatovia/docs/data/task2/maps/simple.txt | 5 ++ raskatovia/docs/data/task2/maze.py | 96 ++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 raskatovia/docs/data/task2/maps/simple.txt diff --git a/raskatovia/docs/data/task2/maps/simple.txt b/raskatovia/docs/data/task2/maps/simple.txt new file mode 100644 index 0000000..fe2e907 --- /dev/null +++ b/raskatovia/docs/data/task2/maps/simple.txt @@ -0,0 +1,5 @@ +####### +#S...F# +#.###.# +#.....# +####### \ No newline at end of file diff --git a/raskatovia/docs/data/task2/maze.py b/raskatovia/docs/data/task2/maze.py index e69de29..da42d64 100644 --- a/raskatovia/docs/data/task2/maze.py +++ b/raskatovia/docs/data/task2/maze.py @@ -0,0 +1,96 @@ +class Cell: + def __init__(self, row, col, value): + self.row = row + self.col = col + self.value = value + + def is_wall(self): + return self.value == "#" + + def is_start(self): + return self.value == "S" + + def is_finish(self): + return self.value == "F" + + +class Maze: + def __init__(self, cells, start, finish): + self.cells = cells + self.start = start + self.finish = finish + self.height = len(cells) + self.width = len(cells[0]) if cells else 0 + + def inside(self, row, col): + return 0 <= row < self.height and 0 <= col < self.width + + def get_cell(self, row, col): + if not self.inside(row, col): + return None + return self.cells[row][col] + + def is_free(self, row, col): + cell = self.get_cell(row, col) + return cell is not None and not cell.is_wall() + + def neighbors(self, row, col): + variants = [ + (row - 1, col), + (row + 1, col), + (row, col - 1), + (row, col + 1) + ] + result = [] + for next_row, next_col in variants: + if self.is_free(next_row, next_col): + result.append((next_row, next_col)) + return result + + def draw(self, path=None): + path_set = set(path) if path else set() + lines = [] + for row in range(self.height): + line = "" + for col in range(self.width): + cell = self.cells[row][col] + if (row, col) in path_set and not cell.is_start() and not cell.is_finish(): + line += "*" + else: + line += cell.value + lines.append(line) + return "\n".join(lines) + + +class MazeBuilder: + def __init__(self): + self.lines = [] + + def from_file(self, filename): + with open(filename, "r", encoding="utf-8") as file: + self.lines = [line.rstrip("\n") for line in file if line.strip()] + return self + + def build(self): + cells = [] + start = None + finish = None + width = len(self.lines[0]) + + for row, line in enumerate(self.lines): + if len(line) != width: + raise ValueError("maze lines have different length") + cell_row = [] + for col, value in enumerate(line): + cell = Cell(row, col, value) + if cell.is_start(): + start = (row, col) + if cell.is_finish(): + finish = (row, col) + cell_row.append(cell) + cells.append(cell_row) + + if start is None or finish is None: + raise ValueError("maze must have start and finish") + + return Maze(cells, start, finish) \ No newline at end of file -- 2.43.0 From 308ee2d7166f8dffae01102c437374aa1f02b128 Mon Sep 17 00:00:00 2001 From: raskatovia Date: Fri, 22 May 2026 21:26:10 +0300 Subject: [PATCH 09/15] =?UTF-8?q?[2]=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=20=D0=B2=20=D1=88?= =?UTF-8?q?=D0=B8=D1=80=D0=B8=D0=BD=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- raskatovia/docs/data/task2/solver.py | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/raskatovia/docs/data/task2/solver.py b/raskatovia/docs/data/task2/solver.py index e69de29..ae1b9f4 100644 --- a/raskatovia/docs/data/task2/solver.py +++ b/raskatovia/docs/data/task2/solver.py @@ -0,0 +1,58 @@ +from collections import deque +from maze import MazeBuilder + +def build_path(previous, start, finish): + if finish not in previous: + return [] + path = [] + current = finish + while current != start: + path.append(current) + current = previous[current] + path.append(start) + path.reverse() + return path + +class BfsStrategy: + def solve(self, maze): + start = maze.start + finish = maze.finish + queue = deque([start]) + previous = {start: None} + visited_count = 0 + + while queue: + current = queue.popleft() + visited_count += 1 + + if current == finish: + break + + for next_cell in maze.neighbors(current[0], current[1]): + if next_cell not in previous: + previous[next_cell] = current + queue.append(next_cell) + + path = build_path(previous, start, finish) + return { + "name": "BFS", + "path": path, + "visited": visited_count, + "length": len(path) + } + +class MazeSolver: + def __init__(self, strategy): + self.strategy = strategy + + def solve(self, maze): + return self.strategy.solve(maze) + +if __name__ == "__main__": + maze = MazeBuilder().from_file("raskatovia/docs/data/task2/maps/simple.txt").build() + solver = MazeSolver(BfsStrategy()) + result = solver.solve(maze) + print("algorithm:", result["name"]) + print("visited:", result["visited"]) + print("length:", result["length"]) + print(maze.draw(result["path"])) \ No newline at end of file -- 2.43.0 From a339b8fb6f108ea1d992de585054909d0db51e0f Mon Sep 17 00:00:00 2001 From: raskatovia Date: Fri, 22 May 2026 21:34:27 +0300 Subject: [PATCH 10/15] =?UTF-8?q?[2]=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=20=D0=B2=20=D0=B3?= =?UTF-8?q?=D0=BB=D1=83=D0=B1=D0=B8=D0=BD=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- raskatovia/docs/data/task2/solver.py | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/raskatovia/docs/data/task2/solver.py b/raskatovia/docs/data/task2/solver.py index ae1b9f4..bad83a7 100644 --- a/raskatovia/docs/data/task2/solver.py +++ b/raskatovia/docs/data/task2/solver.py @@ -40,6 +40,33 @@ class BfsStrategy: "visited": visited_count, "length": len(path) } +class DfsStrategy: + def solve(self, maze): + start = maze.start + finish = maze.finish + stack = [start] + previous = {start: None} + visited_count = 0 + + while stack: + current = stack.pop() + visited_count += 1 + + if current == finish: + break + + for next_cell in maze.neighbors(current[0], current[1]): + if next_cell not in previous: + previous[next_cell] = current + stack.append(next_cell) + + path = build_path(previous, start, finish) + return { + "name": "DFS", + "path": path, + "visited": visited_count, + "length": len(path) + } class MazeSolver: def __init__(self, strategy): @@ -50,7 +77,7 @@ class MazeSolver: if __name__ == "__main__": maze = MazeBuilder().from_file("raskatovia/docs/data/task2/maps/simple.txt").build() - solver = MazeSolver(BfsStrategy()) + solver = MazeSolver(DfsStrategy()) result = solver.solve(maze) print("algorithm:", result["name"]) print("visited:", result["visited"]) -- 2.43.0 From f3270c41979c3fd091f3c66ee81d05112ebb12b2 Mon Sep 17 00:00:00 2001 From: raskatovia Date: Fri, 22 May 2026 21:39:47 +0300 Subject: [PATCH 11/15] =?UTF-8?q?[2]=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=B8=D0=BB=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=BD=D1=8B=D1=85=20=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=B3=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- raskatovia/docs/data/task2/solver.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/raskatovia/docs/data/task2/solver.py b/raskatovia/docs/data/task2/solver.py index bad83a7..1f22173 100644 --- a/raskatovia/docs/data/task2/solver.py +++ b/raskatovia/docs/data/task2/solver.py @@ -77,9 +77,13 @@ class MazeSolver: if __name__ == "__main__": maze = MazeBuilder().from_file("raskatovia/docs/data/task2/maps/simple.txt").build() - solver = MazeSolver(DfsStrategy()) - result = solver.solve(maze) - print("algorithm:", result["name"]) - print("visited:", result["visited"]) - print("length:", result["length"]) - print(maze.draw(result["path"])) \ No newline at end of file + strategies = [BfsStrategy(), DfsStrategy()] + + for strategy in strategies: + solver = MazeSolver(strategy) + result = solver.solve(maze) + print("algorithm:", result["name"]) + print("visited:", result["visited"]) + print("length:", result["length"]) + print(maze.draw(result["path"])) + print() \ No newline at end of file -- 2.43.0 From fa3d95b5c07d9bb74376460a67bdd0dd94b00f13 Mon Sep 17 00:00:00 2001 From: raskatovia Date: Fri, 22 May 2026 21:44:40 +0300 Subject: [PATCH 12/15] =?UTF-8?q?[2]=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=20astar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- raskatovia/docs/data/task2/solver.py | 41 +++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/raskatovia/docs/data/task2/solver.py b/raskatovia/docs/data/task2/solver.py index 1f22173..ad20457 100644 --- a/raskatovia/docs/data/task2/solver.py +++ b/raskatovia/docs/data/task2/solver.py @@ -1,3 +1,7 @@ +from collections import deque +import heapq +from maze import MazeBuilder + from collections import deque from maze import MazeBuilder @@ -67,6 +71,41 @@ class DfsStrategy: "visited": visited_count, "length": len(path) } +def distance(first, second): + return abs(first[0] - second[0]) + abs(first[1] - second[1]) + +class AstarStrategy: + def solve(self, maze): + start = maze.start + finish = maze.finish + queue = [] + heapq.heappush(queue, (0, start)) + previous = {start: None} + costs = {start: 0} + visited_count = 0 + + while queue: + current = heapq.heappop(queue)[1] + visited_count += 1 + + if current == finish: + break + + for next_cell in maze.neighbors(current[0], current[1]): + new_cost = costs[current] + 1 + if next_cell not in costs or new_cost < costs[next_cell]: + costs[next_cell] = new_cost + priority = new_cost + distance(next_cell, finish) + heapq.heappush(queue, (priority, next_cell)) + previous[next_cell] = current + + path = build_path(previous, start, finish) + return { + "name": "A*", + "path": path, + "visited": visited_count, + "length": len(path) + } class MazeSolver: def __init__(self, strategy): @@ -77,7 +116,7 @@ class MazeSolver: if __name__ == "__main__": maze = MazeBuilder().from_file("raskatovia/docs/data/task2/maps/simple.txt").build() - strategies = [BfsStrategy(), DfsStrategy()] + strategies = [BfsStrategy(), DfsStrategy(), AstarStrategy()] for strategy in strategies: solver = MazeSolver(strategy) -- 2.43.0 From c19eb1a1f61a7da36c38974a6e34aca4440c5370 Mon Sep 17 00:00:00 2001 From: raskatovia Date: Sat, 23 May 2026 12:11:53 +0300 Subject: [PATCH 13/15] =?UTF-8?q?[2]=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=D1=8B=D0=B5?= =?UTF-8?q?=20=D0=BB=D0=B0=D0=B1=D0=B8=D1=80=D0=B8=D0=BD=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- raskatovia/docs/data/task2/maps/hard.txt | 9 ++++++++ raskatovia/docs/data/task2/maps/medium.txt | 7 ++++++ raskatovia/docs/data/task2/solver.py | 25 ++++++++++++++-------- 3 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 raskatovia/docs/data/task2/maps/hard.txt create mode 100644 raskatovia/docs/data/task2/maps/medium.txt diff --git a/raskatovia/docs/data/task2/maps/hard.txt b/raskatovia/docs/data/task2/maps/hard.txt new file mode 100644 index 0000000..99fb354 --- /dev/null +++ b/raskatovia/docs/data/task2/maps/hard.txt @@ -0,0 +1,9 @@ +############### +#S....#.......# +#.###.#.#####.# +#...#.#.....#.# +###.#.#####.#.# +#...#.....#.#.# +#.#######.#.#.# +#............F# +############### \ No newline at end of file diff --git a/raskatovia/docs/data/task2/maps/medium.txt b/raskatovia/docs/data/task2/maps/medium.txt new file mode 100644 index 0000000..70ac804 --- /dev/null +++ b/raskatovia/docs/data/task2/maps/medium.txt @@ -0,0 +1,7 @@ +########### +#S..#.....# +###.#.###.# +#...#...#.# +#.#####.#.# +#.......#F# +########### \ No newline at end of file diff --git a/raskatovia/docs/data/task2/solver.py b/raskatovia/docs/data/task2/solver.py index ad20457..4456ec5 100644 --- a/raskatovia/docs/data/task2/solver.py +++ b/raskatovia/docs/data/task2/solver.py @@ -115,14 +115,21 @@ class MazeSolver: return self.strategy.solve(maze) if __name__ == "__main__": - maze = MazeBuilder().from_file("raskatovia/docs/data/task2/maps/simple.txt").build() + files = [ + "simple.txt", + "medium.txt", + "hard.txt" + ] strategies = [BfsStrategy(), DfsStrategy(), AstarStrategy()] - for strategy in strategies: - solver = MazeSolver(strategy) - result = solver.solve(maze) - print("algorithm:", result["name"]) - print("visited:", result["visited"]) - print("length:", result["length"]) - print(maze.draw(result["path"])) - print() \ No newline at end of file + for filename in files: + print("map:", filename) + maze = MazeBuilder().from_file("raskatovia/docs/data/task2/maps/" + filename).build() + for strategy in strategies: + solver = MazeSolver(strategy) + result = solver.solve(maze) + print("algorithm:", result["name"]) + print("visited:", result["visited"]) + print("length:", result["length"]) + print(maze.draw(result["path"])) + print() \ No newline at end of file -- 2.43.0 From 5b6854061555ef434548bef3a4b62024eac0a569 Mon Sep 17 00:00:00 2001 From: raskatovia Date: Sat, 23 May 2026 12:14:08 +0300 Subject: [PATCH 14/15] =?UTF-8?q?[2]=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BB=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=80=D1=8B=20=D0=B0=D0=BB?= =?UTF-8?q?=D0=B3=D0=BE=D1=80=D0=B8=D1=82=D0=BC=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- raskatovia/docs/data/task2/results.csv | 46 ++++++++++++++++++++++++++ raskatovia/docs/data/task2/zamery.py | 40 ++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 raskatovia/docs/data/task2/results.csv create mode 100644 raskatovia/docs/data/task2/zamery.py diff --git a/raskatovia/docs/data/task2/results.csv b/raskatovia/docs/data/task2/results.csv new file mode 100644 index 0000000..3a391b8 --- /dev/null +++ b/raskatovia/docs/data/task2/results.csv @@ -0,0 +1,46 @@ +map,algorithm,try,time,visited,length +simple.txt,BFS,1,2.6000008801929653e-05,9,5 +simple.txt,BFS,2,1.4800010831095278e-05,9,5 +simple.txt,BFS,3,1.2799995602108538e-05,9,5 +simple.txt,BFS,4,1.1600001016631722e-05,9,5 +simple.txt,BFS,5,1.1399999493733048e-05,9,5 +simple.txt,DFS,1,9.60000033956021e-06,5,5 +simple.txt,DFS,2,7.199996616691351e-06,5,5 +simple.txt,DFS,3,6.300004315562546e-06,5,5 +simple.txt,DFS,4,6.200003554113209e-06,5,5 +simple.txt,DFS,5,6.200003554113209e-06,5,5 +simple.txt,A*,1,1.4599994756281376e-05,5,5 +simple.txt,A*,2,9.499999578110874e-06,5,5 +simple.txt,A*,3,8.29999044071883e-06,5,5 +simple.txt,A*,4,8.300004992634058e-06,5,5 +simple.txt,A*,5,2.4499997380189598e-05,5,5 +medium.txt,BFS,1,4.0400002035312355e-05,29,29 +medium.txt,BFS,2,3.700000524986535e-05,29,29 +medium.txt,BFS,3,3.670000296551734e-05,29,29 +medium.txt,BFS,4,3.470000228844583e-05,29,29 +medium.txt,BFS,5,3.370000922586769e-05,29,29 +medium.txt,DFS,1,3.4199998481199145e-05,29,29 +medium.txt,DFS,2,3.369999467395246e-05,29,29 +medium.txt,DFS,3,3.329999162815511e-05,29,29 +medium.txt,DFS,4,3.309999010525644e-05,29,29 +medium.txt,DFS,5,3.300000389572233e-05,29,29 +medium.txt,A*,1,4.470000567380339e-05,29,29 +medium.txt,A*,2,4.549999721348286e-05,29,29 +medium.txt,A*,3,4.259998968336731e-05,29,29 +medium.txt,A*,4,4.260000423528254e-05,29,29 +medium.txt,A*,5,4.1799998143687844e-05,29,29 +hard.txt,BFS,1,4.680000711232424e-05,38,19 +hard.txt,BFS,2,4.390001413412392e-05,38,19 +hard.txt,BFS,3,4.4200001866556704e-05,38,19 +hard.txt,BFS,4,4.2100000428035855e-05,38,19 +hard.txt,BFS,5,4.389999958220869e-05,38,19 +hard.txt,DFS,1,2.570000651758164e-05,19,19 +hard.txt,DFS,2,2.1800005924887955e-05,19,19 +hard.txt,DFS,3,2.19999928958714e-05,19,19 +hard.txt,DFS,4,2.1799991372972727e-05,19,19 +hard.txt,DFS,5,2.1799991372972727e-05,19,19 +hard.txt,A*,1,4.149999585933983e-05,25,19 +hard.txt,A*,2,3.7699996028095484e-05,25,19 +hard.txt,A*,3,3.6999990697950125e-05,25,19 +hard.txt,A*,4,3.680000372696668e-05,25,19 +hard.txt,A*,5,3.720000677276403e-05,25,19 diff --git a/raskatovia/docs/data/task2/zamery.py b/raskatovia/docs/data/task2/zamery.py new file mode 100644 index 0000000..c6f2656 --- /dev/null +++ b/raskatovia/docs/data/task2/zamery.py @@ -0,0 +1,40 @@ +import csv +import time +from maze import MazeBuilder +from solver import BfsStrategy, DfsStrategy, AstarStrategy, MazeSolver + +MAPS = ["simple.txt", "medium.txt", "hard.txt"] +REPEATS = 5 + +def run_one(filename, strategy): + maze = MazeBuilder().from_file("raskatovia/docs/data/task2/maps/" + filename).build() + solver = MazeSolver(strategy) + start = time.perf_counter() + result = solver.solve(maze) + work_time = time.perf_counter() - start + return result, work_time + +def main(): + rows = [["map", "algorithm", "try", "time", "visited", "length"]] + strategies = [BfsStrategy(), DfsStrategy(), AstarStrategy()] + + for filename in MAPS: + for strategy in strategies: + for number in range(1, REPEATS + 1): + result, work_time = run_one(filename, strategy) + rows.append([ + filename, + result["name"], + number, + work_time, + result["visited"], + result["length"] + ]) + + with open("raskatovia/docs/data/task2/results.csv", "w", newline="", encoding="utf-8") as file: + writer = csv.writer(file) + writer.writerows(rows) + + print("results saved") + +main() \ No newline at end of file -- 2.43.0 From 65594bdb6e5a1da699632f17c7b1f64d1d372fbc Mon Sep 17 00:00:00 2001 From: raskatovia Date: Sat, 23 May 2026 12:34:31 +0300 Subject: [PATCH 15/15] =?UTF-8?q?[2]=20=D0=BE=D1=84=D0=BE=D1=80=D0=BC?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BE=D1=82=D1=87=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- raskatovia/docs/task2report.md | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/raskatovia/docs/task2report.md b/raskatovia/docs/task2report.md index e69de29..d78ae3b 100644 --- a/raskatovia/docs/task2report.md +++ b/raskatovia/docs/task2report.md @@ -0,0 +1,46 @@ +Цель работы + +В этом задании я сделал программу для поиска пути в лабиринте. Лабиринт загружается из текстового файла, после этого для него запускаются три алгоритма: BFS, DFS и A\*. Нужно было сравнить как они проходят разные карты + + + + В файле maze.py находится описание лабиринта. Cell отвечает за отдельную клетку, а Maze хранит всю карту, старт, финиш и умеет находить соседние клетки, куда можно идти. Для загрузки карты из файла сделан MazeBuilder. Он читает строки, проверяет их длину и ищет точки S и F. \[тут я столкнулся с ошибкой на hard.txt, потому что одна строка была другой длины] + + В файле solver.py находится поиск пути.MazeSolver получает стратегию поиска и запускает её. Были сделаны три стратегии: BfsStrategy, DfsStrategy и AstarStrategy. BFS идёт в ширину, DFS идёт в глубину, а A\* использует расстояние до финиша + + Сначала программа проверялась на simple.txt, потом были добавлены medium.txt и hard.txt. Для каждой карты запускались все три алгоритма. Программа выводила найденный путь, количество посещённых клеток и длину пути + + Для замеров сделан файл zamery.py. Он запускает алгоритмы по 5 раз и сохраняет результаты в results.csv + + Результаты + +simple.txt; BFS; время 0.00001532; посещено 9; длина пути 5 + +simple.txt; DFS; время 0.00000710; посещено 5; длина пути 5 + +simple.txt; A\*; время 0.00001304; посещено 5; длина пути 5 + + + +medium.txt; BFS; время 0.00003650; посещено 29; длина пути 29 + +medium.txt; DFS; время 0.00003346; посещено 29; длина пути 29 + +medium.txt; A\*; время 0.00004344; посещено 29; длина пути 29 + + + +hard.txt; BFS; время 0.00004418; посещено 38; длина пути 19 + +hard.txt; DFS; время 0.00002262; посещено 19; длина пути 19 + +hard.txt; A\*; время 0.00003804; посещено 25; длина пути 19 + + + + По результатам видно, что на простом лабиринте разница почти не важна. На medium.txt все алгоритмы прошли примерно одинаково. На hard.txt разница заметнее: BFS посетил больше всего клеток, DFS меньше всего, а A\* оказался между ними. При этом длина пути на hard.txt у всех получилась одинаковая + + Заключение + +В работе получилось сделать загрузку лабиринта из файла и несколько способов поиска пути. BFS надёжный, но может обходить больше клеток. DFS простой и иногда быстро доходит до финиша, но зависит от формы лабиринта. A\* старается идти ближе к цели, но на маленьких картах его преимущество не всегда видно.В целом задание было понятнее когда появились карты и путь стал выводиться прямо в консоли. Самая заметная проблема была с неправильной строкой в hard.txt, но после исправления все карты начали нормально запускаться + -- 2.43.0