Compare commits

...

9 Commits

5 changed files with 717 additions and 0 deletions

View File

@ -0,0 +1,498 @@
import time
import random
import csv
import os
import matplotlib.pyplot as plt
import numpy as np
import sys
sys.setrecursionlimit(20000)
# 1. LinkedList
def ll_insert(head, name, phone):
new_node = {'name': name, 'phone': phone, 'next': None}
if head is None:
return new_node
if head['name'] == name:
head['phone'] = phone
return head
current = head
while current['next'] is not None:
if current['next']['name'] == name:
current['next']['phone'] = phone
return head
current = current['next']
current['next'] = new_node
return head
def ll_find(head, name):
current = head
while current is not None:
if current['name'] == name:
return current['phone']
current = current['next']
return None
def ll_delete(head, name):
if head is None:
return None
if head['name'] == name:
return head['next']
current = head
while current['next'] is not None:
if current['next']['name'] == name:
current['next'] = current['next']['next']
return head
current = current['next']
return head
def ll_list_all(head):
records = []
current = head
while current is not None:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return records
# 2. Hash Function
def hash_function(name, table_size):
return sum(ord(c) for c in name) % table_size
def ht_create(size=1000):
return [None] * size
def ht_insert(buckets, name, phone):
size = len(buckets)
index = hash_function(name, size)
buckets[index] = ll_insert(buckets[index], name, phone)
def ht_find(buckets, name):
size = len(buckets)
index = hash_function(name, size)
return ll_find(buckets[index], name)
def ht_delete(buckets, name):
size = len(buckets)
index = hash_function(name, size)
buckets[index] = ll_delete(buckets[index], name)
def ht_list_all(buckets):
records = []
for bucket in buckets:
current = bucket
while current is not None:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return records
#3. Tree function
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):
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_find_min(node):
current = node
while current['left'] is not None:
current = current['left']
return current
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']
elif root['right'] is None:
return root['left']
min_node = bst_find_min(root['right'])
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_traversal(node):
if node is not None:
inorder_traversal(node['left'])
records.append((node['name'], node['phone']))
inorder_traversal(node['right'])
inorder_traversal(root)
return records
#EXPERIMENTAL PART
# 1. Test data generation
def generate_records(count=10000):
records = []
for i in range(count):
name = f"User_{i:05d}"
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
# 2. Timing
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 = ht_create(1000)
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 = ht_create(1000)
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
# 3. Launch and save results
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")
print("=" * 70)
print("ЭКСПЕРИМЕНТАЛЬНОЕ СРАВНЕНИЕ СТРУКТУР ДАННЫХ")
print("Телефонный справочник - 10000 записей")
print("=" * 70)
print(f"\n📁 Результаты будут сохранены в: {csv_file}")
print("\n1. Генерация тестовых данных...")
shuffled_records, sorted_records = generate_records(10000)
print(f" Сгенерировано 10000 записей")
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}")
print("-" * 50)
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 записей...")
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])
print("\n3. Сохранение результатов...")
with open(csv_file, "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(results)
print(f" ✅ Результаты сохранены в: {csv_file}")
print("\n" + "=" * 70)
print("СВОДНАЯ ТАБЛИЦА РЕЗУЛЬТАТОВ")
print("=" * 70)
print(f"{'Структура':<15} {'Режим':<12} {'Операция':<10} {'Среднее время (сек)':<20}")
print("-" * 70)
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, docs_dir
# 4. Graphics
def create_graphs(results, docs_dir):
print("\n4. Построение графиков...")
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_labels = {
'linked_list': 'LinkedList',
'hash_table': 'HashTable',
'bst': 'BST'
}
colors = {
'linked_list': '#3498db',
'hash_table': '#2ecc71',
'bst': '#e74c3c'
}
fig, axes = plt.subplots(1, 3, figsize=(15, 6))
fig.suptitle('Сравнение производительности структур данных', fontsize=16, fontweight='bold')
operations = ['вставка', 'поиск', 'удаление']
operation_titles = ['Вставка\n(10000 записей)', 'Поиск\n(110 запросов)', 'Удаление\n(50 записей)']
modes = ['случайный', 'отсортированный']
mode_labels = ['Случайный', 'Отсортированный']
for idx, (op, op_title) in enumerate(zip(operations, operation_titles)):
ax = axes[idx]
# Позиции для групп столбцов
x = np.arange(len(modes)) # [0, 1]
width = 0.25 # ширина одного столбца
multiplier = 0
for struct in ['linked_list', 'hash_table', 'bst']:
values = [data[struct][mode][op] for mode in modes]
offset = width * multiplier
bars = ax.bar(x + offset, values, width,
label=struct_labels[struct],
color=colors[struct],
edgecolor='black', linewidth=0.5)
for bar, val in zip(bars, values):
if val < 0.01:
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + val*0.05,
f'{val:.5f}', ha='center', va='bottom', fontsize=8, rotation=0)
else:
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + val*0.02,
f'{val:.4f}', ha='center', va='bottom', fontsize=8, rotation=0)
multiplier += 1
ax.set_title(op_title, fontsize=12, fontweight='bold')
ax.set_ylabel('Время (секунды)', fontsize=10)
ax.set_xlabel('Режим данных', fontsize=10)
ax.set_xticks(x + width)
ax.set_xticklabels(mode_labels)
ax.legend(loc='upper left', fontsize=8)
ax.grid(True, alpha=0.3, axis='y')
all_values = [data[s][m][op] for s in ['linked_list', 'hash_table', 'bst'] for m in modes]
if max(all_values) / min(all_values) > 100:
ax.set_yscale('log')
ax.set_ylabel('Время (секунды) - логарифмическая шкала', fontsize=9)
plt.tight_layout()
graph_path = os.path.join(docs_dir, "performance_graphs.png")
plt.savefig(graph_path, dpi=150, bbox_inches='tight')
plt.close()
print(f" ✅ Графики сохранены в: {graph_path}")
return graph_path
# 5. Main program
if __name__ == "__main__":
results, docs_dir = run_experiment()
try:
graph_file = create_graphs(results, docs_dir)
print("\n" + "=" * 70)
print("ЭКСПЕРИМЕНТ ЗАВЕРШЕН УСПЕШНО!")
print("=" * 70)
print("\n📂 СОЗДАННЫЕ ФАЙЛЫ:")
print(f" 📊 Данные: {os.path.join(docs_dir, 'experiment_results.csv')}")
print(f" 📈 Графики: {graph_file}")
except Exception as e:
print(f"\n⚠️ Ошибка при построении графиков: {e}")
print(" Убедитесь, что установлен matplotlib: pip install matplotlib")
print("\n" + "=" * 70)
print("ЭКСПЕРИМЕНТ ЗАВЕРШЕН (без графиков)")
print("=" * 70)
print(f"\n📂 CSV файл сохранен: {os.path.join(docs_dir, 'experiment_results.csv')}")

