тест полной программы (Успех)

This commit is contained in:
Dima 2026-05-16 20:01:46 +03:00
parent 6c9a56505a
commit 303da5bdc5
3 changed files with 373 additions and 1 deletions

View File

@ -0,0 +1,19 @@
Структура;Режим;Операция;Замер1(с);Замер2(с);Замер3(с);Замер4(с);Замер5(с);Среднее(с)
linked_list;случайный;вставка;5.503300700000182;5.004083100000571;4.882084700000632;4.881827499999417;4.890130499999941;5.032285300000149
linked_list;случайный;поиск;0.05034929999965243;0.04795749999993859;0.046004300000277;0.04418989999976475;0.04287860000022192;0.04627591999997094
linked_list;случайный;удаление;0.03702340000018012;0.03709479999997711;0.03829469999982393;0.03841730000021926;0.03741160000026866;0.03764836000009382
hash_table;случайный;вставка;0.03724729999976262;0.036700800000289746;0.03645409999990079;0.036475899999459216;0.035486800000398944;0.03647297999996226
hash_table;случайный;поиск;0.00042500000017753337;0.00033910000001924345;0.00033829999938461697;0.0003378999999767984;0.00033820000044215703;0.00035570000000006985
hash_table;случайный;удаление;0.00018709999949351186;0.00017469999966124306;0.0001795999996829778;0.00018339999951422215;0.00017609999940759735;0.00018017999955191044
bst;случайный;вставка;0.04527770000004239;0.042043200000080105;0.04279800000040268;0.038970799999333394;0.03744349999942642;0.041306639999856995
bst;случайный;поиск;0.0005276000001686043;0.0004296000006434042;0.00043430000005173497;0.00041569999939383706;0.0004365999993751757;0.00044875999992655125
bst;случайный;удаление;0.09453469999971276;0.09244760000001406;0.10106580000046961;0.09086349999961385;0.09310050000021874;0.0944024200000058
linked_list;отсортированный;вставка;6.237431600000491;6.1635778999998365;6.183921300000293;6.150560400000359;6.1811854999996285;6.183335340000122
linked_list;отсортированный;поиск;0.05593550000048708;0.053237000000081025;0.05208490000040911;0.05022400000052585;0.049882199999956356;0.052272720000291886
linked_list;отсортированный;удаление;0.04117889999997715;0.037663099999917904;0.03757399999994959;0.04252919999998994;0.03767599999991944;0.03932423999995081
hash_table;отсортированный;вставка;0.04085130000021309;0.03589560000000347;0.03588300000046729;0.035286500000438537;0.03309669999998732;0.03620262000022194
hash_table;отсортированный;поиск;0.00044720000005327165;0.00040470000021741726;0.0003451000002314686;0.00034250000044266926;0.0003420000002734014;0.00037630000024364564
hash_table;отсортированный;удаление;0.0001863999996203347;0.00017409999964002054;0.00017500000012660166;0.00017459999980928842;0.00017379999917466193;0.00017677999967418144
bst;отсортированный;вставка;18.630878699999812;18.350701800000024;18.322985300001164;18.381200199999512;18.44051959999888;18.425257119999877
bst;отсортированный;поиск;0.16251639999973122;0.15183020000040415;0.1572033000011288;0.16128759999992326;0.16190610000012384;0.15894872000026225
bst;отсортированный;удаление;0.09546029999910388;0.09252720000040426;0.09302340000067488;0.09245310000005702;0.09305589999894437;0.09330397999983689
1 Структура Режим Операция Замер1(с) Замер2(с) Замер3(с) Замер4(с) Замер5(с) Среднее(с)
2 linked_list случайный вставка 5.503300700000182 5.004083100000571 4.882084700000632 4.881827499999417 4.890130499999941 5.032285300000149
3 linked_list случайный поиск 0.05034929999965243 0.04795749999993859 0.046004300000277 0.04418989999976475 0.04287860000022192 0.04627591999997094
4 linked_list случайный удаление 0.03702340000018012 0.03709479999997711 0.03829469999982393 0.03841730000021926 0.03741160000026866 0.03764836000009382
5 hash_table случайный вставка 0.03724729999976262 0.036700800000289746 0.03645409999990079 0.036475899999459216 0.035486800000398944 0.03647297999996226
6 hash_table случайный поиск 0.00042500000017753337 0.00033910000001924345 0.00033829999938461697 0.0003378999999767984 0.00033820000044215703 0.00035570000000006985
7 hash_table случайный удаление 0.00018709999949351186 0.00017469999966124306 0.0001795999996829778 0.00018339999951422215 0.00017609999940759735 0.00018017999955191044
8 bst случайный вставка 0.04527770000004239 0.042043200000080105 0.04279800000040268 0.038970799999333394 0.03744349999942642 0.041306639999856995
9 bst случайный поиск 0.0005276000001686043 0.0004296000006434042 0.00043430000005173497 0.00041569999939383706 0.0004365999993751757 0.00044875999992655125
10 bst случайный удаление 0.09453469999971276 0.09244760000001406 0.10106580000046961 0.09086349999961385 0.09310050000021874 0.0944024200000058
11 linked_list отсортированный вставка 6.237431600000491 6.1635778999998365 6.183921300000293 6.150560400000359 6.1811854999996285 6.183335340000122
12 linked_list отсортированный поиск 0.05593550000048708 0.053237000000081025 0.05208490000040911 0.05022400000052585 0.049882199999956356 0.052272720000291886
13 linked_list отсортированный удаление 0.04117889999997715 0.037663099999917904 0.03757399999994959 0.04252919999998994 0.03767599999991944 0.03932423999995081
14 hash_table отсортированный вставка 0.04085130000021309 0.03589560000000347 0.03588300000046729 0.035286500000438537 0.03309669999998732 0.03620262000022194
15 hash_table отсортированный поиск 0.00044720000005327165 0.00040470000021741726 0.0003451000002314686 0.00034250000044266926 0.0003420000002734014 0.00037630000024364564
16 hash_table отсортированный удаление 0.0001863999996203347 0.00017409999964002054 0.00017500000012660166 0.00017459999980928842 0.00017379999917466193 0.00017677999967418144
17 bst отсортированный вставка 18.630878699999812 18.350701800000024 18.322985300001164 18.381200199999512 18.44051959999888 18.425257119999877
18 bst отсортированный поиск 0.16251639999973122 0.15183020000040415 0.1572033000011288 0.16128759999992326 0.16190610000012384 0.15894872000026225
19 bst отсортированный удаление 0.09546029999910388 0.09252720000040426 0.09302340000067488 0.09245310000005702 0.09305589999894437 0.09330397999983689

