This commit is contained in:
Andrey 2026-09-05 01:36:33 +03:00
parent e6b4e51999
commit 5d337d933b
8 changed files with 2278946 additions and 132 deletions

View File

@ -1,109 +1,109 @@
Structure,Mode,Operation,Time (sec) Structure,Mode,Operation,Time (sec)
LinkedList,random,insert (trial 1),3.415125 LinkedList,random,insert (trial 1),3.492299
LinkedList,random,find (trial 1),0.035397 LinkedList,random,find (trial 1),0.037285
LinkedList,random,delete (trial 1),0.017692 LinkedList,random,delete (trial 1),0.017788
LinkedList,random,insert (trial 2),3.534952 LinkedList,random,insert (trial 2),3.626929
LinkedList,random,find (trial 2),0.038819 LinkedList,random,find (trial 2),0.037489
LinkedList,random,delete (trial 2),0.021675 LinkedList,random,delete (trial 2),0.017875
LinkedList,random,insert (trial 3),3.493529 LinkedList,random,insert (trial 3),3.520048
LinkedList,random,find (trial 3),0.036592 LinkedList,random,find (trial 3),0.038240
LinkedList,random,delete (trial 3),0.018221 LinkedList,random,delete (trial 3),0.017604
LinkedList,random,insert (trial 4),3.340745 LinkedList,random,insert (trial 4),3.506699
LinkedList,random,find (trial 4),0.036098 LinkedList,random,find (trial 4),0.038922
LinkedList,random,delete (trial 4),0.017576 LinkedList,random,delete (trial 4),0.018784
LinkedList,random,insert (trial 5),3.369741 LinkedList,random,insert (trial 5),3.556780
LinkedList,random,find (trial 5),0.035302 LinkedList,random,find (trial 5),0.038981
LinkedList,random,delete (trial 5),0.017674 LinkedList,random,delete (trial 5),0.018246
LinkedList,random,Insert (avg),3.430818 LinkedList,random,Insert (avg),3.540551
LinkedList,random,Find (avg),0.036442 LinkedList,random,Find (avg),0.038183
LinkedList,random,Delete (avg),0.018568 LinkedList,random,Delete (avg),0.018059
LinkedList,sorted,insert (trial 1),3.118200 LinkedList,sorted,insert (trial 1),3.346370
LinkedList,sorted,find (trial 1),0.037116 LinkedList,sorted,find (trial 1),0.040201
LinkedList,sorted,delete (trial 1),0.019387 LinkedList,sorted,delete (trial 1),0.020495
LinkedList,sorted,insert (trial 2),3.338498 LinkedList,sorted,insert (trial 2),3.314037
LinkedList,sorted,find (trial 2),0.036500 LinkedList,sorted,find (trial 2),0.038854
LinkedList,sorted,delete (trial 2),0.019001 LinkedList,sorted,delete (trial 2),0.019935
LinkedList,sorted,insert (trial 3),3.136906 LinkedList,sorted,insert (trial 3),3.354769
LinkedList,sorted,find (trial 3),0.037498 LinkedList,sorted,find (trial 3),0.039805
LinkedList,sorted,delete (trial 3),0.019219 LinkedList,sorted,delete (trial 3),0.020464
LinkedList,sorted,insert (trial 4),3.253578 LinkedList,sorted,insert (trial 4),3.406509
LinkedList,sorted,find (trial 4),0.036434 LinkedList,sorted,find (trial 4),0.039368
LinkedList,sorted,delete (trial 4),0.019333 LinkedList,sorted,delete (trial 4),0.020180
LinkedList,sorted,insert (trial 5),3.207896 LinkedList,sorted,insert (trial 5),3.403112
LinkedList,sorted,find (trial 5),0.038585 LinkedList,sorted,find (trial 5),0.039473
LinkedList,sorted,delete (trial 5),0.020473 LinkedList,sorted,delete (trial 5),0.020447
LinkedList,sorted,Insert (avg),3.211016 LinkedList,sorted,Insert (avg),3.364960
LinkedList,sorted,Find (avg),0.037227 LinkedList,sorted,Find (avg),0.039540
LinkedList,sorted,Delete (avg),0.019482 LinkedList,sorted,Delete (avg),0.020304
HashTable,random,insert (trial 1),0.010124 HashTable,random,insert (trial 1),0.009849
HashTable,random,find (trial 1),0.000093 HashTable,random,find (trial 1),0.000086
HashTable,random,delete (trial 1),0.000052 HashTable,random,delete (trial 1),0.000048
HashTable,random,insert (trial 2),0.010397 HashTable,random,insert (trial 2),0.009472
HashTable,random,find (trial 2),0.000086 HashTable,random,find (trial 2),0.000083
HashTable,random,delete (trial 2),0.000048 HashTable,random,delete (trial 2),0.000044
HashTable,random,insert (trial 3),0.009352 HashTable,random,insert (trial 3),0.009662
HashTable,random,find (trial 3),0.000081 HashTable,random,find (trial 3),0.000082
HashTable,random,delete (trial 3),0.000046 HashTable,random,delete (trial 3),0.000044
HashTable,random,insert (trial 4),0.009326 HashTable,random,insert (trial 4),0.009410
HashTable,random,find (trial 4),0.000080 HashTable,random,find (trial 4),0.000082
HashTable,random,delete (trial 4),0.000046 HashTable,random,delete (trial 4),0.000044
HashTable,random,insert (trial 5),0.010205 HashTable,random,insert (trial 5),0.009140
HashTable,random,find (trial 5),0.000081 HashTable,random,find (trial 5),0.000083
HashTable,random,delete (trial 5),0.000046 HashTable,random,delete (trial 5),0.000044
HashTable,random,Insert (avg),0.009881 HashTable,random,Insert (avg),0.009507
HashTable,random,Find (avg),0.000084 HashTable,random,Find (avg),0.000083
HashTable,random,Delete (avg),0.000048 HashTable,random,Delete (avg),0.000045
HashTable,sorted,insert (trial 1),0.008975 HashTable,sorted,insert (trial 1),0.009291
HashTable,sorted,find (trial 1),0.000087 HashTable,sorted,find (trial 1),0.000087
HashTable,sorted,delete (trial 1),0.000050 HashTable,sorted,delete (trial 1),0.000047
HashTable,sorted,insert (trial 2),0.009137 HashTable,sorted,insert (trial 2),0.009102
HashTable,sorted,find (trial 2),0.000086 HashTable,sorted,find (trial 2),0.000100
HashTable,sorted,delete (trial 2),0.000050 HashTable,sorted,delete (trial 2),0.000090
HashTable,sorted,insert (trial 3),0.009460 HashTable,sorted,insert (trial 3),0.009200
HashTable,sorted,find (trial 3),0.000086 HashTable,sorted,find (trial 3),0.000087
HashTable,sorted,delete (trial 3),0.000049 HashTable,sorted,delete (trial 3),0.000048
HashTable,sorted,insert (trial 4),0.008977 HashTable,sorted,insert (trial 4),0.009909
HashTable,sorted,find (trial 4),0.000085 HashTable,sorted,find (trial 4),0.000089
HashTable,sorted,delete (trial 4),0.000049 HashTable,sorted,delete (trial 4),0.000049
HashTable,sorted,insert (trial 5),0.009416 HashTable,sorted,insert (trial 5),0.009171
HashTable,sorted,find (trial 5),0.000094 HashTable,sorted,find (trial 5),0.000088
HashTable,sorted,delete (trial 5),0.000053 HashTable,sorted,delete (trial 5),0.000049
HashTable,sorted,Insert (avg),0.009193 HashTable,sorted,Insert (avg),0.009335
HashTable,sorted,Find (avg),0.000087 HashTable,sorted,Find (avg),0.000090
HashTable,sorted,Delete (avg),0.000050 HashTable,sorted,Delete (avg),0.000057
BST,random,insert (trial 1),0.031499 BST,random,insert (trial 1),0.034288
BST,random,find (trial 1),0.000274 BST,random,find (trial 1),0.000271
BST,random,delete (trial 1),0.000153 BST,random,delete (trial 1),0.000156
BST,random,insert (trial 2),0.031806 BST,random,insert (trial 2),0.032324
BST,random,find (trial 2),0.000286 BST,random,find (trial 2),0.000272
BST,random,delete (trial 2),0.000157 BST,random,delete (trial 2),0.000154
BST,random,insert (trial 3),0.031514 BST,random,insert (trial 3),0.101986
BST,random,find (trial 3),0.000267 BST,random,find (trial 3),0.000264
BST,random,delete (trial 3),0.000150 BST,random,delete (trial 3),0.000151
BST,random,insert (trial 4),0.031758 BST,random,insert (trial 4),0.031992
BST,random,find (trial 4),0.000260 BST,random,find (trial 4),0.000265
BST,random,delete (trial 4),0.000144 BST,random,delete (trial 4),0.000151
BST,random,insert (trial 5),0.031923 BST,random,insert (trial 5),0.032047
BST,random,find (trial 5),0.000262 BST,random,find (trial 5),0.000261
BST,random,delete (trial 5),0.000145 BST,random,delete (trial 5),0.000150
BST,random,Insert (avg),0.031700 BST,random,Insert (avg),0.046528
BST,random,Find (avg),0.000270 BST,random,Find (avg),0.000266
BST,random,Delete (avg),0.000150 BST,random,Delete (avg),0.000152
BST,sorted,insert (trial 1),14.135551 BST,sorted,insert (trial 1),12.604559
BST,sorted,find (trial 1),0.123919 BST,sorted,find (trial 1),0.105486
BST,sorted,delete (trial 1),0.054104 BST,sorted,delete (trial 1),0.052166
BST,sorted,insert (trial 2),13.781539 BST,sorted,insert (trial 2),12.359827
BST,sorted,find (trial 2),0.126835 BST,sorted,find (trial 2),0.116147
BST,sorted,delete (trial 2),0.055120 BST,sorted,delete (trial 2),0.057597
BST,sorted,insert (trial 3),15.010563 BST,sorted,insert (trial 3),12.470136
BST,sorted,find (trial 3),0.117841 BST,sorted,find (trial 3),0.109819
BST,sorted,delete (trial 3),0.056871 BST,sorted,delete (trial 3),0.052912
BST,sorted,insert (trial 4),14.378650 BST,sorted,insert (trial 4),12.437366
BST,sorted,find (trial 4),0.113316 BST,sorted,find (trial 4),0.104483
BST,sorted,delete (trial 4),0.054129 BST,sorted,delete (trial 4),0.051517
BST,sorted,insert (trial 5),14.285981 BST,sorted,insert (trial 5),12.580773
BST,sorted,find (trial 5),0.112919 BST,sorted,find (trial 5),0.109896
BST,sorted,delete (trial 5),0.057369 BST,sorted,delete (trial 5),0.056510
BST,sorted,Insert (avg),14.318457 BST,sorted,Insert (avg),12.490532
BST,sorted,Find (avg),0.118966 BST,sorted,Find (avg),0.109166
BST,sorted,Delete (avg),0.055519 BST,sorted,Delete (avg),0.054140