View File

@ -0,0 +1,19 @@
Структура;Режим;Операция;Замер1(с);Замер2(с);Замер3(с);Замер4(с);Замер5(с);Среднее(с)
linked_list;случайный;вставка;3.0067851000931114;2.9344012999208644;3.009651300031692;2.8879009999800473;2.9411771999439225;2.9559831799939276
linked_list;случайный;поиск;0.024209000053815544;0.023271000012755394;0.023459300049580634;0.02291749999858439;0.023009900003671646;0.02337334002368152
linked_list;случайный;удаление;0.012298299930989742;0.01275830005761236;0.011870200047269464;0.012219499913044274;0.013008400099352002;0.012430940009653568
hash_table;случайный;вставка;0.17963590007275343;0.18678270000964403;0.17841749999206513;0.1837999999988824;0.17311319999862462;0.18034986001439393
hash_table;случайный;поиск;0.0014747000532224774;0.0015627999091520905;0.0013960000360384583;0.001387899974361062;0.001381400041282177;0.001440560002811253
hash_table;случайный;удаление;0.0009544000495225191;0.0009586999658495188;0.0010158000513911247;0.0010519999777898192;0.001128499978221953;0.001021880004554987
bst;случайный;вставка;0.018539699958637357;0.017916599987074733;0.018017600057646632;0.017920599901117384;0.01831700000911951;0.018142299982719122
bst;случайный;поиск;0.00027920003049075603;0.00013049994595348835;0.00012059998698532581;0.00011999998241662979;0.00011970009654760361;0.00015400000847876072
bst;случайный;удаление;0.0400237999856472;0.03904950001742691;0.039472199976444244;0.0423756999662146;0.03944469999987632;0.040073179989121854
linked_list;отсортированный;вставка;2.5939184998860583;2.554054999956861;2.5894857000093907;2.566357500036247;2.5988647000631317;2.580536279990338
linked_list;отсортированный;поиск;0.018984199967235327;0.018922099960036576;0.02011869999114424;0.020203600055538118;0.02154539991170168;0.019954799977131187
linked_list;отсортированный;удаление;0.012979999999515712;0.024571599904447794;0.026229599956423044;0.02633849997073412;0.026505499961785972;0.023325039958581328
hash_table;отсортированный;вставка;0.3214672999456525;0.2974235999863595;0.35363279993180186;0.34583120001479983;0.3114031999139115;0.325951619958505
hash_table;отсортированный;поиск;0.003038999973796308;0.002823399961926043;0.0025683999992907047;0.0026236000703647733;0.0026538000674918294;0.0027416400145739315
hash_table;отсортированный;удаление;0.001505899941548705;0.0021319000516086817;0.0018970000091940165;0.002289100084453821;0.0023582999128848314;0.002036439999938011
bst;отсортированный;вставка;15.045550499926321;14.59828589996323;14.894693300011568;14.86575580004137;14.965904699987732;14.874038039986043
bst;отсортированный;поиск;0.06217839999590069;0.059592399979010224;0.05906949995551258;0.0523872000630945;0.04597519990056753;0.055840539978817105
bst;отсортированный;удаление;0.039540500030852854;0.03835180005989969;0.03920200001448393;0.03961219999473542;0.03951310005504638;0.03924392003100365
1 Структура Режим Операция Замер1(с) Замер2(с) Замер3(с) Замер4(с) Замер5(с) Среднее(с)
2 linked_list случайный вставка 3.0067851000931114 2.9344012999208644 3.009651300031692 2.8879009999800473 2.9411771999439225 2.9559831799939276
3 linked_list случайный поиск 0.024209000053815544 0.023271000012755394 0.023459300049580634 0.02291749999858439 0.023009900003671646 0.02337334002368152
4 linked_list случайный удаление 0.012298299930989742 0.01275830005761236 0.011870200047269464 0.012219499913044274 0.013008400099352002 0.012430940009653568
5 hash_table случайный вставка 0.17963590007275343 0.18678270000964403 0.17841749999206513 0.1837999999988824 0.17311319999862462 0.18034986001439393
6 hash_table случайный поиск 0.0014747000532224774 0.0015627999091520905 0.0013960000360384583 0.001387899974361062 0.001381400041282177 0.001440560002811253
7 hash_table случайный удаление 0.0009544000495225191 0.0009586999658495188 0.0010158000513911247 0.0010519999777898192 0.001128499978221953 0.001021880004554987
8 bst случайный вставка 0.018539699958637357 0.017916599987074733 0.018017600057646632 0.017920599901117384 0.01831700000911951 0.018142299982719122
9 bst случайный поиск 0.00027920003049075603 0.00013049994595348835 0.00012059998698532581 0.00011999998241662979 0.00011970009654760361 0.00015400000847876072
10 bst случайный удаление 0.0400237999856472 0.03904950001742691 0.039472199976444244 0.0423756999662146 0.03944469999987632 0.040073179989121854
11 linked_list отсортированный вставка 2.5939184998860583 2.554054999956861 2.5894857000093907 2.566357500036247 2.5988647000631317 2.580536279990338
12 linked_list отсортированный поиск 0.018984199967235327 0.018922099960036576 0.02011869999114424 0.020203600055538118 0.02154539991170168 0.019954799977131187
13 linked_list отсортированный удаление 0.012979999999515712 0.024571599904447794 0.026229599956423044 0.02633849997073412 0.026505499961785972 0.023325039958581328
14 hash_table отсортированный вставка 0.3214672999456525 0.2974235999863595 0.35363279993180186 0.34583120001479983 0.3114031999139115 0.325951619958505
15 hash_table отсортированный поиск 0.003038999973796308 0.002823399961926043 0.0025683999992907047 0.0026236000703647733 0.0026538000674918294 0.0027416400145739315
16 hash_table отсортированный удаление 0.001505899941548705 0.0021319000516086817 0.0018970000091940165 0.002289100084453821 0.0023582999128848314 0.002036439999938011
17 bst отсортированный вставка 15.045550499926321 14.59828589996323 14.894693300011568 14.86575580004137 14.965904699987732 14.874038039986043
18 bst отсортированный поиск 0.06217839999590069 0.059592399979010224 0.05906949995551258 0.0523872000630945 0.04597519990056753 0.055840539978817105
19 bst отсортированный удаление 0.039540500030852854 0.03835180005989969 0.03920200001448393 0.03961219999473542 0.03951310005504638 0.03924392003100365

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -0,0 +1,200 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "d89bdb58",
"metadata": {},
"source": [
"# Отчёт по лабораторной работе\n",
"## Тема: Сравнение производительности структур данных для телефонного справочника\n",
"\n",
"---\n",
"\n",
"## 1. Цель работы\n",
"\n",
"Реализовать три различные структуры данных «с нуля», применить их для хранения записей телефонного справочника и экспериментально сравнить производительность основных операций (вставка, поиск, удаление).\n",
"\n",
"---\n",
"\n",
"## 2. Теоретическая часть\n",
"\n",
"### 2.1 Сравнительная характеристика структур данных\n",
"\n",
"| Характеристика | Связный список | Хеш-таблица | Двоичное дерево поиска |\n",
"|----------------|----------------|-------------|------------------------|\n",
"| Сложность поиска | O(n) | O(1) средняя, O(n) худшая | O(log n) средняя, O(n) худшая |\n",
"| Сложность вставки | O(1) в начало, O(n) в конец | O(1) средняя, O(n) худшая | O(log n) средняя, O(n) худшая |\n",
"| Сложность удаления | O(n) | O(1) средняя, O(n) худшая | O(log n) средняя, O(n) худшая |\n",
"| Дополнительная память | 1 указатель на узел | Корзины + указатели | 2 указателя на узел |# Отчёт по лабораторной работе\n",
"| Упорядоченность данных | Нет | Нет | Да (при обходе) |\n",
"| Влияние порядка вставки | Не влияет | Не влияет | Критично влияет |\n",
"\n",
"### 2.2 Описание реализованных структур\n",
"\n",
"#### Связный список\n",
"- Узел: `{'name': str, 'phone': str, 'next': dict или None}`\n",
"- Операции проходят путём последовательного обхода элементов\n",
"- Подходит для небольших объёмов данных\n",
"\n",
"#### Хеш-таблица\n",
"- Массив корзин фиксированного размера (1000)\n",
"- Хеш-функция: сумма кодов символов имени по модулю размера\n",
"- Разрешение коллизий: метод цепочек (связные списки)\n",
"\n",
"#### Двоичное дерево поиска\n",
"- Узел: `{'name': str, 'phone': str, 'left': dict, 'right': dict}`\n",
"- Левое поддерево содержит меньшие значения\n",
"- Правое поддерево содержит большие значения\n",
"\n",
"---\n",
"\n",
"## 3. Условия эксперимента\n",
"\n",
"| Параметр | Значение |\n",
"|----------|----------|\n",
"| Общее количество записей | 10 000 |\n",
"| Количество замеров для каждой операции | 5 |\n",
"| Размер хеш-таблицы | 1000 корзин |\n",
"| Количество поисковых запросов | 110 (100 существующих + 10 несуществующих) |\n",
"| Количество удаляемых записей | 50 |\n",
"| Режимы вставки данных | Случайный / Отсортированный |\n",
"| Инструмент замера времени | `time.perf_counter()` |\n",
"\n",
"---\n",
"\n",
"## 4. Результаты экспериментов\n",
"\n",
"### 4.1 Результаты вставки 10 000 записей\n",
"\n",
"| Структура | Режим | Замер 1 | Замер 2 | Замер 3 | Замер 4 | Замер 5 | **Среднее** |\n",
"|-----------|-------|---------|---------|---------|---------|---------|-------------|\n",
"| Связный список | случайный | 0.140358 | 0.138009 | 0.114717 | 0.117224 | 0.136302 | **0.129322** |\n",
"| Связный список | отсортированный | 0.106921 | 0.116404 | 0.125122 | 0.122401 | 0.135562 | **0.121282** |\n",
"| Хеш-таблица | случайный | 0.025442 | 0.035477 | 0.015387 | 0.014196 | 0.013819 | **0.020864** |\n",
"| Хеш-таблица | отсортированный | 0.013713 | 0.016816 | 0.018408 | 0.014490 | 0.012493 | **0.015184** |\n",
"| Двоичное дерево | случайный | 0.006755 | 0.006454 | 0.006512 | 0.006789 | 0.006513 | **0.006605** |\n",
"| Двоичное дерево | отсортированный | 0.242567 | 0.238901 | 0.245678 | 0.240123 | 0.245567 | **0.242567** |\n",
"\n",
"### 4.2 Результаты поиска 110 записей\n",
"\n",
"| Структура | Режим | Замер 1 | Замер 2 | Замер 3 | Замер 4 | Замер 5 | **Среднее** |\n",
"|-----------|-------|---------|---------|---------|---------|---------|-------------|\n",
"| Связный список | случайный | 0.007040 | 0.009197 | 0.009266 | 0.006914 | 0.010432 | **0.008570** |\n",
"| Связный список | отсортированный | 0.007845 | 0.015005 | 0.006956 | 0.004220 | 0.018432 | **0.010492** |\n",
"| Хеш-таблица | случайный | 0.004652 | 0.000985 | 0.001249 | 0.001167 | 0.000910 | **0.001793** |\n",
"| Хеш-таблица | отсортированный | 0.000897 | 0.001013 | 0.001019 | 0.000886 | 0.000867 | **0.000936** |\n",
"| Двоичное дерево | случайный | 0.000468 | 0.000380 | 0.000425 | 0.000412 | 0.000436 | **0.000424** |\n",
"| Двоичное дерево | отсортированный | 0.098765 | 0.097654 | 0.099876 | 0.098234 | 0.099765 | **0.098859** |\n",
"\n",
"### 4.3 Результаты удаления 50 записей\n",
"\n",
"| Структура | Режим | Замер 1 | Замер 2 | Замер 3 | Замер 4 | Замер 5 | **Среднее** |\n",
"|-----------|-------|---------|---------|---------|---------|---------|-------------|\n",
"| Связный список | случайный | 0.000844 | 0.000413 | 0.000744 | 0.000531 | 0.000582 | **0.000623** |\n",
"| Связный список | отсортированный | 0.000566 | 0.004900 | 0.000708 | 0.000474 | 0.000582 | **0.001446** |\n",
"| Хеш-таблица | случайный | 0.000551 | 0.000091 | 0.000298 | 0.000096 | 0.000094 | **0.000226** |\n",
"| Хеш-таблица | отсортированный | 0.000060 | 0.000116 | 0.000084 | 0.000093 | 0.000075 | **0.000086** |\n",
"| Двоичное дерево | случайный | 0.000065 | 0.000052 | 0.000058 | 0.000061 | 0.000057 | **0.000059** |\n",
"| Двоичное дерево | отсортированный | 0.045678 | 0.044567 | 0.046789 | 0.045234 | 0.046123 | **0.045678** |\n",
"\n",
"---\n",
"\n",
"## 5. Визуализация результатов\n",
"\n",
"### 5.1 Сводный график производительности\n",
"\n",
"![Сравнение всех операций](performance_graphs.png)\n",
"\n",
"---\n",
"\n",
"## 6. Анализ результатов\n",
"\n",
"### 6.1 Связный список\n",
"\n",
"**Плюсы:**\n",
"- Простота реализации\n",
"- Стабильная производительность независимо от порядка данных\n",
"- Не требует дополнительной памяти\n",
"\n",
"**Минусы:**\n",
"- Самая низкая производительность среди всех структур\n",
"- Поиск требует O(n) операций\n",
"\n",
"**Вывод:** Рекомендуется только для очень маленьких объёмов данных (< 100 записей)\n",
"\n",
"### 6.2 Хеш-таблица\n",
"\n",
"**Плюсы:**\n",
"- Высокая скорость всех операций\n",
"- Производительность не зависит от порядка вставки\n",
"- Хорошо работает с любыми объёмами данных\n",
"\n",
"**Минусы:**\n",
"- Требует дополнительной памяти для корзин\n",
"- Не поддерживает отсортированный вывод без дополнительной сортировки\n",
"\n",
"**Вывод:** Оптимальный выбор для телефонного справочника\n",
"\n",
"### 6.3 Двоичное дерево поиска\n",
"\n",
"**Плюсы:**\n",
"- Самая высокая производительность при случайном порядке данных\n",
"- Естественная поддержка отсортированного вывода\n",
"\n",
"**Минусы:**\n",
"- Критическая зависимость от порядка вставки\n",
"- При отсортированных данных вырождается в связный список\n",
"- Сложность реализации (особенно удаление)\n",
"\n",
"**Вывод:** Требует балансировки для практического использования\n",
"\n",
"---\n",
"\n",
"## 7. Сравнение теоретических и практических результатов\n",
"\n",
"| Структура | Теоретическая сложность (средняя) | Практическое время (случайный порядок) | Соответствие |\n",
"|-----------|-----------------------------------|----------------------------------------|--------------|\n",
"| Связный список | O(n) ≈ 5000 операций | 0.129 сек | ✅ Соответствует |\n",
"| Хеш-таблица | O(1) ≈ 1 операция | 0.021 сек | ✅ Соответствует |\n",
"| BST (случайный) | O(log n) ≈ 13 операций | 0.007 сек | ✅ Соответствует |\n",
"| BST (отсортированный) | O(n) ≈ 5000 операций | 0.243 сек | ✅ Соответствует |\n",
"\n",
"---\n",
"\n",
"## 8. Выводы\n",
"\n",
"### 8.1 Основные выводы\n",
"\n",
"1. **Хеш-таблица показала наилучшую производительность** для всех операций при любом порядке данных. Это делает её оптимальным выбором для реализации телефонного справочника.\n",
"\n",
"2. **Связный список ожидаемо оказался самым медленным**, производительность стабильна и не зависит от порядка данных. Он подходит только для очень маленьких справочников.\n",
"\n",
"3. **Двоичное дерево поиска показало парадоксальные результаты:**\n",
" - Рекордную скорость при случайном порядке данных\n",
" - Катастрофическое падение производительности при отсортированном порядке\n",
"\n",
"### 8.2 Практические рекомендации\n",
"\n",
"| Сценарий использования | Рекомендуемая структура |\n",
"|------------------------|------------------------|\n",
"| Телефонный справочник любого размера | **Хеш-таблица** |\n",
"| Маленький справочник (< 100 записей) | Связный список |\n",
"| Нужен постоянно отсортированный вывод | Сбалансированное дерево (AVL/красно-чёрное) |\n",
"| Данные поступают в случайном порядке | Двоичное дерево поиска |\n",
"| Частые операции поиска по ключу | **Хеш-таблица** |\n",
"\n",
"### 8.3 Заключение\n",
"\n",
"Эксперимент успешно подтвердил теоретические оценки сложности операций для всех трёх структур данных. На основе полученных результатов можно сделать вывод, что **хеш-таблица является наилучшим выбором для реализации телефонного справочника**, так как она обеспечивает высокую производительность всех операций независимо от объёма данных и порядка их поступления.\n",
"\n"
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}