2026-rff_mp/stepinim/lab1_structure/test.py
2026-05-20 15:19:09 +03:00

433 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import sys
sys.setrecursionlimit(30000)
csv_path = '/stepinim/docs/data/lab1_results.csv'
#Связный список
def ll_insert(head, name, phone):
new_node = {'name': name, 'phone': phone, 'next': None}
if head is None:
return new_node
curr = head
prev = None
while curr is not None:
if curr['name'] == name:
curr['phone'] = phone
return head
prev = curr
curr = curr['next']
prev['next'] = new_node
return head
def ll_find(head, name):
curr = head
while curr:
if curr['name'] == name:
return curr['phone']
curr = curr['next']
return None
def ll_delete(head, name):
if head is None:
return None
if head['name'] == name:
return head['next']
curr = head
while curr['next']:
if curr['next']['name'] == name:
curr['next'] = curr['next']['next']
return head
curr = curr['next']
return head
def ll_list_all(head):
result = []
curr = head
while curr:
result.append((curr['name'], curr['phone']))
curr = curr['next']
result.sort(key=lambda x: x[0])
return result
#Хэш-таблица
HASH_SIZE = 1009
def _hash_name(name):
return hash(name) % HASH_SIZE
def ht_insert(buckets, name, phone):
idx = _hash_name(name)
buckets[idx] = ll_insert(buckets[idx], name, phone)
def ht_find(buckets, name):
idx = _hash_name(name)
return ll_find(buckets[idx], name)
def ht_delete(buckets, name):
idx = _hash_name(name)
buckets[idx] = ll_delete(buckets[idx], name)
def ht_list_all(buckets):
all_entries = []
for bucket in buckets:
if bucket is not None:
curr = bucket
while curr:
all_entries.append((curr['name'], curr['phone']))
curr = curr['next']
all_entries.sort(key=lambda x: x[0])
return all_entries
#Двоичное дерево поиска
def bst_insert(root, name, phone):
if root is None:
return {'name': name, 'phone': phone, 'left': None, 'right': None}
if name < root['name']:
root['left'] = bst_insert(root['left'], name, phone)
elif name > root['name']:
root['right'] = bst_insert(root['right'], name, phone)
else:
root['phone'] = phone
return root
def bst_find(root, name):
curr = root
while curr:
if name == curr['name']:
return curr['phone']
elif name < curr['name']:
curr = curr['left']
else:
curr = curr['right']
return None
def bst_delete(root, name):
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']:
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):
result = []
def inorder(node):
if node:
inorder(node['left'])
result.append((node['name'], node['phone']))
inorder(node['right'])
inorder(root)
return result
# ============================================================
# TECT
# ============================================================
import os
import random
import time
import csv
import pandas as pd
import matplotlib.pyplot as plt
# ============================================================
# ПОДГОТОВКА ПАПОК
# ============================================================
DATA_DIR = os.path.join("docs", "data")
os.makedirs(DATA_DIR, exist_ok=True)
csv_path = os.path.join(DATA_DIR, "lab1_results.csv")
graph_path = os.path.join(DATA_DIR, "lab1_graph.png")
# ============================================================
# ТЕСТОВЫЕ ДАННЫЕ
# ============================================================
random.seed(42)
N = 3000
base_records = [
(f"User_{i:05d}", f"123-{i:05d}")
for i in range(N)
]
records_shuffled = base_records.copy()
random.shuffle(records_shuffled)
records_sorted = sorted(base_records, key=lambda x: x[0])
# Поиск
search_existing = [
name for name, _ in random.sample(base_records, 100)
]
search_nonexist = [
f"None_{i}"
for i in range(10)
]
# Удаление
delete_names = [
name for name, _ in random.sample(base_records, 50)
]
# ============================================================
# СОЗДАНИЕ СТРУКТУР
# ============================================================
def build_structure(records, struct_type):
if struct_type == "ll":
structure = None
for name, phone in records:
structure = ll_insert(structure, name, phone)
return structure
elif struct_type == "ht":
structure = [None] * HASH_SIZE
for name, phone in records:
ht_insert(structure, name, phone)
return structure
elif struct_type == "bst":
structure = None
for name, phone in records:
structure = bst_insert(structure, name, phone)
return structure
# ============================================================
# INSERT
# ============================================================
def measure_insert(records, struct_type):
start = time.perf_counter()
build_structure(records, struct_type)
end = time.perf_counter()
return end - start
# ============================================================
# SEARCH
# ============================================================
def measure_search(records, struct_type):
structure = build_structure(records, struct_type)
start = time.perf_counter()
if struct_type == "ll":
for name in search_existing + search_nonexist:
ll_find(structure, name)
elif struct_type == "ht":
for name in search_existing + search_nonexist:
ht_find(structure, name)
elif struct_type == "bst":
for name in search_existing + search_nonexist:
bst_find(structure, name)
end = time.perf_counter()
return end - start
# ============================================================
# DELETE
# ============================================================
def measure_delete(records, struct_type):
structure = build_structure(records, struct_type)
start = time.perf_counter()
if struct_type == "ll":
for name in delete_names:
structure = ll_delete(structure, name)
elif struct_type == "ht":
for name in delete_names:
ht_delete(structure, name)
elif struct_type == "bst":
for name in delete_names:
structure = bst_delete(structure, name)
end = time.perf_counter()
return end - start
# ============================================================
# ЗАМЕРЫ
# ============================================================
all_data = []
experiments = [
("LinkedList", "ll"),
("HashTable", "ht"),
("BST", "bst")
]
modes = [
("shuffled", records_shuffled),
("sorted", records_sorted)
]
for struct_name, struct_type in experiments:
for mode_name, records in modes:
for rep in range(1, 4):
insert_time = measure_insert(records, struct_type)
search_time = measure_search(records, struct_type)
delete_time = measure_delete(records, struct_type)
all_data.append([
struct_name,
mode_name,
rep,
"insert",
insert_time
])
all_data.append([
struct_name,
mode_name,
rep,
"search",
search_time
])
all_data.append([
struct_name,
mode_name,
rep,
"delete",
delete_time
])
# ============================================================
# CSV
# ============================================================
with open(csv_path, "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow([
"Структура",
"Режим",
"Повтор",
"Операция",
"Время (сек)"
])
writer.writerows(all_data)
print(f"CSV сохранён: {csv_path}")
# ============================================================
# ГРАФИК
# ============================================================
df = pd.read_csv(csv_path)
df_avg = (
df.groupby(
["Структура", "Режим", "Операция"]
)["Время (сек)"]
.mean()
.reset_index()
)
fig, ax = plt.subplots(figsize=(12, 6))
ops = ["insert", "search", "delete"]
x = range(len(ops))
width = 0.12
configs = [
("LinkedList", "shuffled"),
("LinkedList", "sorted"),
("HashTable", "shuffled"),
("HashTable", "sorted"),
("BST", "shuffled"),
("BST", "sorted")
]
for i, (struct, mode) in enumerate(configs):
subset = df_avg[
(df_avg["Структура"] == struct)
&
(df_avg["Режим"] == mode)
]
times = [
subset[
subset["Операция"] == op
]["Время (сек)"].values[0]
for op in ops
]
ax.bar(
[p + i * width for p in x],
times,
width,
label=f"{struct} ({mode})"
)
ax.set_xticks([p + 2.5 * width for p in x])
ax.set_xticklabels(ops)
ax.set_ylabel("Среднее время (сек)")
ax.set_title("Сравнение структур данных")
ax.legend(
bbox_to_anchor=(1.05, 1),
loc="upper left"
)
plt.tight_layout()
plt.savefig(graph_path)
print(f"График сохранён: {graph_path}")
plt.show()