[13] Final. All is complete

This commit is contained in:
shapovalovka 2026-05-25 11:58:51 +03:00
parent 83e323fff6
commit 41004bcb8a
31 changed files with 1918 additions and 0 deletions

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,48 @@
import csv
import matplotlib.pyplot as plt
array_arr = []
array_list = []
array_hash = []
array_bin = []
with open('results.csv', 'r', encoding='utf-8-sig') as file:
reader = csv.reader(file, delimiter=';')
next(reader) # пропускаем заголовок
values = []
for row in reader:
values.append(float(row[3]))
array_arr = values[0:4]
array_list = values[4:8]
array_hash = values[8:12]
array_bin = values[12:16]
print(f"array_arr : {array_arr}")
print(f"array_list: {array_list}")
print(f"array_hash: {array_hash}")
print(f"array_bin : {array_bin}")
l = [1, 2, 3, 4]
#визуализация без дерева
plt.plot(l, array_arr, label = 'Array', c='black')
plt.plot(l, array_list, label = 'Linked list', c='blue')
plt.plot(l, array_hash, label = 'Hash table', c='orange')
plt.ylabel('array') #название по y
plt.xlabel('l') #название по x
plt.legend(loc='upper center', bbox_to_anchor=(0.5, 1.15), ncol = 3)
plt.savefig('t1p1.png', dpi=300, bbox_inches='tight') #сохранение в файле
plt.show()
#визуализация с деревом
plt.plot(l, array_arr, label = 'Array', c='black')
plt.plot(l, array_list, label = 'Linked list', c='blue')
plt.plot(l, array_hash, label = 'Hash table', c='orange')
plt.plot(l, array_bin, label = 'Binary tree', c='red')
plt.ylabel('array') #название по y
plt.xlabel('l') #название по x
plt.legend(loc='upper center', bbox_to_anchor=(0.5, 1.15), ncol = 4)
plt.savefig('t1p2.png', dpi=300, bbox_inches='tight') #сохранение в файле
plt.show()

View File

@ -0,0 +1,9 @@
Структура;Режим;Операция;Время (сек)
Array;случайный;вставка (в начало);0.06431880006566644
Array;отсортированный;вставка (в начало);0.06380272014066576
Array;любой;поиск 110 записей;0.07721293987706304
Array;любой;удаление 50 записей (среднее);0.0018548803813755513
Linked list;случайный;вставка (в начало);0.01246960014104843
Linked list;отсортированный;вставка (в начало);0.007890580128878355
Linked list;любой;поиск 110 записей;0.23582311999052763
Linked list;любой;удаление 50 записей (среднее);0.0023578427862375973
1 Структура Режим Операция Время (сек)
2 Array случайный вставка (в начало) 0.06431880006566644
3 Array отсортированный вставка (в начало) 0.06380272014066576
4 Array любой поиск 110 записей 0.07721293987706304
5 Array любой удаление 50 записей (среднее) 0.0018548803813755513
6 Linked list случайный вставка (в начало) 0.01246960014104843
7 Linked list отсортированный вставка (в начало) 0.007890580128878355
8 Linked list любой поиск 110 записей 0.23582311999052763
9 Linked list любой удаление 50 записей (среднее) 0.0023578427862375973

View File