1 Structure Mode Operation Time (sec)
2 LinkedList random insert (trial 1) 3.415125 3.492299
3 LinkedList random find (trial 1) 0.035397 0.037285
4 LinkedList random delete (trial 1) 0.017692 0.017788
5 LinkedList random insert (trial 2) 3.534952 3.626929
6 LinkedList random find (trial 2) 0.038819 0.037489
7 LinkedList random delete (trial 2) 0.021675 0.017875
8 LinkedList random insert (trial 3) 3.493529 3.520048
9 LinkedList random find (trial 3) 0.036592 0.038240
10 LinkedList random delete (trial 3) 0.018221 0.017604
11 LinkedList random insert (trial 4) 3.340745 3.506699
12 LinkedList random find (trial 4) 0.036098 0.038922
13 LinkedList random delete (trial 4) 0.017576 0.018784
14 LinkedList random insert (trial 5) 3.369741 3.556780
15 LinkedList random find (trial 5) 0.035302 0.038981
16 LinkedList random delete (trial 5) 0.017674 0.018246
17 LinkedList random Insert (avg) 3.430818 3.540551
18 LinkedList random Find (avg) 0.036442 0.038183
19 LinkedList random Delete (avg) 0.018568 0.018059
20 LinkedList sorted insert (trial 1) 3.118200 3.346370
21 LinkedList sorted find (trial 1) 0.037116 0.040201
22 LinkedList sorted delete (trial 1) 0.019387 0.020495
23 LinkedList sorted insert (trial 2) 3.338498 3.314037
24 LinkedList sorted find (trial 2) 0.036500 0.038854
25 LinkedList sorted delete (trial 2) 0.019001 0.019935
26 LinkedList sorted insert (trial 3) 3.136906 3.354769
27 LinkedList sorted find (trial 3) 0.037498 0.039805
28 LinkedList sorted delete (trial 3) 0.019219 0.020464
29 LinkedList sorted insert (trial 4) 3.253578 3.406509
30 LinkedList sorted find (trial 4) 0.036434 0.039368
31 LinkedList sorted delete (trial 4) 0.019333 0.020180
32 LinkedList sorted insert (trial 5) 3.207896 3.403112
33 LinkedList sorted find (trial 5) 0.038585 0.039473
34 LinkedList sorted delete (trial 5) 0.020473 0.020447
35 LinkedList sorted Insert (avg) 3.211016 3.364960
36 LinkedList sorted Find (avg) 0.037227 0.039540
37 LinkedList sorted Delete (avg) 0.019482 0.020304
38 HashTable random insert (trial 1) 0.010124 0.009849
39 HashTable random find (trial 1) 0.000093 0.000086
40 HashTable random delete (trial 1) 0.000052 0.000048
41 HashTable random insert (trial 2) 0.010397 0.009472
42 HashTable random find (trial 2) 0.000086 0.000083
43 HashTable random delete (trial 2) 0.000048 0.000044
44 HashTable random insert (trial 3) 0.009352 0.009662
45 HashTable random find (trial 3) 0.000081 0.000082
46 HashTable random delete (trial 3) 0.000046 0.000044
47 HashTable random insert (trial 4) 0.009326 0.009410
48 HashTable random find (trial 4) 0.000080 0.000082
49 HashTable random delete (trial 4) 0.000046 0.000044
50 HashTable random insert (trial 5) 0.010205 0.009140
51 HashTable random find (trial 5) 0.000081 0.000083
52 HashTable random delete (trial 5) 0.000046 0.000044
53 HashTable random Insert (avg) 0.009881 0.009507
54 HashTable random Find (avg) 0.000084 0.000083
55 HashTable random Delete (avg) 0.000048 0.000045
56 HashTable sorted insert (trial 1) 0.008975 0.009291
57 HashTable sorted find (trial 1) 0.000087
58 HashTable sorted delete (trial 1) 0.000050 0.000047
59 HashTable sorted insert (trial 2) 0.009137 0.009102
60 HashTable sorted find (trial 2) 0.000086 0.000100
61 HashTable sorted delete (trial 2) 0.000050 0.000090
62 HashTable sorted insert (trial 3) 0.009460 0.009200
63 HashTable sorted find (trial 3) 0.000086 0.000087
64 HashTable sorted delete (trial 3) 0.000049 0.000048
65 HashTable sorted insert (trial 4) 0.008977 0.009909
66 HashTable sorted find (trial 4) 0.000085 0.000089
67 HashTable sorted delete (trial 4) 0.000049
68 HashTable sorted insert (trial 5) 0.009416 0.009171
69 HashTable sorted find (trial 5) 0.000094 0.000088
70 HashTable sorted delete (trial 5) 0.000053 0.000049
71 HashTable sorted Insert (avg) 0.009193 0.009335
72 HashTable sorted Find (avg) 0.000087 0.000090
73 HashTable sorted Delete (avg) 0.000050 0.000057
74 BST random insert (trial 1) 0.031499 0.034288
75 BST random find (trial 1) 0.000274 0.000271
76 BST random delete (trial 1) 0.000153 0.000156
77 BST random insert (trial 2) 0.031806 0.032324
78 BST random find (trial 2) 0.000286 0.000272
79 BST random delete (trial 2) 0.000157 0.000154
80 BST random insert (trial 3) 0.031514 0.101986
81 BST random find (trial 3) 0.000267 0.000264
82 BST random delete (trial 3) 0.000150 0.000151
83 BST random insert (trial 4) 0.031758 0.031992
84 BST random find (trial 4) 0.000260 0.000265
85 BST random delete (trial 4) 0.000144 0.000151
86 BST random insert (trial 5) 0.031923 0.032047
87 BST random find (trial 5) 0.000262 0.000261
88 BST random delete (trial 5) 0.000145 0.000150
89 BST random Insert (avg) 0.031700 0.046528
90 BST random Find (avg) 0.000270 0.000266
91 BST random Delete (avg) 0.000150 0.000152
92 BST sorted insert (trial 1) 14.135551 12.604559
93 BST sorted find (trial 1) 0.123919 0.105486
94 BST sorted delete (trial 1) 0.054104 0.052166
95 BST sorted insert (trial 2) 13.781539 12.359827
96 BST sorted find (trial 2) 0.126835 0.116147
97 BST sorted delete (trial 2) 0.055120 0.057597
98 BST sorted insert (trial 3) 15.010563 12.470136
99 BST sorted find (trial 3) 0.117841 0.109819
100 BST sorted delete (trial 3) 0.056871 0.052912
101 BST sorted insert (trial 4) 14.378650 12.437366
102 BST sorted find (trial 4) 0.113316 0.104483
103 BST sorted delete (trial 4) 0.054129 0.051517
104 BST sorted insert (trial 5) 14.285981 12.580773
105 BST sorted find (trial 5) 0.112919 0.109896
106 BST sorted delete (trial 5) 0.057369 0.056510
107 BST sorted Insert (avg) 14.318457 12.490532
108 BST sorted Find (avg) 0.118966 0.109166
109 BST sorted Delete (avg) 0.055519 0.054140

