2026-rff_mp/SokolovNE/main.py

494 lines
15 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 time
import csv
import random
import copy
import os
# ============================================================
# 1. СВЯЗНЫЙ СПИСОК (LinkedList)
# ============================================================
def ll_insert(head, name, phone):
if head is None:
return {'name': name, 'phone': phone, 'next': None}
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': None}
curr = head
while curr['next'] is not None:
curr = curr['next']
curr['next'] = new_node
return head
def ll_find(head, name):
curr = head
while curr is not None:
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']
prev = head
curr = head['next']
while curr is not None:
if curr['name'] == name:
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
# ============================================================
# 2. ХЕШ-ТАБЛИЦА (HashTable)
# ============================================================
def _hash(name, bucket_count):
return sum(ord(ch) for ch in name) % bucket_count
def ht_create(bucket_count=1000):
return [None] * bucket_count
def ht_insert(buckets, name, phone):
idx = _hash(name, len(buckets))
buckets[idx] = ll_insert(buckets[idx], name, phone)
def ht_find(buckets, name):
idx = _hash(name, len(buckets))
return ll_find(buckets[idx], name)
def ht_delete(buckets, name):
idx = _hash(name, len(buckets))
buckets[idx] = ll_delete(buckets[idx], name)
def ht_list_all(buckets):
all_records = []
for head in buckets:
curr = head
while curr is not None:
all_records.append((curr['name'], curr['phone']))
curr = curr['next']
all_records.sort(key=lambda x: x[0])
return all_records
# ============================================================
# 3. ДВОИЧНОЕ ДЕРЕВО ПОИСКА (BST) — итеративная версия
# ============================================================
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']
elif name < current['name']:
current = current['left']
else:
current = current['right']
return None
def bst_min_node(node):
while node['left'] is not None:
node = node['left']
return node
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 None and current['right'] is None:
if parent is None:
return None
if parent['left'] is current:
parent['left'] = None
else:
parent['right'] = None
return root
if current['left'] is None:
child = current['right']
elif current['right'] is None:
child = current['left']
else:
successor_parent = current
successor = current['right']
while successor['left'] is not None:
successor_parent = successor
successor = successor['left']
current['name'] = successor['name']
current['phone'] = successor['phone']
if successor_parent['left'] is successor:
successor_parent['left'] = successor['right']
else:
successor_parent['right'] = successor['right']
return root
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):
result = []
stack = []
current = root
while stack or current is not None:
while current is not None:
stack.append(current)
current = current['left']
current = stack.pop()
result.append((current['name'], current['phone']))
current = current['right']
return result
# ============================================================
# 4. ГЕНЕРАЦИЯ ТЕСТОВЫХ ДАННЫХ
# ============================================================
def generate_records(N=5000):
records = [(f"User_{i:05d}", f"phone_{i}") for i in range(N)]
shuffled = copy.deepcopy(records)
random.shuffle(shuffled)
return shuffled, records
# ============================================================
# 5. ЗАМЕРЫ ДЛЯ LINKEDLIST
# ============================================================
def test_linked_list(records_shuffled, records_sorted, results):
N = len(records_shuffled)
# Вставка shuffled
times = []
for _ in range(5):
head = None
start = time.perf_counter()
for name, phone in records_shuffled:
head = ll_insert(head, name, phone)
times.append(time.perf_counter() - start)
results.append(["LinkedList", "shuffled", "insert", sum(times) / 5] + times)
# Вставка sorted
times = []
for _ in range(5):
head = None
start = time.perf_counter()
for name, phone in records_sorted:
head = ll_insert(head, name, phone)
times.append(time.perf_counter() - start)
results.append(["LinkedList", "sorted", "insert", sum(times) / 5] + times)
# Подготовка для поиска/удаления
head = None
for name, phone in records_shuffled:
head = ll_insert(head, name, phone)
# Поиск
existing = [f"User_{i:05d}" for i in random.sample(range(N), 100)]
nonexisting = [f"None_{i}" for i in range(10)]
search_names = existing + nonexisting
times = []
for _ in range(5):
start = time.perf_counter()
for name in search_names:
ll_find(head, name)
times.append(time.perf_counter() - start)
results.append(["LinkedList", "shuffled", "search", sum(times) / 5] + times)
# Удаление
delete_names = [f"User_{i:05d}" for i in random.sample(range(N), 50)]
times = []
for _ in range(5):
head_copy = None
for name, phone in records_shuffled:
head_copy = ll_insert(head_copy, name, phone)
start = time.perf_counter()
for name in delete_names:
head_copy = ll_delete(head_copy, name)
times.append(time.perf_counter() - start)
results.append(["LinkedList", "shuffled", "delete", sum(times) / 5] + times)
# ============================================================
# 6. ЗАМЕРЫ ДЛЯ ХЕШ-ТАБЛИЦЫ
# ============================================================
def test_hash_table(records_shuffled, records_sorted, results):
N = len(records_shuffled)
bucket_count = 1000
# Вставка shuffled
times = []
for _ in range(5):
buckets = ht_create(bucket_count)
start = time.perf_counter()
for name, phone in records_shuffled:
ht_insert(buckets, name, phone)
times.append(time.perf_counter() - start)
results.append(["HashTable", "shuffled", "insert", sum(times) / 5] + times)
# Вставка sorted
times = []
for _ in range(5):
buckets = ht_create(bucket_count)
start = time.perf_counter()
for name, phone in records_sorted:
ht_insert(buckets, name, phone)
times.append(time.perf_counter() - start)
results.append(["HashTable", "sorted", "insert", sum(times) / 5] + times)
# Подготовка
buckets = ht_create(bucket_count)
for name, phone in records_shuffled:
ht_insert(buckets, name, phone)
# Поиск
existing = [f"User_{i:05d}" for i in random.sample(range(N), 100)]
nonexisting = [f"None_{i}" for i in range(10)]
search_names = existing + nonexisting
times = []
for _ in range(5):
start = time.perf_counter()
for name in search_names:
ht_find(buckets, name)
times.append(time.perf_counter() - start)
results.append(["HashTable", "shuffled", "search", sum(times) / 5] + times)
# Удаление
delete_names = [f"User_{i:05d}" for i in random.sample(range(N), 50)]
times = []
for _ in range(5):
buckets_copy = ht_create(bucket_count)
for name, phone in records_shuffled:
ht_insert(buckets_copy, name, phone)
start = time.perf_counter()
for name in delete_names:
ht_delete(buckets_copy, name)
times.append(time.perf_counter() - start)
results.append(["HashTable", "shuffled", "delete", sum(times) / 5] + times)
# ============================================================
# 7. ЗАМЕРЫ ДЛЯ BST
# ============================================================
def test_bst(records_shuffled, records_sorted, results):
N = len(records_shuffled)
# Вставка shuffled
times = []
for _ in range(5):
root = None
start = time.perf_counter()
for name, phone in records_shuffled:
root = bst_insert(root, name, phone)
times.append(time.perf_counter() - start)
results.append(["BST", "shuffled", "insert", sum(times) / 5] + times)
# Вставка sorted
times = []
for _ in range(5):
root = None
start = time.perf_counter()
for name, phone in records_sorted:
root = bst_insert(root, name, phone)
times.append(time.perf_counter() - start)
results.append(["BST", "sorted", "insert", sum(times) / 5] + times)
# Подготовка
root = None
for name, phone in records_shuffled:
root = bst_insert(root, name, phone)
# Поиск
existing = [f"User_{i:05d}" for i in random.sample(range(N), 100)]
nonexisting = [f"None_{i}" for i in range(10)]
search_names = existing + nonexisting
times = []
for _ in range(5):
start = time.perf_counter()
for name in search_names:
bst_find(root, name)
times.append(time.perf_counter() - start)
results.append(["BST", "shuffled", "search", sum(times) / 5] + times)
# Удаление
delete_names = [f"User_{i:05d}" for i in random.sample(range(N), 50)]
times = []
for _ in range(5):
root_copy = None
for name, phone in records_shuffled:
root_copy = bst_insert(root_copy, name, phone)
start = time.perf_counter()
for name in delete_names:
root_copy = bst_delete(root_copy, name)
times.append(time.perf_counter() - start)
results.append(["BST", "shuffled", "delete", sum(times) / 5] + times)
# ============================================================
# 8. СОХРАНЕНИЕ РЕЗУЛЬТАТОВ В CSV
# ============================================================
def save_results(results, filename="docs/data/results.csv"):
os.makedirs("docs/data", exist_ok=True)
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["Structure", "Mode", "Operation", "AvgSec", "Run1", "Run2", "Run3", "Run4", "Run5"])
for row in results:
writer.writerow(row)
print(f"Результаты сохранены в {filename}")
# ============================================================
# 9. ПОСТРОЕНИЕ ГРАФИКОВ
# ============================================================
def plot_results():
"""Построение графиков по результатам из CSV"""
try:
import matplotlib.pyplot as plt
import pandas as pd
except ImportError:
print("Библиотеки matplotlib или pandas не установлены. Пропускаем графики.")
print("Установите: pip install matplotlib pandas")
return
try:
df = pd.read_csv("docs/data/results.csv")
except FileNotFoundError:
print("Файл results.csv не найден. Сначала запустите main.py для генерации данных.")
return
operations = df["Operation"].unique()
for op in operations:
subset = df[df["Operation"] == op]
plt.figure(figsize=(10, 6))
labels = [f"{row.Structure}\n({row.Mode})" for _, row in subset.iterrows()]
values = subset["AvgSec"]
plt.bar(labels, values, color=['blue', 'orange', 'green', 'red', 'purple', 'brown'])
plt.title(f"Сравнение времени {op} (5 замеров, N=5000)")
plt.ylabel("Время (секунды)")
plt.xticks(rotation=45)
plt.tight_layout()
filename = f"docs/graph_{op}.png"
plt.savefig(filename)
print(f"Сохранён график: {filename}")
plt.close()
print("\nГрафики построены и сохранены в папке docs/")
# ============================================================
# 10. MAIN
# ============================================================
def main():
print("Генерация тестовых данных (N=5000)...")
shuffled, sorted_records = generate_records(5000)
results = []
print("Тестирование LinkedList...")
test_linked_list(shuffled, sorted_records, results)
print("Тестирование HashTable...")
test_hash_table(shuffled, sorted_records, results)
print("Тестирование BST...")
test_bst(shuffled, sorted_records, results)
save_results(results)
# Построение графиков
plot_results()
print("\nГотово! Файл results.csv и графики сохранены в папке docs/")
if __name__ == "__main__":
main()