@ -0,0 +1,212 @@
import random
import time
import csv
# ---------- Реализация связного списка ----------
def ll_insert_begin(head, name, phone):
# Вставка узла в начало списка. Возвращает новую голову.
new_node = {'name': name, 'phone': phone, 'next': head}
return new_node
def ll_find(head, name):
# Поиск телефона по имени. Возвращает phone или None.
current = head
while current:
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']:
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:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return records
# ---------- Измерения для массива ----------
def array_insert_measure(records, sorted_flag=False):
# Вставка записей в начало массива. Возвращает время.
arr = []
start = time.perf_counter()
if sorted_flag:
# records уже отсортированы
for item in records:
arr.insert(0, item)
else:
for item in records:
arr.insert(0, item)
end = time.perf_counter()
return end - start
def array_find_measure(records, test_names):
# Поиск в массиве: линейный перебор.
start = time.perf_counter()
for name in test_names:
for rec in records:
if rec[0] == name:
break
end = time.perf_counter()
return end - start
def array_delete_measure(records, delete_names):
# Удаление из массива через создание нового списка (как в оригинале).
times = []
for name in delete_names:
start = time.perf_counter()
records = [rec for rec in records if rec[0] != name]
end = time.perf_counter()
times.append(end - start)
return sum(times) / len(times) if times else 0
# ---------- Измерения для связного списка ----------
def linked_insert_measure(records, sorted_flag=False):
# Вставка записей в начало связного списка. Возвращает время.
head = None
start = time.perf_counter()
# Если sorted_flag == True, records уже отсортированы, но для связного списка
# вставка в начало всегда O(1), порядок не влияет на время.
for name, phone in records:
head = ll_insert_begin(head, name, phone)
end = time.perf_counter()
return end - start
def linked_find_measure(head, test_names):
# Поиск в связном списке.
start = time.perf_counter()
for name in test_names:
ll_find(head, name)
end = time.perf_counter()
return end - start
def linked_delete_measure(head, delete_names):
# Удаление из связного списка.
times = []
for name in delete_names:
start = time.perf_counter()
head = ll_delete(head, name)
end = time.perf_counter()
times.append(end - start)
return sum(times) / len(times) if times else 0
# ---------- Основная функция эксперимента ----------
def main():
N = 10000
# Генерация тестовых данных
records = []
for i in range(N):
name = f"User_{i:05d}"
phone = f"8{random.randint(9000000000, 9999999999)}"
records.append((name, phone))
records_shuffled = records.copy()
random.shuffle(records_shuffled)
records_sorted = sorted(records, key=lambda x: x[0])
# Имена для поиска (100 существующих + 10 несуществующих)
existing_names = random.sample([rec[0] for rec in records], 100)
non_existing = [f"None_{i}" for i in range(10)]
test_names = existing_names + non_existing
# Имена для удаления (50 случайных)
delete_names = random.sample([rec[0] for rec in records], 50)
# Результаты будем собирать в список списков
results = [["Структура", "Режим", "Операция", "Время (сек)"]]
# ----- Массив -----
# Вставка (случайный порядок)
arr_time_shuffled = 0.0
arr_time_sorted = 0.0
for _ in range(5):
arr_time_shuffled += array_insert_measure(records_shuffled, sorted_flag=False)
arr_time_sorted += array_insert_measure(records_sorted, sorted_flag=True)
results.append(["Array", "случайный", "вставка (в начало)", arr_time_shuffled / 5])
results.append(["Array", "отсортированный", "вставка (в начало)", arr_time_sorted / 5])
# Поиск
find_time = 0.0
for _ in range(5):
find_time += array_find_measure(records, test_names)
results.append(["Array", "любой", "поиск 110 записей", find_time / 5])
# Удаление
del_time = 0.0
for _ in range(5):
del_time += array_delete_measure(records.copy(), delete_names)
results.append(["Array", "любой", "удаление 50 записей (среднее)", del_time / 5])
# ----- Связный список -----
# Вставка
ll_time_shuffled = 0.0
ll_time_sorted = 0.0
for _ in range(5):
ll_time_shuffled += linked_insert_measure(records_shuffled)
ll_time_sorted += linked_insert_measure(records_sorted)
results.append(["Linked list", "случайный", "вставка (в начало)", ll_time_shuffled / 5])
results.append(["Linked list", "отсортированный", "вставка (в начало)", ll_time_sorted / 5])
# Поиск (предварительно строим список)
head = None
for name, phone in records:
head = ll_insert_begin(head, name, phone)
find_time_ll = 0.0
for _ in range(5):
find_time_ll += linked_find_measure(head, test_names)
results.append(["Linked list", "любой", "поиск 110 записей", find_time_ll / 5])
# Удаление (копируем список для каждого замера)
del_time_ll = 0.0
for _ in range(5):
# Строим новую копию списка
h = None
for name, phone in records:
h = ll_insert_begin(h, name, phone)
del_time_ll += linked_delete_measure(h, delete_names)
results.append(["Linked list", "любой", "удаление 50 записей (среднее)", del_time_ll / 5])
# ----- Вывод результатов в единый столбец -----
print("\nРезультаты экспериментов (время в секундах):\n")
# Определяем максимальную ширину первого столбца для красивого выравнивания
col_widths = [max(len(str(row[i])) for row in results) for i in range(4)]
for row in results:
print(f"{row[0]:<{col_widths[0]}} {row[1]:<{col_widths[1]}} "
f"{row[2]:<{col_widths[2]}} {row[3]:<{col_widths[3]}}")
# ----- Запись результатов в CSV-файл -----
with open('results.csv', 'w', newline='', encoding='utf-8-sig') as csvfile:
writer = csv.writer(csvfile, delimiter = ';')
writer.writerows(results)
print("\nРезультаты сохранены в файл 'results.csv'.")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,185 @@
import random
import time
import csv
import os
# --------------------- Реализация связного списка (взята из t1_1) ---------------------
def ll_insert_begin(head, name, phone):
# Вставка узла в начало списка. Возвращает новую голову.
new_node = {'name': name, 'phone': phone, 'next': head}
return new_node
def ll_find(head, name):
# Поиск телефона по имени. Возвращает phone или None.
current = head
while current:
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']:
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:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return records
# --------------------- Реализация хеш-таблицы ---------------------
class HashTable:
def __init__(self, size=2000):
self.size = size
self.buckets = [None] * size # каждый bucket — голова связного списка
def _hash(self, name):
# Простая хеш-функция: сумма кодов символов по модулю размера.
return sum(ord(ch) for ch in name) % self.size
def insert(self, name, phone):
index = self._hash(name)
# Вставляем в начало связного списка в данном bucket'е
self.buckets[index] = ll_insert_begin(self.buckets[index], name, phone)
def find(self, name):
index = self._hash(name)
return ll_find(self.buckets[index], name)
def delete(self, name):
index = self._hash(name)
self.buckets[index] = ll_delete(self.buckets[index], name)
def list_all(self):
# Собирает все записи из всех bucket'ов и сортирует по имени.
all_records = []
for head in self.buckets:
current = head
while current:
all_records.append((current['name'], current['phone']))
current = current['next']
all_records.sort(key=lambda x: x[0])
return all_records
# --------------------- Функции измерений ---------------------
def generate_data(N=10000):
records = []
for i in range(N):
name = f"User_{i:05d}"
phone = f"8{random.randint(9000000000, 9999999999)}"
records.append((name, phone))
return records
def measure_insert(records, sort_order='random'):
# Измеряет время вставки в хеш-таблицу.
# sort_order: 'random' или 'sorted' — порядок передаваемых записей.
ht = HashTable(size=2000)
start = time.perf_counter()
for name, phone in records:
ht.insert(name, phone)
end = time.perf_counter()
return end - start
def measure_find(records, test_names):
# Поиск 110 записей в уже заполненной хеш-таблице.
ht = HashTable(size=2000)
for name, phone in records:
ht.insert(name, phone)
start = time.perf_counter()
for name in test_names:
ht.find(name)
end = time.perf_counter()
return end - start
def measure_delete(records, delete_names):
# Удаление 50 записей из хеш-таблицы (среднее время одного удаления).
times = []
for name in delete_names:
ht = HashTable(size=2000)
for n, p in records:
ht.insert(n, p)
start = time.perf_counter()
ht.delete(name)
end = time.perf_counter()
times.append(end - start)
return sum(times) / len(times)
# --------------------- Основная функция ---------------------
def main():
N = 10000
records = generate_data(N)
# Перемешанные и отсортированные копии
records_shuffled = records.copy()
random.shuffle(records_shuffled)
records_sorted = sorted(records, key=lambda x: x[0])
# Имена для поиска (100 существующих + 10 несуществующих)
existing_names = random.sample([rec[0] for rec in records], 100)
non_existing = [f"None_{i}" for i in range(10)]
test_names = existing_names + non_existing
# Имена для удаления (50 случайных)
delete_names = random.sample([rec[0] for rec in records], 50)
# Замеры (по 5 повторений)
insert_shuffled_avg = 0.0
insert_sorted_avg = 0.0
find_avg = 0.0
delete_avg = 0.0
repeats = 5
for _ in range(repeats):
insert_shuffled_avg += measure_insert(records_shuffled, 'random')
insert_sorted_avg += measure_insert(records_sorted, 'sorted')
find_avg += measure_find(records, test_names)
delete_avg += measure_delete(records, delete_names)
insert_shuffled_avg /= repeats
insert_sorted_avg /= repeats
find_avg /= repeats
delete_avg /= repeats
# Подготовка строк для CSV
new_rows = [
["Hash table", "случайный", "вставка (в начало)", insert_shuffled_avg],
["Hash table", "отсортированный", "вставка (в начало)", insert_sorted_avg],
["Hash table", "любой", "поиск 110 записей", find_avg],
["Hash table", "любой", "удаление 50 записей (среднее)", delete_avg]
]
# Определяем имя CSV-файла (там же, где и t1_1.py)
csv_filename = "results.csv"
file_exists = os.path.isfile(csv_filename)
# Запись в CSV (добавление)
with open(csv_filename, 'a', newline='', encoding='utf-8-sig') as f:
writer = csv.writer(f, delimiter=';')
# Если файл только что создан, сначала запишем заголовок
if not file_exists:
writer.writerow(["Структура", "Режим", "Операция", "Время (сек)"])
writer.writerows(new_rows)
print("Результаты для хеш-таблицы добавлены в", csv_filename)
print(f"Среднее время вставки (случ. порядок): {insert_shuffled_avg:.6f} сек")
print(f"Среднее время вставки (отсорт.): {insert_sorted_avg:.6f} сек")
print(f"Среднее время поиска 110 записей: {find_avg:.6f} сек")
print(f"Среднее время удаления 50 записей: {delete_avg:.6f} сек")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,211 @@
import random
import time
import csv
import os
# --------------------- Реализация бинарного дерева поиска (итеративная) ---------------------
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
else:
current = current['left']
elif name > current['name']:
if current['right'] is None:
current['right'] = new_node
break
else:
current = current['right']
else: # имя уже существует — обновляем телефон
current['phone'] = phone
break
return root
def bst_find(root, name):
#Итеративный поиск. Возвращает phone или None.
current = root
while current:
if name == current['name']:
return current['phone']
elif name < current['name']:
current = current['left']
else:
current = current['right']
return None
def bst_find_min(node):
#Возвращает узел с минимальным ключом в поддереве.
while node['left']:
node = node['left']
return node
def bst_delete(root, name):
#Итеративное удаление. Возвращает новый корень.
# Сначала найдём удаляемый узел и его родителя
parent = None
current = root
while current and current['name'] != name:
parent = current
if name < current['name']:
current = current['left']
else:
current = current['right']
if current is None: # узел не найден
return root
# Случай 1: нет левого потомка
if current['left'] is None:
child = current['right']
# Случай 2: нет правого потомка
elif current['right'] is None:
child = current['left']
# Случай 3: два потомка
else:
# Находим минимальный узел в правом поддереве (преемник)
min_parent = current
min_node = current['right']
while min_node['left']:
min_parent = min_node
min_node = min_node['left']
# Копируем данные из min_node в current
current['name'], current['phone'] = min_node['name'], min_node['phone']
# Удаляем min_node (у него нет левого потомка)
if min_parent['left'] == min_node:
min_parent['left'] = min_node['right']
else:
min_parent['right'] = min_node['right']
return root
# Подсоединяем child к parent
if parent is None:
return child
if parent['left'] == current:
parent['left'] = child
else:
parent['right'] = child
return root
def bst_list_all(root):
#Итеративный симметричный обход (inorder) без рекурсии, используя стек.
result = []
stack = []
current = root
while stack or current:
while current:
stack.append(current)
current = current['left']
current = stack.pop()
result.append((current['name'], current['phone']))
current = current['right']
return result
# --------------------- Функции измерений ---------------------
def generate_data(N=10000):
records = []
for i in range(N):
name = f"User_{i:05d}"
phone = f"8{random.randint(9000000000, 9999999999)}"
records.append((name, phone))
return records
def measure_insert(records):
root = None
start = time.perf_counter()
for name, phone in records:
root = bst_insert(root, name, phone)
end = time.perf_counter()
return end - start
def measure_find(records, test_names):
root = None
for name, phone in records:
root = bst_insert(root, name, phone)
start = time.perf_counter()
for name in test_names:
bst_find(root, name)
end = time.perf_counter()
return end - start
def measure_delete(records, delete_names):
times = []
for name in delete_names:
root = None
for n, p in records:
root = bst_insert(root, n, p)
start = time.perf_counter()
root = bst_delete(root, name)
end = time.perf_counter()
times.append(end - start)
return sum(times) / len(times)
def main():
N = 10000
records = generate_data(N)
records_shuffled = records.copy()
random.shuffle(records_shuffled)
records_sorted = sorted(records, key=lambda x: x[0])
existing_names = random.sample([rec[0] for rec in records], 100)
non_existing = [f"None_{i}" for i in range(10)]
test_names = existing_names + non_existing
delete_names = random.sample([rec[0] for rec in records], 50)
insert_shuffled_avg = 0.0
insert_sorted_avg = 0.0
find_avg = 0.0
delete_avg = 0.0
repeats = 5
for _ in range(repeats):
insert_shuffled_avg += measure_insert(records_shuffled)
insert_sorted_avg += measure_insert(records_sorted)
find_avg += measure_find(records, test_names)
delete_avg += measure_delete(records, delete_names)
insert_shuffled_avg /= repeats
insert_sorted_avg /= repeats
find_avg /= repeats
delete_avg /= repeats
new_rows = [
["Binary tree", "случайный", "вставка (корень)", insert_shuffled_avg],
["Binary tree", "отсортированный", "вставка (корень)", insert_sorted_avg],
["Binary tree", "любой", "поиск 110 записей", find_avg],
["Binary tree", "любой", "удаление 50 записей (среднее)", delete_avg]
]
csv_filename = "results.csv"
file_exists = os.path.isfile(csv_filename)
need_header = False
if file_exists:
with open(csv_filename, 'r', encoding='utf-8-sig') as f:
first_line = f.readline()
if not first_line.startswith("Структура"):
need_header = True
else:
need_header = True
with open(csv_filename, 'a', newline='', encoding='utf-8-sig') as f:
writer = csv.writer(f, delimiter=';')
if need_header:
writer.writerow(["Структура", "Режим", "Операция", "Время (сек)"])
writer.writerows(new_rows)
print("Результаты для двоичного дерева поиска добавлены в", csv_filename)
print(f"Среднее время вставки (случ. порядок): {insert_shuffled_avg:.6f} сек")
print(f"Среднее время вставки (отсорт.): {insert_sorted_avg:.6f} сек")
print(f"Среднее время поиска 110 записей: {find_avg:.6f} сек")
print(f"Среднее время удаления 50 записей: {delete_avg:.6f} сек")
if __name__ == "__main__":
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@ -0,0 +1,2 @@
t1_1.py -> t1_2.py -> t1_3.py
-> res.py

