Merge pull request '[1] Первая лабораторная работа' (#235) from mylnikovas/2026-rff_mp:task_1 into develop
Reviewed-on: #235
This commit is contained in:
commit
6bf6bc0c5f
92
MylnikovAS/task_1/docs/data/experiment_part.py
Normal file
92
MylnikovAS/task_1/docs/data/experiment_part.py
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
def main():
|
||||||
|
N = 10000
|
||||||
|
random.seed(42)
|
||||||
|
|
||||||
|
records_sorted = [(f"User_{i:05d}", f"8-999-123-{i:04d}") for i in range(N)]
|
||||||
|
records_shuffled = records_sorted.copy()
|
||||||
|
random.shuffle(records_shuffled)
|
||||||
|
|
||||||
|
search_existing = [random.choice(records_sorted)[0] for _ in range(100)]
|
||||||
|
search_non_existing = [f"None_{i}" for i in range(10)]
|
||||||
|
search_names = search_existing + search_non_existing
|
||||||
|
delete_names = [random.choice(records_sorted)[0] for _ in range(50)]
|
||||||
|
|
||||||
|
csv_rows = [["Structure", "Mode", "Operation", "Time (sec)"]]
|
||||||
|
plot_data = []
|
||||||
|
|
||||||
|
def run_experiment(struct_type, mode, dataset):
|
||||||
|
print(f"Start: {struct_type} | Mode: {mode}...")
|
||||||
|
times_insert, times_find, times_delete = [], [], []
|
||||||
|
|
||||||
|
for round_idx in range(1, 6):
|
||||||
|
if struct_type == "LinkedList": container = None
|
||||||
|
elif struct_type == "HashTable": container = ht_create(size=1000)
|
||||||
|
elif struct_type == "BST": container = None
|
||||||
|
|
||||||
|
# А. Вставка
|
||||||
|
start = time.perf_counter()
|
||||||
|
if struct_type == "LinkedList":
|
||||||
|
for name, phone in dataset: container = ll_insert(container, name, phone)
|
||||||
|
elif struct_type == "HashTable":
|
||||||
|
for name, phone in dataset: ht_insert(container, name, phone)
|
||||||
|
elif struct_type == "BST":
|
||||||
|
for name, phone in dataset: container = bst_insert(container, name, phone)
|
||||||
|
t_ins = time.perf_counter() - start
|
||||||
|
times_insert.append(t_ins)
|
||||||
|
csv_rows.append([struct_type, mode, f"insert (number {round_idx})", f"{t_ins:.6f}"])
|
||||||
|
|
||||||
|
# Б. Поиск
|
||||||
|
start = time.perf_counter()
|
||||||
|
if struct_type == "LinkedList":
|
||||||
|
for name in search_names: ll_find(container, name)
|
||||||
|
elif struct_type == "HashTable":
|
||||||
|
for name in search_names: ht_find(container, name)
|
||||||
|
elif struct_type == "BST":
|
||||||
|
for name in search_names: bst_find(container, name)
|
||||||
|
t_find = time.perf_counter() - start
|
||||||
|
times_find.append(t_find)
|
||||||
|
csv_rows.append([struct_type, mode, f"find (number {round_idx})", f"{t_find:.6f}"])
|
||||||
|
|
||||||
|
# В. Удаление
|
||||||
|
start = time.perf_counter()
|
||||||
|
if struct_type == "LinkedList":
|
||||||
|
for name in delete_names: container = ll_delete(container, name)
|
||||||
|
elif struct_type == "HashTable":
|
||||||
|
for name in delete_names: ht_delete(container, name)
|
||||||
|
elif struct_type == "BST":
|
||||||
|
for name in delete_names: container = bst_delete(container, name)
|
||||||
|
t_del = time.perf_counter() - start
|
||||||
|
times_delete.append(t_del)
|
||||||
|
csv_rows.append([struct_type, mode, f"delete (number {round_idx})", f"{t_del:.6f}"])
|
||||||
|
|
||||||
|
# Запись средних значений
|
||||||
|
csv_rows.append([struct_type, mode, "Insert (average)", f"{sum(times_insert)/5:.6f}"])
|
||||||
|
csv_rows.append([struct_type, mode, "Find (average)", f"{sum(times_find)/5:.6f}"])
|
||||||
|
csv_rows.append([struct_type, mode, "Delete (average)", f"{sum(times_delete)/5:.6f}"])
|
||||||
|
|
||||||
|
avg_ins = sum(times_insert) / 5
|
||||||
|
avg_find = sum(times_find) / 5
|
||||||
|
avg_del = sum(times_delete) / 5
|
||||||
|
|
||||||
|
plot_data.append((struct_type, mode, avg_ins, avg_find, avg_del))
|
||||||
|
|
||||||
|
# Запуск всех тестов
|
||||||
|
run_experiment("LinkedList", "random", records_shuffled)
|
||||||
|
run_experiment("LinkedList", "sorted", records_sorted)
|
||||||
|
run_experiment("HashTable", "random", records_shuffled)
|
||||||
|
run_experiment("HashTable", "sorted", records_sorted)
|
||||||
|
run_experiment("BST", "random", records_shuffled)
|
||||||
|
run_experiment("BST", "sorted", records_sorted)
|
||||||
|
|
||||||
|
# Сохранение в CSV
|
||||||
|
with open("results.csv", "w", newline="", encoding="utf-8") as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
writer.writerows(csv_rows)
|
||||||
|
print("\n[Успех] Все тесты завершены! Результаты сохранены в 'results.csv'.")
|
||||||
|
|
||||||
|
generate_performance_charts(plot_data)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
experiment_thread = threading.Thread(target=main)
|
||||||
|
experiment_thread.start()
|
||||||
|
experiment_thread.join()
|
||||||
153
MylnikovAS/task_1/docs/data/ll_ht_bst.py
Normal file
153
MylnikovAS/task_1/docs/data/ll_ht_bst.py
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
import csv
|
||||||
|
import random
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
|
sys.setrecursionlimit(30000)
|
||||||
|
threading.stack_size(64*1024*1024)
|
||||||
|
|
||||||
|
|
||||||
|
def ll_insert(head, name, phone):
|
||||||
|
"""Добавляет запись или обновляет телефон, если имя уже существует. Возвращает новую голову списка."""
|
||||||
|
curr = head
|
||||||
|
while curr is not None:
|
||||||
|
if curr["name"] == name:
|
||||||
|
curr["phone"] = phone
|
||||||
|
return head
|
||||||
|
curr = curr["next"]
|
||||||
|
|
||||||
|
new_node = {"name": name, "phone": phone, "next": head}
|
||||||
|
return new_node
|
||||||
|
|
||||||
|
def ll_find(head, name):
|
||||||
|
"""Ищет узел по имени. Возвращает телефон или None."""
|
||||||
|
curr = head
|
||||||
|
while curr is not None:
|
||||||
|
if curr["name"] == name:
|
||||||
|
return curr["phone"]
|
||||||
|
curr = curr["next"]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def ll_delete(head, name):
|
||||||
|
"""Удаляет узел по имени. Возвращает новую голову списка."""
|
||||||
|
curr = head
|
||||||
|
prev = None
|
||||||
|
|
||||||
|
while curr is not None:
|
||||||
|
if curr["name"] == name:
|
||||||
|
if prev is None:
|
||||||
|
return curr["next"]
|
||||||
|
else:
|
||||||
|
prev["next"] = curr["next"]
|
||||||
|
return head
|
||||||
|
prev = curr
|
||||||
|
curr = curr["next"]
|
||||||
|
|
||||||
|
return head
|
||||||
|
|
||||||
|
def ll_list_all(head):
|
||||||
|
"""Собирает все записи в список и сортирует их по имени."""
|
||||||
|
records = []
|
||||||
|
curr = head
|
||||||
|
while curr is not None:
|
||||||
|
records.append((curr["name"], curr["phone"]))
|
||||||
|
curr = curr["next"]
|
||||||
|
records.sort(key=lambda x: x[0])
|
||||||
|
return records
|
||||||
|
|
||||||
|
|
||||||
|
def ht_create(size=1000):
|
||||||
|
"""Создает пустую хеш-таблицу заданного размера."""
|
||||||
|
return [None] * size
|
||||||
|
|
||||||
|
def ht_insert(buckets, name, phone):
|
||||||
|
"""Вычисляет индекс бакета и вызывает ll_insert."""
|
||||||
|
idx = abs(hash(name)) % len(buckets)
|
||||||
|
buckets[idx] = ll_insert(buckets[idx], name, phone)
|
||||||
|
|
||||||
|
def ht_find(buckets, name):
|
||||||
|
"""Вычисляет индекс бакета и вызывает ll_find."""
|
||||||
|
idx = abs(hash(name)) % len(buckets)
|
||||||
|
return ll_find(buckets[idx], name)
|
||||||
|
|
||||||
|
def ht_delete(buckets, name):
|
||||||
|
"""Вычисляет индекс бакета и вызывает ll_delete."""
|
||||||
|
idx = abs(hash(name)) % len(buckets)
|
||||||
|
buckets[idx] = ll_delete(buckets[idx], name)
|
||||||
|
|
||||||
|
def ht_list_all(buckets):
|
||||||
|
"""Собирает записи из всех бакетов и сортирует их по имени."""
|
||||||
|
records = []
|
||||||
|
for head in buckets:
|
||||||
|
curr = head
|
||||||
|
while curr is not None:
|
||||||
|
records.append((curr["name"], curr["phone"]))
|
||||||
|
curr = curr["next"]
|
||||||
|
records.sort(key=lambda x: x[0])
|
||||||
|
return records
|
||||||
|
|
||||||
|
|
||||||
|
def bst_insert(root, name, phone):
|
||||||
|
"""Рекурсивно вставляет узел или обновляет телефон."""
|
||||||
|
if root is None:
|
||||||
|
return {"name": name, "phone": phone, "left": None, "right": None}
|
||||||
|
|
||||||
|
if name == root["name"]:
|
||||||
|
root["phone"] = phone
|
||||||
|
elif name < root["name"]:
|
||||||
|
root["left"] = bst_insert(root["left"], name, phone)
|
||||||
|
else:
|
||||||
|
root["right"] = bst_insert(root["right"], name, phone)
|
||||||
|
|
||||||
|
return root
|
||||||
|
|
||||||
|
def bst_find(root, name):
|
||||||
|
"""Рекурсивный поиск по дереву."""
|
||||||
|
if root is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if name == root["name"]:
|
||||||
|
return root["phone"]
|
||||||
|
elif name < root["name"]:
|
||||||
|
return bst_find(root["left"], name)
|
||||||
|
else:
|
||||||
|
return bst_find(root["right"], name)
|
||||||
|
|
||||||
|
def bst_delete(root, name):
|
||||||
|
"""Рекурсивное удаление узла из BST."""
|
||||||
|
if root is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if name < root["name"]:
|
||||||
|
root["left"] = bst_delete(root["left"], name)
|
||||||
|
elif name > root["name"]:
|
||||||
|
root["right"] = bst_delete(root["right"], name)
|
||||||
|
else:
|
||||||
|
if root["left"] is None:
|
||||||
|
return root["right"]
|
||||||
|
if root["right"] is None:
|
||||||
|
return root["left"]
|
||||||
|
|
||||||
|
min_node = root["right"]
|
||||||
|
while min_node["left"] is not None:
|
||||||
|
min_node = min_node["left"]
|
||||||
|
|
||||||
|
root["name"] = min_node["name"]
|
||||||
|
root["phone"] = min_node["phone"]
|
||||||
|
root["right"] = bst_delete(root["right"], min_node["name"])
|
||||||
|
|
||||||
|
return root
|
||||||
|
|
||||||
|
def bst_list_all(root):
|
||||||
|
"""Центрированный обход дерева для сбора записей."""
|
||||||
|
records = []
|
||||||
|
def _inorder(node):
|
||||||
|
if node is not None:
|
||||||
|
_inorder(node["left"])
|
||||||
|
records.append((node["name"], node["phone"]))
|
||||||
|
_inorder(node["right"])
|
||||||
|
|
||||||
|
_inorder(root)
|
||||||
|
return records
|
||||||
BIN
MylnikovAS/task_1/docs/data/performance.png
Normal file
BIN
MylnikovAS/task_1/docs/data/performance.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 224 KiB |
109
MylnikovAS/task_1/docs/data/results.csv
Normal file
109
MylnikovAS/task_1/docs/data/results.csv
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
Structure,Mode,Operation,Time (sec)
|
||||||
|
LinkedList,random,insert (number 1),4.815837
|
||||||
|
LinkedList,random,find (number 1),0.052892
|
||||||
|
LinkedList,random,delete (number 1),0.027702
|
||||||
|
LinkedList,random,insert (number 2),4.566321
|
||||||
|
LinkedList,random,find (number 2),0.049406
|
||||||
|
LinkedList,random,delete (number 2),0.024055
|
||||||
|
LinkedList,random,insert (number 3),4.912175
|
||||||
|
LinkedList,random,find (number 3),0.048987
|
||||||
|
LinkedList,random,delete (number 3),0.025564
|
||||||
|
LinkedList,random,insert (number 4),5.096061
|
||||||
|
LinkedList,random,find (number 4),0.059990
|
||||||
|
LinkedList,random,delete (number 4),0.026717
|
||||||
|
LinkedList,random,insert (number 5),5.182869
|
||||||
|
LinkedList,random,find (number 5),0.055768
|
||||||
|
LinkedList,random,delete (number 5),0.027361
|
||||||
|
LinkedList,random,Insert (average),4.914653
|
||||||
|
LinkedList,random,Find (average),0.053409
|
||||||
|
LinkedList,random,Delete (average),0.026280
|
||||||
|
LinkedList,sorted,insert (number 1),4.635120
|
||||||
|
LinkedList,sorted,find (number 1),0.057343
|
||||||
|
LinkedList,sorted,delete (number 1),0.028141
|
||||||
|
LinkedList,sorted,insert (number 2),4.673462
|
||||||
|
LinkedList,sorted,find (number 2),0.058540
|
||||||
|
LinkedList,sorted,delete (number 2),0.030570
|
||||||
|
LinkedList,sorted,insert (number 3),4.720830
|
||||||
|
LinkedList,sorted,find (number 3),0.050661
|
||||||
|
LinkedList,sorted,delete (number 3),0.026368
|
||||||
|
LinkedList,sorted,insert (number 4),4.413700
|
||||||
|
LinkedList,sorted,find (number 4),0.061699
|
||||||
|
LinkedList,sorted,delete (number 4),0.040006
|
||||||
|
LinkedList,sorted,insert (number 5),4.487595
|
||||||
|
LinkedList,sorted,find (number 5),0.054366
|
||||||
|
LinkedList,sorted,delete (number 5),0.031918
|
||||||
|
LinkedList,sorted,Insert (average),4.586142
|
||||||
|
LinkedList,sorted,Find (average),0.056522
|
||||||
|
LinkedList,sorted,Delete (average),0.031401
|
||||||
|
HashTable,random,insert (number 1),0.013673
|
||||||
|
HashTable,random,find (number 1),0.000142
|
||||||
|
HashTable,random,delete (number 1),0.000081
|
||||||
|
HashTable,random,insert (number 2),0.012924
|
||||||
|
HashTable,random,find (number 2),0.000111
|
||||||
|
HashTable,random,delete (number 2),0.000056
|
||||||
|
HashTable,random,insert (number 3),0.013575
|
||||||
|
HashTable,random,find (number 3),0.000178
|
||||||
|
HashTable,random,delete (number 3),0.000090
|
||||||
|
HashTable,random,insert (number 4),0.012327
|
||||||
|
HashTable,random,find (number 4),0.000112
|
||||||
|
HashTable,random,delete (number 4),0.000058
|
||||||
|
HashTable,random,insert (number 5),0.012698
|
||||||
|
HashTable,random,find (number 5),0.000151
|
||||||
|
HashTable,random,delete (number 5),0.000055
|
||||||
|
HashTable,random,Insert (average),0.013039
|
||||||
|
HashTable,random,Find (average),0.000139
|
||||||
|
HashTable,random,Delete (average),0.000068
|
||||||
|
HashTable,sorted,insert (number 1),0.012770
|
||||||
|
HashTable,sorted,find (number 1),0.000128
|
||||||
|
HashTable,sorted,delete (number 1),0.000067
|
||||||
|
HashTable,sorted,insert (number 2),0.030806
|
||||||
|
HashTable,sorted,find (number 2),0.000143
|
||||||
|
HashTable,sorted,delete (number 2),0.000074
|
||||||
|
HashTable,sorted,insert (number 3),0.011925
|
||||||
|
HashTable,sorted,find (number 3),0.000142
|
||||||
|
HashTable,sorted,delete (number 3),0.000072
|
||||||
|
HashTable,sorted,insert (number 4),0.012686
|
||||||
|
HashTable,sorted,find (number 4),0.000263
|
||||||
|
HashTable,sorted,delete (number 4),0.000114
|
||||||
|
HashTable,sorted,insert (number 5),0.011504
|
||||||
|
HashTable,sorted,find (number 5),0.000139
|
||||||
|
HashTable,sorted,delete (number 5),0.000075
|
||||||
|
HashTable,sorted,Insert (average),0.015938
|
||||||
|
HashTable,sorted,Find (average),0.000163
|
||||||
|
HashTable,sorted,Delete (average),0.000080
|
||||||
|
BST,random,insert (number 1),0.042690
|
||||||
|
BST,random,find (number 1),0.000424
|
||||||
|
BST,random,delete (number 1),0.000232
|
||||||
|
BST,random,insert (number 2),0.042969
|
||||||
|
BST,random,find (number 2),0.000436
|
||||||
|
BST,random,delete (number 2),0.000248
|
||||||
|
BST,random,insert (number 3),0.041771
|
||||||
|
BST,random,find (number 3),0.000462
|
||||||
|
BST,random,delete (number 3),0.000280
|
||||||
|
BST,random,insert (number 4),0.046081
|
||||||
|
BST,random,find (number 4),0.000392
|
||||||
|
BST,random,delete (number 4),0.000199
|
||||||
|
BST,random,insert (number 5),0.042080
|
||||||
|
BST,random,find (number 5),0.000404
|
||||||
|
BST,random,delete (number 5),0.000213
|
||||||
|
BST,random,Insert (average),0.043118
|
||||||
|
BST,random,Find (average),0.000424
|
||||||
|
BST,random,Delete (average),0.000234
|
||||||
|
BST,sorted,insert (number 1),21.678231
|
||||||
|
BST,sorted,find (number 1),0.198191
|
||||||
|
BST,sorted,delete (number 1),0.080743
|
||||||
|
BST,sorted,insert (number 2),25.945965
|
||||||
|
BST,sorted,find (number 2),0.197616
|
||||||
|
BST,sorted,delete (number 2),0.095071
|
||||||
|
BST,sorted,insert (number 3),25.663677
|
||||||
|
BST,sorted,find (number 3),0.194259
|
||||||
|
BST,sorted,delete (number 3),0.081219
|
||||||
|
BST,sorted,insert (number 4),22.098788
|
||||||
|
BST,sorted,find (number 4),0.197365
|
||||||
|
BST,sorted,delete (number 4),0.090777
|
||||||
|
BST,sorted,insert (number 5),22.467530
|
||||||
|
BST,sorted,find (number 5),0.168119
|
||||||
|
BST,sorted,delete (number 5),0.071693
|
||||||
|
BST,sorted,Insert (average),23.570838
|
||||||
|
BST,sorted,Find (average),0.191110
|
||||||
|
BST,sorted,Delete (average),0.083900
|
||||||
|
BIN
MylnikovAS/task_1/docs/Отчёт по лабораторной работе.docx
Normal file
BIN
MylnikovAS/task_1/docs/Отчёт по лабораторной работе.docx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user