Binary file not shown.

View File

@ -11,7 +11,6 @@ threading.stack_size(64*1024*1024)
def ll_insert(head, name, phone): def ll_insert(head, name, phone):
"""Добавляет запись или обновляет телефон, если имя уже существует. Возвращает новую голову списка."""
current = head current = head
while current is not None: while current is not None:
if current["name"] == name: if current["name"] == name:
@ -23,7 +22,6 @@ def ll_insert(head, name, phone):
return fresh_node return fresh_node
def ll_find(head, name): def ll_find(head, name):
"""Ищет узел по имени. Возвращает телефон или None."""
current = head current = head
while current is not None: while current is not None:
if current["name"] == name: if current["name"] == name:
@ -32,7 +30,6 @@ def ll_find(head, name):
return None return None
def ll_delete(head, name): def ll_delete(head, name):
"""Удаляет узел по имени. Возвращает новую голову списка."""
current = head current = head
previous = None previous = None
@ -49,7 +46,6 @@ def ll_delete(head, name):
return head return head
def ll_list_all(head): def ll_list_all(head):
"""Собирает все записи в список и сортирует их по имени."""
entries = [] entries = []
current = head current = head
while current is not None: while current is not None:
@ -60,26 +56,21 @@ def ll_list_all(head):
def ht_create(size=1000): def ht_create(size=1000):
"""Создает пустую хеш-таблицу заданного размера."""
return [None] * size return [None] * size
def ht_insert(buckets, name, phone): def ht_insert(buckets, name, phone):
"""Вычисляет индекс бакета и вызывает ll_insert."""
bucket_idx = abs(hash(name)) % len(buckets) bucket_idx = abs(hash(name)) % len(buckets)
buckets[bucket_idx] = ll_insert(buckets[bucket_idx], name, phone) buckets[bucket_idx] = ll_insert(buckets[bucket_idx], name, phone)
def ht_find(buckets, name): def ht_find(buckets, name):
"""Вычисляет индекс бакета и вызывает ll_find."""
bucket_idx = abs(hash(name)) % len(buckets) bucket_idx = abs(hash(name)) % len(buckets)
return ll_find(buckets[bucket_idx], name) return ll_find(buckets[bucket_idx], name)
def ht_delete(buckets, name): def ht_delete(buckets, name):
"""Вычисляет индекс бакета и вызывает ll_delete."""
bucket_idx = abs(hash(name)) % len(buckets) bucket_idx = abs(hash(name)) % len(buckets)
buckets[bucket_idx] = ll_delete(buckets[bucket_idx], name) buckets[bucket_idx] = ll_delete(buckets[bucket_idx], name)
def ht_list_all(buckets): def ht_list_all(buckets):
"""Собирает записи из всех бакетов и сортирует их по имени."""
entries = [] entries = []
for head_node in buckets: for head_node in buckets:
current = head_node current = head_node
@ -91,7 +82,6 @@ def ht_list_all(buckets):
def bst_insert(root, name, phone): def bst_insert(root, name, phone):
"""Рекурсивно вставляет узел или обновляет телефон."""
if root is None: if root is None:
return {"name": name, "phone": phone, "left": None, "right": None} return {"name": name, "phone": phone, "left": None, "right": None}
@ -105,7 +95,6 @@ def bst_insert(root, name, phone):
return root return root
def bst_find(root, name): def bst_find(root, name):
"""Рекурсивный поиск по дереву."""
if root is None: if root is None:
return None return None
@ -117,7 +106,6 @@ def bst_find(root, name):
return bst_find(root["right"], name) return bst_find(root["right"], name)
def bst_delete(root, name): def bst_delete(root, name):
"""Рекурсивное удаление узла из BST."""
if root is None: if root is None:
return None return None
@ -142,7 +130,6 @@ def bst_delete(root, name):
return root return root
def bst_list_all(root): def bst_list_all(root):
"""Центрированный обход дерева для сбора записей."""
entries = [] entries = []
def _inorder(node): def _inorder(node):
if node is not None: if node is not None:
@ -179,7 +166,7 @@ def perform_benchmark():
elif structure_kind == "HashTable": container = ht_create(size=1000) elif structure_kind == "HashTable": container = ht_create(size=1000)
elif structure_kind == "BST": container = None elif structure_kind == "BST": container = None
# А. Вставка #Вставка
timer_start = time.perf_counter() timer_start = time.perf_counter()
if structure_kind == "LinkedList": if structure_kind == "LinkedList":
for name, phone in data_collection: container = ll_insert(container, name, phone) for name, phone in data_collection: container = ll_insert(container, name, phone)
@ -191,7 +178,7 @@ def perform_benchmark():
insertion_measurements.append(insert_elapsed) insertion_measurements.append(insert_elapsed)
output_rows.append([structure_kind, data_mode, f"insert (trial {trial_num})", f"{insert_elapsed:.6f}"]) output_rows.append([structure_kind, data_mode, f"insert (trial {trial_num})", f"{insert_elapsed:.6f}"])
# Б. Поиск #Поиск
timer_start = time.perf_counter() timer_start = time.perf_counter()
if structure_kind == "LinkedList": if structure_kind == "LinkedList":
for name in search_queries: ll_find(container, name) for name in search_queries: ll_find(container, name)
@ -203,7 +190,7 @@ def perform_benchmark():
search_measurements.append(search_elapsed) search_measurements.append(search_elapsed)
output_rows.append([structure_kind, data_mode, f"find (trial {trial_num})", f"{search_elapsed:.6f}"]) output_rows.append([structure_kind, data_mode, f"find (trial {trial_num})", f"{search_elapsed:.6f}"])
# В. Удаление #Удаление
timer_start = time.perf_counter() timer_start = time.perf_counter()
if structure_kind == "LinkedList": if structure_kind == "LinkedList":
for name in deletion_targets: container = ll_delete(container, name) for name in deletion_targets: container = ll_delete(container, name)
@ -234,23 +221,17 @@ def perform_benchmark():
execute_trial("BST", "random", shuffled_records) execute_trial("BST", "random", shuffled_records)
execute_trial("BST", "sorted", ordered_records) execute_trial("BST", "sorted", ordered_records)
# Сохранение в CSV
with open("benchmark_output.csv", "w", newline="", encoding="utf-8") as csv_file: with open("benchmark_output.csv", "w", newline="", encoding="utf-8") as csv_file:
csv_writer = csv.writer(csv_file) csv_writer = csv.writer(csv_file)
csv_writer.writerows(output_rows) csv_writer.writerows(output_rows)
print("\n[Success] All benchmarks completed! Results saved to 'benchmark_output.csv'.") print("\n[Success] All benchmarks completed! Results saved to 'benchmark_output.csv'.")
# ВЫЗЫВАЕМ ФУНКЦИЮ ДЛЯ СОЗДАНИЯ ГРАФИКОВ
generate_performance_charts(graph_entries) generate_performance_charts(graph_entries)
def generate_performance_charts(plot_data): def generate_performance_charts(plot_data):
"""
Создает графики производительности структур данных.
Args:
plot_data: список кортежей (structure, mode, avg_insert, avg_find, avg_delete)
"""
if not plot_data: if not plot_data:
print("Нет данных для построения графиков") print("Нет данных для построения графиков")
return return
@ -307,6 +288,5 @@ if __name__ == '__main__':
benchmark_thread.start() benchmark_thread.start()
benchmark_thread.join() benchmark_thread.join()
# Дополнительно: если графики не показались автоматически
# Можно вызвать функцию напрямую после завершения потока
print("\nПрограмма завершена. Проверьте файл 'performance_charts.png'") print("\nПрограмма завершена. Проверьте файл 'performance_charts.png'")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

