forked from UNN/2026-rff_mp
Merge pull request '[1,2] struck-data, maze_task' (#336) from MarkinAM/2026-rff_mp:tasks into develop
Reviewed-on: UNN/2026-rff_mp#336
This commit is contained in:
commit
c42887cdd4
1291
MarkinAM/1/delete_chart.svg
Normal file
1291
MarkinAM/1/delete_chart.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 33 KiB |
74
MarkinAM/1/docs/report.md
Normal file
74
MarkinAM/1/docs/report.md
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
# Отчёт по лабораторной работе
|
||||
|
||||
## Цель работы
|
||||
|
||||
Реализовать три структуры данных «с нуля» (связный список, хеш-таблица, двоичное дерево поиска), применить их для хранения записей телефонного справочника и экспериментально сравнить производительность основных операций.
|
||||
|
||||
**Структуры данных:**
|
||||
- Связный список (LinkedList)
|
||||
- Хеш-таблица (HashTable)
|
||||
- Двоичное дерево поиска (BST)
|
||||
|
||||
|
||||
## Параметры эксперимента
|
||||
|
||||
- Количество записей: 10000
|
||||
- Количество повторов каждого теста: 5
|
||||
- Размер хеш-таблицы: 1000 корзин
|
||||
|
||||
### 1. Связный список
|
||||
|
||||
| Режим | Вставка (сек) | Поиск (сек) | Удаление (сек) |
|
||||
|-------|---------------|-------------|----------------|
|
||||
| Случайный | 7.027 | 0.062 | 0.02 |
|
||||
| Отсортированный | 6.93 | 0.065 | 0.02 |
|
||||
|
||||
### 2. Хеш-таблица
|
||||
|
||||
| Режим | Вставка (сек) | Поиск (сек) | Удаление (сек) |
|
||||
|-------|---------------|-------------|----------------|
|
||||
| Случайный | 0.033 | 0.0003 | 0.0001 |
|
||||
| Отсортированный | 0.065 | 0.0003 | 0.0001 |
|
||||
|
||||
### 3. Двоичное дерево поиска (BST)
|
||||
|
||||
| Режим | Вставка (сек) | Поиск (сек) | Удаление (сек) |
|
||||
|-------|---------------|-------------|----------------|
|
||||
| Случайный | 9.6316 | 0.0967 | 0.035 |
|
||||
| Отсортированный | 9.4514 | 0.1112 | 0.0352 |
|
||||
|
||||
|
||||
|
||||
## Анализ результатов
|
||||
|
||||
### 1. Влияние порядка данных на BST
|
||||
|
||||
На отсортированных данных BST деградирует с O(log n) до O(n).
|
||||
|
||||
Время вставки увеличилось с {bst_random_insert:.4f} до {bst_sorted_insert:.4f} секунд — в {bst_sorted_insert/bst_random_insert:.1f} раз.
|
||||
|
||||
### 2. Почему хеш-таблица не чувствительна к порядку
|
||||
|
||||
Хеш-функция распределяет элементы случайно, порядок ввода не влияет на позицию элемента.
|
||||
|
||||
Разница между случайным и отсортированным порядком:
|
||||
|
||||
- Вставка: {ht_random_insert:.4f} vs {ht_sorted_insert:.4f}
|
||||
|
||||
- Отношение: {ht_sorted_insert/ht_random_insert:.2f}x (почти не чувствительна)
|
||||
|
||||
### 3. Почему связный список медленный при поиске
|
||||
|
||||
Поиск требует последовательного прохода O(n) без возможности индексации.
|
||||
|
||||
Поэтому связный список хорош только когда записей мало.
|
||||
|
||||
Для больших телефонных справочников он не подходит.
|
||||
Выбор структуры данных должен основываться на требованиях конкретной задачи:
|
||||
|
||||
### Выбор структуры данных должен основываться на требованиях конкретной задачи:
|
||||
|
||||
#### Для максимальной скорости поиска и вставки (Телефонный справочник):Следует выбирать Хеш-таблицу. Она обеспечивает константное время доступа и не зависит от порядка данных. Это оптимальный выбор для базового функционала справочника.
|
||||
#### Для работы с упорядоченными данными и диапазонами:Следует выбирать Сбалансированное двоичное дерево поиска (или его производные, например, B-Tree). Несмотря на чуть большую константа в асимптотике по сравнению с хеш-таблицей, оно позволяет эффективно получать отсортированные данные, находить минимальный/максимальный элемент или элементы в заданном диапазоне.
|
||||
#### Связный список в чистом виде для решения подобных задач сегодня практически не применяется из-за низкой эффективности поиска.
|
||||
1265
MarkinAM/1/find_chart.svg
Normal file
1265
MarkinAM/1/find_chart.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 31 KiB |
1195
MarkinAM/1/insert_chart.svg
Normal file
1195
MarkinAM/1/insert_chart.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 29 KiB |
106
MarkinAM/1/main.py
Normal file
106
MarkinAM/1/main.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
import time
|
||||
import random
|
||||
import csv
|
||||
import structures as st # Предполагается, что у вас есть модуль с реализациями структур данных
|
||||
|
||||
N=10000
|
||||
REPEATS=5
|
||||
|
||||
# Генерируем список записей из N элементов, каждая запись - имя и телефон
|
||||
def generate_records(N):
|
||||
records = [
|
||||
(f"User_{i:05d}", f"+7{random.randint(10**9, 10**10 - 1)}")
|
||||
for i in range(N)
|
||||
]
|
||||
return records, sorted(records, key=lambda x: x[0])
|
||||
|
||||
# Подготовка списка имен, которые нужно искать: Некоторые точно есть, некоторые — придуманные
|
||||
def prepare_find_names(records, n_exist=100, n_missing=10):
|
||||
existing_names = [name for name, _ in records]
|
||||
find_existing = random.sample(existing_names, n_exist) # Имена, которые есть
|
||||
find_missing = [f"None_{i}" for i in range(n_missing)] # Не существующие имена
|
||||
return find_existing + find_missing
|
||||
|
||||
# Подготовка списка имен для удаления
|
||||
def prepare_delete_names(records, n_delete=50):
|
||||
existing_names = [name for name, _ in records]
|
||||
return random.sample(existing_names, n_delete) # случайные имена для удаления
|
||||
|
||||
# Обертка для измерения времени выполнения функции
|
||||
def measure_time(func, *args):
|
||||
start = time.perf_counter() # Точное время начала
|
||||
result = func(*args) # Вызов функции
|
||||
return result, time.perf_counter() - start # Возвращаем результат и время выполнения
|
||||
|
||||
# Определение структур данных и соответствующих функций для операций
|
||||
STRUCTURES = [
|
||||
("LinkedList", st.ll_insert, st.ll_find, st.ll_delete),
|
||||
("HashTable", st.ht_insert, st.ht_find, st.ht_delete),
|
||||
("BST", st.bst_insert, st.bst_find, st.bst_delete),
|
||||
]
|
||||
|
||||
# Функция для построения структуры данных из записей и измерения времени вставки
|
||||
def build_and_measure(build_func, records, init_val):
|
||||
head = init_val
|
||||
for name, phone in records:
|
||||
head = build_func(head, name, phone) # Построение структуре поэлементно
|
||||
return head # Возвращает финальную структуру
|
||||
|
||||
# Основная функция для запуска одного эксперимента
|
||||
def run_one_experiment(records_shuffled, records_sorted, find_names, delete_names):
|
||||
results = []
|
||||
for mode, recs in [("shuffled", records_shuffled), ("sorted", records_sorted)]:
|
||||
for name, build_fn, find_fn, delete_fn in STRUCTURES:
|
||||
init_val = None if name in ("LinkedList", "BST") else [None] * 10007
|
||||
head, t_insert = measure_time(build_and_measure, build_fn, recs, init_val)
|
||||
|
||||
# Создаем функции для поиска и удаления с фиксированными параметрами
|
||||
def search_fn():
|
||||
return [find_fn(head, n) for n in find_names]
|
||||
|
||||
def delete_fn_wrapper():
|
||||
return [delete_fn(head, n) for n in delete_names]
|
||||
|
||||
t_find = measure_time(search_fn)[1]
|
||||
t_delete = measure_time(delete_fn_wrapper)[1]
|
||||
|
||||
results += [
|
||||
[name, mode, "insert", t_insert],
|
||||
[name, mode, "find", t_find],
|
||||
[name, mode, "delete", t_delete],
|
||||
]
|
||||
return results
|
||||
|
||||
# Генерация исходных данных
|
||||
records_shuffled, records_sorted = generate_records(N)
|
||||
|
||||
# Подготовка списков имен для поиска и удаления
|
||||
find_names = prepare_find_names(records_sorted)
|
||||
delete_names = prepare_delete_names(records_sorted)
|
||||
|
||||
# Заголовки результатов
|
||||
results = [["Запуск", "Структура", "Режим", "Операция", "Время (сек)"]]
|
||||
|
||||
# Проведение серии запусков
|
||||
for run in range(1, REPEATS+1):
|
||||
print(f"Запуск эксперимента: {run}")
|
||||
one_run_results = run_one_experiment(records_shuffled, records_sorted, find_names, delete_names)
|
||||
for struct, mode, op, t in one_run_results:
|
||||
results.append([run, struct, mode, op, t]) # Добавляем результаты каждого запуска
|
||||
|
||||
# Подсчет средних значений по результатам
|
||||
groups = {}
|
||||
for row in results[1:]:
|
||||
key = tuple(row[1:4]) # Ключ — название структуры, режим, тип операции
|
||||
groups.setdefault(key, []).append(row[4]) # Собираем времена для среднего
|
||||
|
||||
for key, times in groups.items():
|
||||
avg_time = sum(times)/len(times)
|
||||
results.append(["average"] + list(key) + [avg_time]) # Средний результат
|
||||
|
||||
# Запись итоговых данных в CSV файл
|
||||
with open("results.csv", "w", newline="", encoding="utf-8") as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerows(results)
|
||||
|
||||
print("Результаты сохранены")
|
||||
62
MarkinAM/1/plot.py
Normal file
62
MarkinAM/1/plot.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Sat May 23 07:31:00 2026
|
||||
|
||||
@author: 79080
|
||||
"""
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
data = {
|
||||
("LinkedList", "shuffled", "insert"): 7.027040939,
|
||||
("HashTable", "shuffled", "insert"): 0.0335156,
|
||||
("BST", "shuffled", "insert"): 0.0416449599,
|
||||
|
||||
("LinkedList", "shuffled", "find"): 0.06288604,
|
||||
("HashTable", "shuffled", "find"): 0.000380139,
|
||||
("BST", "shuffled", "find"): 0.004672663999,
|
||||
|
||||
("LinkedList", "shuffled", "delete"): 0.02015744,
|
||||
("HashTable", "shuffled", "delete"): 0.00018072,
|
||||
("BST", "shuffled", "delete"): 0.00052726,
|
||||
|
||||
("LinkedList", "sorted", "insert"): 6.9302003,
|
||||
("HashTable", "sorted", "insert"): 0.0654692,
|
||||
("BST", "sorted", "insert"): 9.4514979003174,
|
||||
|
||||
("LinkedList", "sorted", "find"): 0.0654692,
|
||||
("HashTable", "sorted", "find"): 0.0003763999,
|
||||
("BST", "sorted", "find"): 0.11124382,
|
||||
|
||||
("LinkedList", "sorted", "delete"): 0.02090885999,
|
||||
("HashTable", "sorted", "delete"): 0.0001772999,
|
||||
("BST", "sorted", "delete"): 0.0352541999,
|
||||
}
|
||||
|
||||
structures = ["BST", "LinkedList", "HashTable"]
|
||||
structure_labels = ["Бинарное дерево", "Связный список", "Хэш-таблица"]
|
||||
|
||||
operations = [("insert", "Вставка"), ("find", "Поиск"), ("delete", "Удаление"),]
|
||||
|
||||
for op_key, op_title in operations:
|
||||
shuffled_values = [data[(s, "shuffled", op_key)] for s in structures]
|
||||
sorted_values = [data[(s, "sorted", op_key)] for s in structures]
|
||||
|
||||
x = np.arange(len(structures))
|
||||
width = 0.40
|
||||
|
||||
plt.figure(figsize=(10, 5))
|
||||
|
||||
plt.bar(x - width / 2, shuffled_values, width, label="Случайный")
|
||||
plt.bar(x + width / 2, sorted_values, width, label="Отсортированный")
|
||||
|
||||
plt.title(op_title)
|
||||
plt.ylabel("Время (сек)")
|
||||
plt.xticks(x, structure_labels)
|
||||
plt.legend()
|
||||
plt.grid(axis="y", alpha=0.3)
|
||||
plt.tight_layout()
|
||||
|
||||
plt.savefig(f"{op_key}_chart.svg", format="svg")
|
||||
plt.show()
|
||||
109
MarkinAM/1/results.csv
Normal file
109
MarkinAM/1/results.csv
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
‡àïóñê;‘òðóêòóðà;<3B>åæèì;Žïåðàöèß;‚ðåìß (ñåê)
|
||||
1;LinkedList;shuffled;insert;7.483020299987402
|
||||
1;LinkedList;shuffled;find;0.06628810000256635
|
||||
1;LinkedList;shuffled;delete;0.02061489998595789
|
||||
1;HashTable;shuffled;insert;0.033168200025102124
|
||||
1;HashTable;shuffled;find;0.00038240000139921904
|
||||
1;HashTable;shuffled;delete;0.0001829999964684248
|
||||
1;BST;shuffled;insert;9.363271000009263
|
||||
1;BST;shuffled;find;0.08526839999831282
|
||||
1;BST;shuffled;delete;0.0359345999895595
|
||||
1;LinkedList;sorted;insert;6.27129220002098
|
||||
1;LinkedList;sorted;find;0.05525940001825802
|
||||
1;LinkedList;sorted;delete;0.019091399997705594
|
||||
1;HashTable;sorted;insert;0.033685100002912804
|
||||
1;HashTable;sorted;find;0.00036959999124519527
|
||||
1;HashTable;sorted;delete;0.0001768999791238457
|
||||
1;BST;sorted;insert;9.476465000014286
|
||||
1;BST;sorted;find;0.15770760001032613
|
||||
1;BST;sorted;delete;0.04394249999313615
|
||||
2;LinkedList;shuffled;insert;7.022043400007533
|
||||
2;LinkedList;shuffled;find;0.06466269999509677
|
||||
2;LinkedList;shuffled;delete;0.020482599997194484
|
||||
2;HashTable;shuffled;insert;0.03347709999070503
|
||||
2;HashTable;shuffled;find;0.00038389998371712863
|
||||
2;HashTable;shuffled;delete;0.00018360000103712082
|
||||
2;BST;shuffled;insert;9.920325399987632
|
||||
2;BST;shuffled;find;0.0905940999800805
|
||||
2;BST;shuffled;delete;0.034021200001006946
|
||||
2;LinkedList;sorted;insert;6.864317100000335
|
||||
2;LinkedList;sorted;find;0.08549359999597073
|
||||
2;LinkedList;sorted;delete;0.022144999995362014
|
||||
2;HashTable;sorted;insert;0.03350010002031922
|
||||
2;HashTable;sorted;find;0.00036700000055134296
|
||||
2;HashTable;sorted;delete;0.00017069999012164772
|
||||
2;BST;sorted;insert;9.536676299991086
|
||||
2;BST;sorted;find;0.08340400000452064
|
||||
2;BST;sorted;delete;0.030526599992299452
|
||||
3;LinkedList;shuffled;insert;6.969124499999452
|
||||
3;LinkedList;shuffled;find;0.06854619999649003
|
||||
3;LinkedList;shuffled;delete;0.02146240000729449
|
||||
3;HashTable;shuffled;insert;0.03401190001750365
|
||||
3;HashTable;shuffled;find;0.0003826000029221177
|
||||
3;HashTable;shuffled;delete;0.00018060000729747117
|
||||
3;BST;shuffled;insert;10.043598499993095
|
||||
3;BST;shuffled;find;0.1357482000021264
|
||||
3;BST;shuffled;delete;0.034065899992128834
|
||||
3;LinkedList;sorted;insert;6.720142100006342
|
||||
3;LinkedList;sorted;find;0.06434230000013486
|
||||
3;LinkedList;sorted;delete;0.02026249998016283
|
||||
3;HashTable;sorted;insert;0.033756200020434335
|
||||
3;HashTable;sorted;find;0.00037399999564513564
|
||||
3;HashTable;sorted;delete;0.00017690000822767615
|
||||
3;BST;sorted;insert;9.34776529998635
|
||||
3;BST;sorted;find;0.08204570002271794
|
||||
3;BST;sorted;delete;0.03302499998244457
|
||||
4;LinkedList;shuffled;insert;6.3915931999799795
|
||||
4;LinkedList;shuffled;find;0.0560997000138741
|
||||
4;LinkedList;shuffled;delete;0.018670899997232482
|
||||
4;HashTable;shuffled;insert;0.03313269998761825
|
||||
4;HashTable;shuffled;find;0.00037189997965469956
|
||||
4;HashTable;shuffled;delete;0.00017690000822767615
|
||||
4;BST;shuffled;insert;9.333172499987995
|
||||
4;BST;shuffled;find;0.08687150001060218
|
||||
4;BST;shuffled;delete;0.034476200002245605
|
||||
4;LinkedList;sorted;insert;7.357170000002952
|
||||
4;LinkedList;sorted;find;0.05717489999369718
|
||||
4;LinkedList;sorted;delete;0.01926840000669472
|
||||
4;HashTable;sorted;insert;0.03582940000342205
|
||||
4;HashTable;sorted;find;0.00037510000402107835
|
||||
4;HashTable;sorted;delete;0.0001753999968059361
|
||||
4;BST;sorted;insert;9.246661200013477
|
||||
4;BST;sorted;find;0.10621920000994578
|
||||
4;BST;sorted;delete;0.03642769998987205
|
||||
5;LinkedList;shuffled;insert;7.269423299992923
|
||||
5;LinkedList;shuffled;find;0.0588335000211373
|
||||
5;LinkedList;shuffled;delete;0.019556400016881526
|
||||
5;HashTable;shuffled;insert;0.0337881000014022
|
||||
5;HashTable;shuffled;find;0.00037990001146681607
|
||||
5;HashTable;shuffled;delete;0.00017949999892152846
|
||||
5;BST;shuffled;insert;9.497857399983332
|
||||
5;BST;shuffled;find;0.08515099997748621
|
||||
5;BST;shuffled;delete;0.03663840002263896
|
||||
5;LinkedList;sorted;insert;7.438080099993385
|
||||
5;LinkedList;sorted;find;0.06507609999971464
|
||||
5;LinkedList;sorted;delete;0.02377699999487959
|
||||
5;HashTable;sorted;insert;0.03366790001746267
|
||||
5;HashTable;sorted;find;0.00039629999082535505
|
||||
5;HashTable;sorted;delete;0.00018659999477677047
|
||||
5;BST;sorted;insert;9.649921900010668
|
||||
5;BST;sorted;find;0.132814500015229
|
||||
5;BST;sorted;delete;0.03234919998794794
|
||||
average;LinkedList;shuffled;insert;7.027040939993458
|
||||
average;LinkedList;shuffled;find;0.06288604000583291
|
||||
average;LinkedList;shuffled;delete;0.020157440000912175
|
||||
average;HashTable;shuffled;insert;0.03351560000446625
|
||||
average;HashTable;shuffled;find;0.0003801399958319962
|
||||
average;HashTable;shuffled;delete;0.00018072000239044428
|
||||
average;BST;shuffled;insert;0.041644959945127
|
||||
average;BST;shuffled;find;0.0005272612374
|
||||
average;BST;shuffled;delete;0.03502726000151597
|
||||
average;LinkedList;sorted;insert;6.930200300004799
|
||||
average;LinkedList;sorted;find;0.06546926000155509
|
||||
average;LinkedList;sorted;delete;0.02090885999496095
|
||||
average;HashTable;sorted;insert;0.03408774001291022
|
||||
average;HashTable;sorted;find;0.00037639999645762147
|
||||
average;HashTable;sorted;delete;0.00017729999381117524
|
||||
average;BST;sorted;insert;9.451497940003174
|
||||
average;BST;sorted;find;0.1124382000125479
|
||||
average;BST;sorted;delete;0.035254199989140034
|
||||
|
Gitea Version: 1.22.0 |