BIN
nikolaevda/graphs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@ -1,3 +1,12 @@
import random
import time
import csv
import os
import traceback
import sys
sys.setrecursionlimit(30000)
def ll_insert(head, name, phone): def ll_insert(head, name, phone):
""" """
@ -294,3 +303,347 @@ def bst_list_all(root, result=None):
bst_list_all(root['right'], result) bst_list_all(root['right'], result)
return result return result
def generate_records(count=10000):
"""
генерация тестовых данных
70% уникальных имён, 30% повторяющихся (для коллизий)
"""
records = []
base_names = ["Алексей", "Борис", "Владимир", "Дмитрий", "Елена",
"Иван", "Мария", "Николай", "Ольга", "Павел"]
for i in range(count):
if random.random() < 0.7:
name = f"User_{i:05d}"
else:
name = random.choice(base_names) + f"_{random.randint(1, 100)}"
phone = f"+7-{random.randint(100,999)}-{random.randint(100,999)}-{random.randint(1000,9999)}"
records.append((name, phone))
shuffled = records.copy()
random.shuffle(shuffled)
sorted_records = sorted(records, key=lambda x: x[0])
return shuffled, sorted_records
def measure_insertion(structure_name, records):
"""
замер времени вставки
возвращает список замеров и заполненную структуру
"""
times = []
filled_structure = None
for run in range(5):
if structure_name == "linked_list":
structure = None
elif structure_name == "hash_table":
structure = hash_table(2003)
elif structure_name == "bst":
structure = None
start = time.perf_counter()
for name, phone in records:
if structure_name == "linked_list":
structure = ll_insert(structure, name, phone)
elif structure_name == "hash_table":
ht_insert(structure, name, phone)
elif structure_name == "bst":
structure = bst_insert(structure, name, phone)
end = time.perf_counter()
times.append(end - start)
if run == 4: # Сохраняем после последнего замера
filled_structure = structure
return times, filled_structure
def measure_search(structure_name, structure, search_names):
"""
замер времени поиска
возвращает список замеров
"""
times = []
for run in range(5):
start = time.perf_counter()
for name in search_names:
if structure_name == "linked_list":
ll_find(structure, name)
elif structure_name == "hash_table":
ht_find(structure, name)
elif structure_name == "bst":
bst_find(structure, name)
end = time.perf_counter()
times.append(end - start)
return times
def measure_deletion(structure_name, original_structure, delete_names):
"""
замер времени удаления
возвращает список замеров
"""
times = []
for run in range(5):
# создаём копию структуры
if structure_name == "linked_list":
all_records = ll_list_all(original_structure)
test_structure = None
for name, phone in all_records:
test_structure = ll_insert(test_structure, name, phone)
elif structure_name == "hash_table":
all_records = ht_list_all(original_structure)
test_structure = hash_table(2003)
for name, phone in all_records:
ht_insert(test_structure, name, phone)
elif structure_name == "bst":
all_records = bst_list_all(original_structure)
test_structure = None
for name, phone in all_records:
test_structure = bst_insert(test_structure, name, phone)
start = time.perf_counter()
for name in delete_names:
if structure_name == "linked_list":
test_structure = ll_delete(test_structure, name)
elif structure_name == "hash_table":
ht_delete(test_structure, name)
elif structure_name == "bst":
test_structure = bst_delete(test_structure, name)
end = time.perf_counter()
times.append(end - start)
return times
print(f"Текущая рабочая директория: {os.getcwd()}")
print(f"Путь к файлу: {os.path.abspath(__file__)}")
def run_experiment():
"""
запуск всех экспериментов и сохранение результатов
"""
current_dir = os.path.dirname(__file__)
docs_dir = os.path.dirname(current_dir)
csv_file = os.path.join(docs_dir, "experiment_results.csv")
os.makedirs(docs_dir, exist_ok=True)
print("ЭКСПЕРИМЕНТАЛЬНОЕ СРАВНЕНИЕ СТРУКТУР ДАННЫХ")
print("Телефонный справочник - 10000 записей")
print(f"\nРезультаты будут сохранены в: {csv_file}")
# генерация данных
print("\n1. Генерация тестовых данных...")
shuffled_records, sorted_records = generate_records(10000)
print(f"Сгенерировано 10000 записей")
print(f"Уникальных имён: {len(set([r[0] for r in shuffled_records]))}")
# подготовка имён для поиска и удаления
random.seed(42)
existing_names = [shuffled_records[i][0] for i in random.sample(range(10000), 100)]
nonexisting_names = [f"NotExist_{i}" for i in range(10)]
search_names = existing_names + nonexisting_names
delete_names = [shuffled_records[i][0] for i in random.sample(range(10000), 50)]
results = [["Структура", "Режим", "Операция",
"Замер1(с)", "Замер2(с)", "Замер3(с)", "Замер4(с)", "Замер5(с)",
"Среднее(с)"]]
# тестирование для каждого режима
for mode_name, records in [("случайный", shuffled_records),
("отсортированный", sorted_records)]:
print(f"\n2. Тестирование режима: {mode_name}")
for struct_name in ["linked_list", "hash_table", "bst"]:
print(f"\n {struct_name.upper()}:")
# вставка
print("Вставка 10000 записей...")
insert_times, filled_struct = measure_insertion(struct_name, records)
avg_insert = sum(insert_times) / 5
print(f"Время: {avg_insert:.4f} сек (среднее)")
# поиск
print("Поиск 110 записей (100 существующих + 10 которых нет)...")
search_times = measure_search(struct_name, filled_struct, search_names)
avg_search = sum(search_times) / 5
print(f"Время: {avg_search:.4f} сек (среднее)")
# удаление
print("Удаление 50 случайных записей...")
delete_times = measure_deletion(struct_name, filled_struct, delete_names)
avg_delete = sum(delete_times) / 5
print(f"Время: {avg_delete:.4f} сек (среднее)")
# сохраняем результаты
results.append([struct_name, mode_name, "вставка"] + insert_times + [avg_insert])
results.append([struct_name, mode_name, "поиск"] + search_times + [avg_search])
results.append([struct_name, mode_name, "удаление"] + delete_times + [avg_delete])
# сохранение CSV
print("\n3. Сохранение результатов...")
try:
with open(csv_file, "w", newline="", encoding="utf-8-sig") as f:
writer = csv.writer(f, delimiter=';')
writer.writerows(results)
print(f"Результаты сохранены в: {csv_file}")
except Exception as e:
print(f"Ошибка сохранения: {e}")
# вывод табл.
print("СВОДНАЯ ТАБЛИЦА РЕЗУЛЬТАТОВ")
print(f"{'Структура':<15} {'Режим':<12} {'Операция':<10} {'Среднее время (сек)':<20}")
for row in results[1:]:
struct, mode, op, t1, t2, t3, t4, t5, avg = row
print(f"{struct:<15} {mode:<12} {op:<10} {avg:<20.6f}")
return results
def create_report_table(results):
"""Создание сводной таблицы"""
print("СВОДНАЯ ТАБЛИЦА (среднее время в секундах)")
print(f"{'Структура':<12} {'Режим':<12} {'Вставка':<12} {'Поиск':<12} {'Удаление':<12}")
summary = {}
for row in results[1:]:
struct, mode, op, _, _, _, _, _, avg = row
key = (struct, mode)
if key not in summary:
summary[key] = {}
summary[key][op] = avg
names = {'linked_list': 'LinkedList', 'hash_table': 'HashTable', 'bst': 'BST'}
for (struct, mode), ops in summary.items():
print(f"{names[struct]:<12} {mode:<12} {ops.get('вставка', 0):<12.6f} {ops.get('поиск', 0):<12.6f} {ops.get('удаление', 0):<12.6f}")
def print_analysis():
"""вывод краткого анализа"""
print("АНАЛИЗ РЕЗУЛЬТАТОВ")
print("""
1. Влияние порядка данных на BST:
- На случайных данных: быстро O(log n)
- На отсортированных: деградация до O(n) (дерево вырождается в список)
2. Хеш-таблица не чувствительна к порядку:
- Хеш-функция случайно распределяет данные по bucket'ам
- Порядок вставки не влияет на время операций
3. Связный список всегда медленен при поиске:
- Поиск требует последовательного прохода O(n)
- Нет индексов или сортировки для ускорения
4. Сравнение удаления:
- Связный список: O(n) нужен поиск элемента
- Хеш-таблица: O(1) прямой доступ по индексу
- BST: O(log n) в среднем, O(n) на отсортированных
5. Рекомендация для реальных задач:
- Хеш-таблица: частый поиск, словари, кэши
- BST (сбалансированный): нужны отсортированные данные
- Связный список: маленькие объёмы, очереди/стеки
- Для телефонного справочника ЛУЧШЕ: ХЕШ-ТАБЛИЦА
""")
def create_graphs(results):
"""Построение столбчатых диаграмм"""
import matplotlib.pyplot as plt
import numpy as np
data = {}
for row in results[1:]:
struct = row[0]
mode = row[1]
op = row[2]
avg = row[8]
if struct not in data:
data[struct] = {}
if mode not in data[struct]:
data[struct][mode] = {}
data[struct][mode][op] = avg
# Настройки
struct_names = {'linked_list': 'LinkedList', 'hash_table': 'HashTable', 'bst': 'BST'}
colors = {'linked_list': '#3498db', 'hash_table': '#2ecc71', 'bst': '#e74c3c'}
modes = ['случайный', 'отсортированный']
operations = ['вставка', 'поиск', 'удаление']
op_titles = ['Вставка (10000 записей)', 'Поиск (110 запросов)', 'Удаление (50 записей)']
fig, axes = plt.subplots(1, 3, figsize=(14, 5))
fig.suptitle('Сравнение производительности структур данных', fontsize=14, fontweight='bold')
for idx, (op, title) in enumerate(zip(operations, op_titles)):
ax = axes[idx]
x = np.arange(len(modes))
width = 0.25
multiplier = 0
for struct in ['linked_list', 'hash_table', 'bst']:
values = [data[struct][mode][op] for mode in modes]
bars = ax.bar(x + multiplier * width, values, width,
label=struct_names[struct], color=colors[struct])
for bar, val in zip(bars, values):
if val < 0.001:
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height(),
f'{val:.6f}', ha='center', va='bottom', fontsize=7)
elif val < 0.01:
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height(),
f'{val:.5f}', ha='center', va='bottom', fontsize=7)
else:
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height(),
f'{val:.3f}', ha='center', va='bottom', fontsize=8)
multiplier += 1
ax.set_title(title)
ax.set_ylabel('Время (сек)')
ax.set_yscale('log')
ax.set_ylim(1e-5, 10)
ax.set_xticks(x + width)
ax.set_xticklabels(['Случайный', 'Отсортированный'])
ax.legend()
ax.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
current_dir = os.path.dirname(__file__)
docs_dir = os.path.dirname(current_dir)
path = os.path.join(docs_dir, 'graphs.png')
plt.savefig(path, dpi=150)
plt.close()
print(f"\nГрафики сохранены: {path}")
return path
if __name__ == "__main__":
results = run_experiment()
create_report_table(results)
create_graphs(results)
print_analysis()
print("ЭКСПЕРИМЕНТ ВЫПОЛНЕН ПОЛНОСТЬЮ!")