2278329
ivankinad/task2/Report2.rtf Normal file

File diff suppressed because it is too large Load Diff

484
ivankinad/task2/laba2.py Normal file
View File

@ -0,0 +1,484 @@
import time
import csv
from abc import ABC, abstractmethod
from collections import deque
from typing import List, Dict, Optional, Tuple
import heapq
#Модель лабиринта
class Cell:
def __init__(self, x: int, y: int):
self.x = x
self.y = y
self.is_wall = False
self.is_start = False
self.is_exit = False
self.weight = 1
def is_passable(self) -> bool:
return not self.is_wall
def __lt__(self, other):
return (self.x, self.y) < (other.x, other.y)
def __repr__(self):
return f"Cell({self.x}, {self.y})"
class Maze:
def __init__(self, width: int, height: int):
self.width = width
self.height = height
self.cells = [[Cell(x, y) for y in range(height)] for x in range(width)]
self.start: Optional[Cell] = None
self.exit: Optional[Cell] = None
def get_cell(self, x: int, y: int) -> Optional[Cell]:
if 0 <= x < self.width and 0 <= y < self.height:
return self.cells[x][y]
return None
def get_neighbors(self, cell: Cell) -> List[Cell]:
neighbors = []
directions = [(0, -1), (0, 1), (-1, 0), (1, 0)]
for dx, dy in directions:
nx, ny = cell.x + dx, cell.y + dy
neighbor = self.get_cell(nx, ny)
if neighbor and neighbor.is_passable():
neighbors.append(neighbor)
return neighbors
#Постройка лабиринта
class MazeBuilder(ABC):
@abstractmethod
def build_from_string_list(self, lines: List[str]) -> Maze:
pass
class TextMazeBuilder(MazeBuilder):
def build_from_string_list(self, lines: List[str]) -> Maze:
height = len(lines)
width = len(lines[0]) if height > 0 else 0
maze = Maze(width, height)
for y, line in enumerate(lines):
for x, char in enumerate(line):
cell = maze.get_cell(x, y)
if char == '#':
cell.is_wall = True
elif char == 'S':
cell.is_start = True
maze.start = cell
elif char == 'E':
cell.is_exit = True
maze.exit = cell
elif char == 'W':
cell.weight = 3
elif char == 'D':
cell.weight = 2
return maze
#Стратегии поиска пути
class PathFindingStrategy(ABC):
def __init__(self):
self.visited_count = 0
@abstractmethod
def find_path(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]:
pass
def _reconstruct_path(self, came_from: Dict, start: Cell, exit: Cell) -> List[Cell]:
if exit not in came_from:
return []
path = []
current = exit
while current != start:
path.append(current)
current = came_from[current]
path.append(start)
path.reverse()
return path
class BFSStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]:
self.visited_count = 0
queue = deque([start])
came_from = {start: None}
while queue:
current = queue.popleft()
self.visited_count += 1
if current == exit:
break
for neighbor in maze.get_neighbors(current):
if neighbor not in came_from:
queue.append(neighbor)
came_from[neighbor] = current
return self._reconstruct_path(came_from, start, exit)
class DFSStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]:
self.visited_count = 0
stack = [start]
came_from = {start: None}
while stack:
current = stack.pop()
self.visited_count += 1
if current == exit:
break
for neighbor in maze.get_neighbors(current):
if neighbor not in came_from:
stack.append(neighbor)
came_from[neighbor] = current
return self._reconstruct_path(came_from, start, exit)
class AStarStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]:
self.visited_count = 0
def heuristic(a: Cell, b: Cell) -> int:
return abs(a.x - b.x) + abs(a.y - b.y)
priority_queue = []
heapq.heappush(priority_queue, (0, start))
came_from = {start: None}
g_score = {start: 0}
while priority_queue:
_, current = heapq.heappop(priority_queue)
self.visited_count += 1
if current == exit:
break
for neighbor in maze.get_neighbors(current):
tentative_g_score = g_score[current] + neighbor.weight
if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g_score
f_score = tentative_g_score + heuristic(neighbor, exit)
heapq.heappush(priority_queue, (f_score, neighbor))
return self._reconstruct_path(came_from, start, exit)
class DijkstraStrategy(PathFindingStrategy):
def find_path(self, maze: Maze, start: Cell, exit: Cell) -> List[Cell]:
self.visited_count = 0
priority_queue = []
heapq.heappush(priority_queue, (0, start))
came_from = {start: None}
g_score = {start: 0}
while priority_queue:
current_g, current = heapq.heappop(priority_queue)
self.visited_count += 1
if current == exit:
break
for neighbor in maze.get_neighbors(current):
tentative_g_score = g_score[current] + neighbor.weight
if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g_score
heapq.heappush(priority_queue, (tentative_g_score, neighbor))
return self._reconstruct_path(came_from, start, exit)
#Оркестратор поиска
class SearchStats:
def __init__(self, time_ms: float, visited_cells: int, path_length: int):
self.time_ms = time_ms
self.visited_cells = visited_cells
self.path_length = path_length
def __str__(self):
return f"Time: {self.time_ms:.3f}ms | Visited: {self.visited_cells} | Path length: {self.path_length}"
class Observer(ABC):
@abstractmethod
def update(self, event: str):
pass
class MazeSolver:
def __init__(self, maze: Maze, strategy: PathFindingStrategy):
self.maze = maze
self.strategy = strategy
self.observers = []
def set_strategy(self, strategy: PathFindingStrategy):
self.strategy = strategy
def add_observer(self, observer: Observer):
self.observers.append(observer)
def _notify(self, event: str):
for observer in self.observers:
observer.update(event)
def solve(self) -> Tuple[List[Cell], SearchStats]:
self._notify("Search started")
start_time = time.perf_counter()
path = self.strategy.find_path(self.maze, self.maze.start, self.maze.exit)
end_time = time.perf_counter()
time_ms = (end_time - start_time) * 1000
stats = SearchStats(time_ms, self.strategy.visited_count, len(path))
self._notify("Search completed")
return path, stats
#Визуализация
class ConsoleView(Observer):
def update(self, event: str):
print(f"[Event] {event}")
def render(self, maze: Maze, path: List[Cell]):
path_set = set(path)
for y in range(maze.height):
row = ""
for x in range(maze.width):
cell = maze.get_cell(x, y)
if cell == maze.start:
row += "S"
elif cell == maze.exit:
row += "E"
elif cell in path_set:
row += "*"
elif cell.is_wall:
row += "#"
elif cell.weight == 3:
row += "W" # Болото
elif cell.weight == 2:
row += "D" # Песок
else:
row += "."
print(row)
#Экспериментальная часть
def create_test_mazes() -> Dict[str, Maze]:
builder = TextMazeBuilder()
mazes = {}
#Маленький лабиринт 10x10 с простым путём
small_maze = [
"S.........",
"#####.####",
"..........",
"####.#####",
"..........",
"#.#######.",
"..........",
"######.###",
"..........",
".........E"
]
mazes["Small (10x10)"] = builder.build_from_string_list(small_maze)
#Пустой лабиринт 50x50
empty_maze = ["." * 50 for _ in range(50)]
empty_maze[0] = "S" + empty_maze[0][1:]
empty_maze[-1] = empty_maze[-1][:-1] + "E"
mazes["Empty (50x50)"] = builder.build_from_string_list(empty_maze)
#Средний лабиринт 50x50 с тупиками
medium_maze = []
for y in range(50):
if y == 0:
row = "S" + "." * 49
elif y == 49:
row = "." * 49 + "E"
elif y % 2 == 1:
row = "#" * 45 + "." * 5 if y % 4 == 1 else "." * 5 + "#" * 45
else:
row = "." * 50
medium_maze.append(row)
mazes["Medium with dead ends (50x50)"] = builder.build_from_string_list(medium_maze)
# Большой лабиринт 100x100
large_maze = []
for y in range(100):
if y == 0:
row = "S" + "." * 99
elif y == 99:
row = "." * 99 + "E"
elif y % 2 == 1:
row = ("#" * 9 + ".") * 10
else:
row = "." * 100
large_maze.append(row)
mazes["Large (100x100)"] = builder.build_from_string_list(large_maze)
# Лабиринт без выхода
no_exit_maze = [
"S....#....",
"##########",
"##########",
"##########",
"##########",
"##########",
"##########",
"##########",
"##########",
"######...E"
]
mazes["No exit (10x10)"] = builder.build_from_string_list(no_exit_maze)
return mazes
def run_experiments() -> None:
mazes = create_test_mazes()
strategies = {
"BFS": BFSStrategy(),
"DFS": DFSStrategy(),
"A*": AStarStrategy(),
"Dijkstra": DijkstraStrategy()
}
results = []
print("=" * 80)
print("ЗАПУСК ЭКСПЕРИМЕНТОВ ПО СРАВНЕНИЮ АЛГОРИТМОВ ПОИСКА ПУТИ")
print("=" * 80)
for maze_name, maze in mazes.items():
print(f"\nТестирование: {maze_name}")
print("-" * 60)
for strategy_name, strategy in strategies.items():
solver = MazeSolver(maze, strategy)
runs = 5
total_time = 0
path = []
stats = None
for _ in range(runs):
path, stats = solver.solve()
total_time += stats.time_ms
avg_time = total_time / runs
results.append([
maze_name,
strategy_name,
f"{avg_time:.4f}",
stats.visited_cells,
stats.path_length
])
print(f" {strategy_name:10} -> "
f"Время: {avg_time:8.3f}мс | "
f"Посещено: {stats.visited_cells:5} | "
f"Длина пути: {stats.path_length:3}")
with open("results_all.csv", "w", newline="", encoding="utf-8") as csvfile:
writer = csv.writer(csvfile)
writer.writerow(["Лабиринт", "Стратегия", "Время (мс)",
"Посещено клеток", "Длина пути"])
writer.writerows(results)
print("\n" + "=" * 80)
print("Все эксперименты завершены!")
print("Результаты сохранены в файл 'results_all.csv'")
print("=" * 80)
def demonstrate_visualization() -> None:
"""Демонстрация визуализации и паттерна Observer."""
builder = TextMazeBuilder()
maze_data = [
"S...#.....",
".###.####.",
".....#....",
"####.#####",
".....#....",
".#######..",
"..........",
"######.###",
"..........",
".........E"
]
maze = builder.build_from_string_list(maze_data)
strategy = AStarStrategy()
solver = MazeSolver(maze, strategy)
console_view = ConsoleView()
solver.add_observer(console_view)
print("\nДЕМОНСТРАЦИЯ ВИЗУАЛИЗАЦИИ")
print("=" * 40)
path, stats = solver.solve()
print("\nНайденный путь:")
console_view.render(maze, path)
print(f"\nСтатистика: {stats}")
print(f" Время: {stats.time_ms:.3f}мс")
print(f" Посещено клеток: {stats.visited_cells}")
print(f" Длина пути: {stats.path_length}")
if __name__ == "__main__":
demonstrate_visualization()
run_experiments()

