forked from UNN/2026-rff_mp
Merge pull request '[1,2] data structures and maze solver' (#216) from raskatovia/2026-rff_mp:raskatovia-3 into develop
Reviewed-on: UNN/2026-rff_mp#216
This commit is contained in:
commit
05f56d5be3
BIN
raskatovia/docs/data/task1/graph.png
Normal file
BIN
raskatovia/docs/data/task1/graph.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
109
raskatovia/docs/data/task1/results.csv
Normal file
109
raskatovia/docs/data/task1/results.csv
Normal file
|
|
@ -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
|
||||||
|
154
raskatovia/docs/data/task1/spravochnik.py
Normal file
154
raskatovia/docs/data/task1/spravochnik.py
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
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):
|
||||||
|
new_node = {"name": name, "phone": phone, "left": None, "right": None}
|
||||||
|
if root is None:
|
||||||
|
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):
|
||||||
|
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):
|
||||||
|
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 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 = []
|
||||||
|
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
|
||||||
46
raskatovia/docs/data/task1/tests.py
Normal file
46
raskatovia/docs/data/task1/tests.py
Normal file
|
|
@ -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()
|
||||||
141
raskatovia/docs/data/task1/zamery.py
Normal file
141
raskatovia/docs/data/task1/zamery.py
Normal file
|
|
@ -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()
|
||||||
9
raskatovia/docs/data/task2/maps/hard.txt
Normal file
9
raskatovia/docs/data/task2/maps/hard.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
###############
|
||||||
|
#S....#.......#
|
||||||
|
#.###.#.#####.#
|
||||||
|
#...#.#.....#.#
|
||||||
|
###.#.#####.#.#
|
||||||
|
#...#.....#.#.#
|
||||||
|
#.#######.#.#.#
|
||||||
|
#............F#
|
||||||
|
###############
|
||||||
7
raskatovia/docs/data/task2/maps/medium.txt
Normal file
7
raskatovia/docs/data/task2/maps/medium.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
###########
|
||||||
|
#S..#.....#
|
||||||
|
###.#.###.#
|
||||||
|
#...#...#.#
|
||||||
|
#.#####.#.#
|
||||||
|
#.......#F#
|
||||||
|
###########
|
||||||
5
raskatovia/docs/data/task2/maps/simple.txt
Normal file
5
raskatovia/docs/data/task2/maps/simple.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#######
|
||||||
|
#S...F#
|
||||||
|
#.###.#
|
||||||
|
#.....#
|
||||||
|
#######
|
||||||
96
raskatovia/docs/data/task2/maze.py
Normal file
96
raskatovia/docs/data/task2/maze.py
Normal file
|
|
@ -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)
|
||||||
46
raskatovia/docs/data/task2/results.csv
Normal file
46
raskatovia/docs/data/task2/results.csv
Normal file
|
|
@ -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
|
||||||
|
135
raskatovia/docs/data/task2/solver.py
Normal file
135
raskatovia/docs/data/task2/solver.py
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
from collections import deque
|
||||||
|
import heapq
|
||||||
|
from maze import MazeBuilder
|
||||||
|
|
||||||
|
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 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)
|
||||||
|
}
|
||||||
|
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):
|
||||||
|
self.strategy = strategy
|
||||||
|
|
||||||
|
def solve(self, maze):
|
||||||
|
return self.strategy.solve(maze)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
files = [
|
||||||
|
"simple.txt",
|
||||||
|
"medium.txt",
|
||||||
|
"hard.txt"
|
||||||
|
]
|
||||||
|
strategies = [BfsStrategy(), DfsStrategy(), AstarStrategy()]
|
||||||
|
|
||||||
|
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()
|
||||||
40
raskatovia/docs/data/task2/zamery.py
Normal file
40
raskatovia/docs/data/task2/zamery.py
Normal file
|
|
@ -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()
|
||||||
38
raskatovia/docs/task1report.md
Normal file
38
raskatovia/docs/task1report.md
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
Цель работы
|
||||||
|
В этой работе я сделал телефонный справочник на основе трёх структур данных связного списка, хеш таблицы и двоичного дерева поиска. Для каждой структуры нужны были добавление, поиск, удаление и вывод всех записей по алфавиту. после этого я сравнил как они работают на перемешанных и отсортированных данных [сначала казалось что разница будет не такой заметной но после мы увидим что разница есть и в зависимости от задачи и ситуации].
|
||||||
|
|
||||||
|
Что было реализовано
|
||||||
|
Связный список
|
||||||
|
Узел списка хранит имя, телефон и ссылку на следующий элемент. При добавлении запись создаётся или обновляется если такое имя уже есть. Использованы функции 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 записей Поэтому часть работы с Бст пришлось переделать без рекурсии]
|
||||||
|
|
||||||
|
!!График среднего времени вставки сохранён в файле graph.png.
|
||||||
|
|
||||||
|
Вывод
|
||||||
|
Связный список подойдёт для небольшого количества данных но для большого справочника он не очень удобен. Хеш таблица лучше подходит если важны быстрые добавление, поиск и удаление. BST удобно использовать когда нужен вывод записей по порядку но обычное дерево сильно зависит от того в каком порядке добавляются элементы. На отсортированных данных оно работает заметно хуже. в целом работа оказалась не самой простой, местами было довольно запутанно особенно с замерами и деревом на отсортированных данных но в итоге было интересно увидеть насколько по-разному ведут себя разные структуры.
|
||||||
46
raskatovia/docs/task2report.md
Normal file
46
raskatovia/docs/task2report.md
Normal file
|
|
@ -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, но после исправления все карты начали нормально запускаться
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user