Binary file not shown.

View File

@ -0,0 +1,21 @@
maze_type;strategy;avg_time_ms;std_time_ms;avg_visited;avg_path_len;path_found
small_10x10_simple;BFS;0.187180;0.026335;19.000000;19.000000;True
small_10x10_simple;DFS;0.167600;0.006841;19.000000;19.000000;True
small_10x10_simple;A*;0.262300;0.029262;19.000000;19.000000;True
small_10x10_simple;Dijkstra;0.260840;0.008608;19.000000;19.000000;True
medium_50x50_deadends;BFS;3.563500;0.053603;380.000000;99.000000;True
medium_50x50_deadends;DFS;3.618520;0.082922;270.000000;219.000000;True
medium_50x50_deadends;A*;4.865660;0.017732;334.000000;99.000000;True
medium_50x50_deadends;Dijkstra;6.019060;0.037679;380.000000;99.000000;True
large_100x100_complex;BFS;8.644360;0.236037;886.000000;199.000000;True
large_100x100_complex;DFS;13.781640;2.087117;697.000000;511.000000;True
large_100x100_complex;A*;12.167040;0.334660;774.000000;199.000000;True
large_100x100_complex;Dijkstra;14.365940;0.236778;886.000000;199.000000;True
empty_50x50;BFS;24.584480;0.184147;2500.000000;99.000000;True
empty_50x50;DFS;182.315780;4.196306;2451.000000;2451.000000;True
empty_50x50;A*;42.602980;0.184895;2500.000000;99.000000;True
empty_50x50;Dijkstra;43.213780;0.745780;2500.000000;99.000000;True
no_exit_50x50;BFS;25.037680;0.572634;2496.000000;0.000000;False
no_exit_50x50;DFS;191.040920;3.180626;2496.000000;0.000000;False
no_exit_50x50;A*;42.158280;0.396219;2496.000000;0.000000;False
no_exit_50x50;Dijkstra;42.499100;0.482887;2496.000000;0.000000;False
Internal Server Error - DRE.lab repo

Internal Server Error

Gitea Version: 1.22.0