View File

@ -0,0 +1,21 @@
Лабиринт,Стратегия,Время (мс),Посещено клеток,Длина пути
Small (10x10),BFS,0.1173,59,27
Small (10x10),DFS,0.0961,49,27
Small (10x10),A*,0.1480,50,27
Small (10x10),Dijkstra,0.1623,60,27
Empty (50x50),BFS,5.1892,2500,99
Empty (50x50),DFS,3.1591,1275,1275
Empty (50x50),A*,13.0123,2500,99
Empty (50x50),Dijkstra,10.5962,2500,99
Medium with dead ends (50x50),BFS,3.3357,1420,1083
Medium with dead ends (50x50),DFS,2.9541,1275,1275
Medium with dead ends (50x50),A*,4.8367,1404,1083
Medium with dead ends (50x50),Dijkstra,3.9227,1420,1083
Large (100x100),BFS,10.6456,5590,199
Large (100x100),DFS,10.8020,4933,4519
Large (100x100),A*,28.2500,5140,199
Large (100x100),Dijkstra,24.3427,5590,199
No exit (10x10),BFS,0.0105,5,0
No exit (10x10),DFS,0.0090,5,0
No exit (10x10),A*,0.0116,5,0
No exit (10x10),Dijkstra,0.0100,5,0
1 Лабиринт Стратегия Время (мс) Посещено клеток Длина пути
2 Small (10x10) BFS 0.1173 59 27
3 Small (10x10) DFS 0.0961 49 27
4 Small (10x10) A* 0.1480 50 27
5 Small (10x10) Dijkstra 0.1623 60 27
6 Empty (50x50) BFS 5.1892 2500 99
7 Empty (50x50) DFS 3.1591 1275 1275
8 Empty (50x50) A* 13.0123 2500 99
9 Empty (50x50) Dijkstra 10.5962 2500 99
10 Medium with dead ends (50x50) BFS 3.3357 1420 1083
11 Medium with dead ends (50x50) DFS 2.9541 1275 1275
12 Medium with dead ends (50x50) A* 4.8367 1404 1083
13 Medium with dead ends (50x50) Dijkstra 3.9227 1420 1083
14 Large (100x100) BFS 10.6456 5590 199
15 Large (100x100) DFS 10.8020 4933 4519
16 Large (100x100) A* 28.2500 5140 199
17 Large (100x100) Dijkstra 24.3427 5590 199
18 No exit (10x10) BFS 0.0105 5 0
19 No exit (10x10) DFS 0.0090 5 0
20 No exit (10x10) A* 0.0116 5 0
21 No exit (10x10) Dijkstra 0.0100 5 0