[1] zadanie_1

This commit is contained in:
zverevem 2026-05-14 13:18:29 +03:00
parent a2621ad508
commit 8468109b7c
10 changed files with 906 additions and 0 deletions

View File

@ -0,0 +1,282 @@
import random
import time
import csv
import os
from phonebook import *
def generate_test_data(n=10000):
records = [(f"User_{i:05d}", f"+7-999-{i:07d}") for i in range(n)]
records_shuffled = records.copy()
random.shuffle(records_shuffled)
records_sorted = sorted(records, key=lambda x: x[0])
return records_shuffled, records_sorted
def get_random_names(records, n=100):
return[name for name, _ in random.sample(records, min(n, len(records)))]
def run_linked_experiments(records, mode_name):
print(f"\n связный список ({mode_name}):")
print("вставка 10000 записей:")
insert_times = []
for run in range(5):
start = time.perf_counter()
head = None
for name, phone in records:
head = ll_insert(head, name, phone)
end = time.perf_counter()
insert_times.append(end - start)
print(f"Вставка {run+1}/5: {insert_times[-1]:.6f} сек")
avg_insert = sum(insert_times) / 5
print(f"среднее: {avg_insert:.6f} сек")
print("поиск 110 записей:")
exist_names = get_random_names(records, 100)
non_exist_names = [f"None_{i}" for i in range(10)]
find_times = []
for run in range(5):
start = time.perf_counter()
for name in exist_names:
ll_find(head, name)
for name in non_exist_names:
ll_find(head, name)
end = time.perf_counter()
find_times.append(end - start)
print(f"поиск {run+1}/5: {find_times[-1]:.6f} сек")
avg_find = sum(find_times) / 5
print(f"среднее: {avg_find:.6f} сек")
print("удаление 50 случайных записей:")
to_delete = get_random_names(records,50)
delete_times = []
for run in range(5):
current_head = head
start = time.perf_counter()
for name in to_delete:
current_head = ll_delete(current_head, name)
end = time.perf_counter()
delete_times.append(end - start)
print(f"удаление {run+1}/5: {delete_times[-1]:.6f} сек")
avg_delete = sum(delete_times) / 5
print(f"среднее: {avg_delete:.6f} сек")
return{
'structure': 'LinkedList',
'mode': mode_name,
'insert_avg': avg_insert,
'insert_all': insert_times,
'find_avg': avg_find,
'find_all': find_times,
'delete_avg': avg_delete,
'delete_all': delete_times
}
def run_hash_experiments(records, mode_name):
print(f"\n хеш-таблица({mode_name})")
print("вставка 10000 записей:")
insert_times = []
for run in range(5):
start = time.perf_counter()
buckets = ht_create(1000)
for name, phone in records:
buckets = ht_insert(buckets, name, phone)
end = time.perf_counter()
insert_times.append(end - start)
print(f"Вставка {run+1}/5: {insert_times[-1]:.6f} сек")
avg_insert = sum(insert_times) / 5
print(f"среднее: {avg_insert:.6f} сек")
print("поиск 110 записей:")
exist_names = get_random_names(records, 100)
non_exist_names = [f"None_{i}" for i in range(10)]
find_times = []
for run in range(5):
start = time.perf_counter()
for name in exist_names:
ht_find(buckets, name)
for name in non_exist_names:
ht_find(buckets, name)
end = time.perf_counter()
find_times.append(end - start)
print(f"поиск {run+1}/5: {find_times[-1]:.6f} сек")
avg_find = sum(find_times) / 5
print(f"среднее: {avg_find:.6f} сек")
print("удаление 50 случайных записей:")
to_delete = get_random_names(records,50)
delete_times = []
for run in range(5):
current_buckets = buckets.copy()
start = time.perf_counter()
for name in to_delete:
current_buckets = ht_delete(current_buckets, name)
end = time.perf_counter()
delete_times.append(end - start)
print(f"удаление {run+1}/5: {delete_times[-1]:.6f} сек")
avg_delete = sum(delete_times) / 5
print(f"среднее: {avg_delete:.6f} сек")
return{
'structure': 'HashTable',
'mode': mode_name,
'insert_avg': avg_insert,
'insert_all': insert_times,
'find_avg': avg_find,
'find_all': find_times,
'delete_avg': avg_delete,
'delete_all': delete_times
}
def run_bst_experiments(records, mode_name):
print(f"\n двоичное дерево({mode_name})")
print("вставка 10000 записей:")
insert_times = []
for run in range(5):
start = time.perf_counter()
root = None
for name, phone in records:
root = bst_insert(root, name, phone)
end = time.perf_counter()
insert_times.append(end - start)
print(f"Вставка {run+1}/5: {insert_times[-1]:.6f} сек")
avg_insert = sum(insert_times) / 5
print(f"среднее: {avg_insert:.6f} сек")
print("поиск 110 записей:")
exist_names = get_random_names(records, 100)
non_exist_names = [f"None_{i}" for i in range(10)]
find_times = []
for run in range(5):
start = time.perf_counter()
for name in exist_names:
bst_find(root, name)
for name in non_exist_names:
bst_find(root, name)
end = time.perf_counter()
find_times.append(end - start)
print(f"поиск {run+1}/5: {find_times[-1]:.6f} сек")
avg_find = sum(find_times) / 5
print(f"среднее: {avg_find:.6f} сек")
print("удаление 50 случайных записей:")
to_delete = get_random_names(records,50)
delete_times = []
for run in range(5):
current_root = root
start = time.perf_counter()
for name in to_delete:
current_root = bst_delete(current_root, name)
end = time.perf_counter()
delete_times.append(end - start)
print(f"удаление {run+1}/5: {delete_times[-1]:.6f} сек")
avg_delete = sum(delete_times) / 5
print(f"среднее: {avg_delete:.6f} сек")
return{
'structure': 'BST',
'mode': mode_name,
'insert_avg': avg_insert,
'insert_all': insert_times,
'find_avg': avg_find,
'find_all': find_times,
'delete_avg': avg_delete,
'delete_all': delete_times
}
def save_results_to_csv(all_results):
os.makedirs("docs/data", exist_ok=True)
with open("docs/data/results.csv", "w", encoding="utf-8") as f:
f.write("Структура, Режим, Операция, Замер, Время (сек)\n")
for res in all_results:
struct = res['structure']
mode = res['mode']
for i, t in enumerate(res['insert_all']):
f.write(f"{struct},{mode},вставка,{i+1},{t}\n")
f.write(f"{struct},{mode},вставка,среднее,{res['insert_avg']}\n")
for i, t in enumerate(res['find_all']):
f.write(f"{struct},{mode},поиск,{i+1},{t}\n")
f.write(f"{struct},{mode},поиск,среднее,{res['find_avg']}\n")
for i, t in enumerate(res['delete_all']):
f.write(f"{struct},{mode},удаление,{i+1},{t}\n")
f.write(f"{struct},{mode},удаление,среднее,{res['delete_avg']}\n")
def main():
print("эксперименты по замеру производительности")
records_shuffled, records_sorted = generate_test_data(10000)
all_results = []
print("режим: случайный порядок")
all_results.append(run_linked_experiments(records_shuffled, "случайный"))
all_results.append(run_hash_experiments(records_shuffled, "случайный"))
all_results.append(run_bst_experiments(records_shuffled, "случайный"))
print("режим: отсортированный порядок")
all_results.append(run_linked_experiments(records_sorted, "отсортированный"))
all_results.append(run_hash_experiments(records_sorted, "отсортированный"))
all_results.append(run_bst_experiments(records_sorted, "отсортированный"))
save_results_to_csv(all_results)
if __name__== "__main__":
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -0,0 +1,123 @@
import matplotlib.pyplot as plt
import numpy as np
import os
os.makedirs('docs/data', exist_ok=True)
structures = ['LinkedList', 'HashTable', 'BST']
random_insert = [0.0037545, 0.015088, 0.026280]
sorted_insert = [0.0017544, 0.011369, 4.930788]
random_search = [0.00000962, 0.0001646, 0.0002592]
sorted_search = [0.00000858, 0.00014016, 0.047126]
random_delete = [0.0000079, 0.00009824, 0.00016984]
sorted_delete = [0.00000294, 0.00005878, 0.023013]
x = np.arange(len(structures))
width = 0.35
#график вставка
fig, ax = plt.subplots(figsize=(12, 7))
bars1 = ax.bar(x - width/2, random_insert, width, label='Случайный порядок', color='#3498db')
bars2 = ax.bar(x + width/2, sorted_insert, width, label='Отсортированный порядок', color='#e74c3c')
for bar in bars1:
height = bar.get_height()
ax.annotate(f'{height:.4f}', xy=(bar.get_x() + bar.get_width()/2, height),
xytext=(0, 3), textcoords="offset points", ha='center', va='bottom', fontsize=9)
for bar in bars2:
height = bar.get_height()
if height < 1:
ax.annotate(f'{height:.4f}', xy=(bar.get_x() + bar.get_width()/2, height),
xytext=(0, 3), textcoords="offset points", ha='center', va='bottom', fontsize=9)
else:
ax.annotate(f'{height:.1f} сек', xy=(bar.get_x() + bar.get_width()/2, height),
xytext=(0, 5), textcoords="offset points", ha='center', va='bottom', fontsize=10, fontweight='bold')
ax.set_ylabel('Время (сек)', fontsize=12)
ax.set_title('Время вставки 10000 записей', fontsize=14, fontweight='bold')
ax.set_xticks(x)
ax.set_xticklabels(structures, fontsize=11)
ax.legend(fontsize=11)
ax.set_yscale('log')
ax.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.savefig('docs/data/graph_insert.png', dpi=150, bbox_inches='tight')
plt.close()
# график поиск
fig, ax = plt.subplots(figsize=(12, 7))
bars1 = ax.bar(x - width/2, random_search, width, label='Случайный порядок', color='#3498db')
bars2 = ax.bar(x + width/2, sorted_search, width, label='Отсортированный порядок', color='#e74c3c')
for bar in bars1:
height = bar.get_height()
ax.annotate(f'{height:.6f}', xy=(bar.get_x() + bar.get_width()/2, height),
xytext=(0, 3), textcoords="offset points", ha='center', va='bottom', fontsize=9)
for bar in bars2:
height = bar.get_height()
if height < 0.01:
ax.annotate(f'{height:.6f}', xy=(bar.get_x() + bar.get_width()/2, height),
xytext=(0, 3), textcoords="offset points", ha='center', va='bottom', fontsize=9)
else:
ax.annotate(f'{height:.4f}', xy=(bar.get_x() + bar.get_width()/2, height),
xytext=(0, 3), textcoords="offset points", ha='center', va='bottom', fontsize=9)
ax.set_ylabel('Время (сек)', fontsize=12)
ax.set_title('Время поиска 110 записей', fontsize=14, fontweight='bold')
ax.set_xticks(x)
ax.set_xticklabels(structures, fontsize=11)
ax.legend(fontsize=11)
ax.set_yscale('log')
ax.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.savefig('docs/data/graph_search.png', dpi=150, bbox_inches='tight')
plt.close()
# график удаление
fig, ax = plt.subplots(figsize=(12, 7))
bars1 = ax.bar(x - width/2, random_delete, width, label='Случайный порядок', color='#3498db')
bars2 = ax.bar(x + width/2, sorted_delete, width, label='Отсортированный порядок', color='#e74c3c')
for bar in bars1:
height = bar.get_height()
ax.annotate(f'{height:.6f}', xy=(bar.get_x() + bar.get_width()/2, height),
xytext=(0, 3), textcoords="offset points", ha='center', va='bottom', fontsize=9)
for bar in bars2:
height = bar.get_height()
if height < 0.01:
ax.annotate(f'{height:.6f}', xy=(bar.get_x() + bar.get_width()/2, height),
xytext=(0, 3), textcoords="offset points", ha='center', va='bottom', fontsize=9)
else:
ax.annotate(f'{height:.4f}', xy=(bar.get_x() + bar.get_width()/2, height),
xytext=(0, 3), textcoords="offset points", ha='center', va='bottom', fontsize=9)
ax.set_ylabel('Время (сек)', fontsize=12)
ax.set_title('Время удаления 50 записей', fontsize=14, fontweight='bold')
ax.set_xticks(x)
ax.set_xticklabels(structures, fontsize=11)
ax.legend(fontsize=11)
ax.set_yscale('log')
ax.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.savefig('docs/data/graph_delete.png', dpi=150, bbox_inches='tight')
plt.close()

View File

@ -0,0 +1,34 @@
import matplotlib.pyplot as plt
import os
os.makedirs('docs/data', exist_ok=True)
data = [
['LinkedList', 'случайный', 0.0037545, 0.00000962, 0.0000079],
['HashTable', 'случайный', 0.015088, 0.0001646, 0.00009824],
['BST', 'случайный', 0.026280, 0.0002592, 0.00016984],
['LinkedList', 'отсортированный', 0.0017544, 0.00000858, 0.00000294],
['HashTable', 'отсортированный', 0.011369, 0.00014016, 0.00005878],
['BST', 'отсортированный', 4.930788, 0.047126, 0.023013],
]
fig, ax = plt.subplots(figsize=(12, 5))
ax.axis('tight')
ax.axis('off')
columns = ['Структура', 'Режим', 'Вставка (10000)', 'Поиск (110)', 'Удаление (50)']
table = ax.table(cellText=data, colLabels=columns, loc='center', cellLoc='center')
table.auto_set_font_size(False)
table.set_fontsize(10)
table.scale(1.2, 1.5)
for i, row in enumerate(data):
if row[0] == 'BST' and row[2] > 1:
table[(i+1, 2)].set_facecolor('#ffcccc')
table[(i+1, 2)].set_text_props(weight='bold')
plt.title('Результаты экспериментов (среднее время в секундах)', fontsize=14, fontweight='bold', pad=20)
plt.savefig('docs/data/table_results.png', dpi=200, bbox_inches='tight', facecolor='white')
plt.close()

View File

@ -0,0 +1,195 @@
def ll_insert(head, name, phone):
new_node = {'name': name, 'phone': phone, 'next': None}
if head is None:
return new_node
current = head
while current['next'] is not None:
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
def hash_function(name, table_size):
total = 0
for ch in name:
total = (total*31 + ord(ch)) % table_size
return total
def ht_create(size=1000):
return [None]*size
def ht_insert(buckets, name, phone):
idx = hash_function(name, len(buckets))
buckets[idx] = ll_insert(buckets[idx], name, phone)
return buckets
def ht_find(buckets, name):
idx = hash_function(name, len(buckets))
return ll_find(buckets[idx], name)
def ht_delete(buckets, name):
idx = hash_function(name, len(buckets))
buckets[idx] = ll_delete(buckets[idx], name)
return buckets
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
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_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
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'] == 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'] == successor:
successor_parent['left'] = successor['right']
else:
successor_parent['right'] = successor['right']
return root
if parent is None:
return child
if parent['left'] == current:
parent['left'] = child
else:
parent['right'] = child
return root
def bst_list_all(root):
records = []
def inorder(node):
if node is None:
return
inorder(node['left'])
records.append((node['name'], node['phone']))
inorder(node['right'])
inorder(root)
return records

View File

@ -0,0 +1,109 @@
Структура, Режим, Операция, Замер, Время (сек)
LinkedList,случайный,вставка,1,0.0013560999650508165
LinkedList,случайный,вставка,2,0.0015854999655857682
LinkedList,случайный,вставка,3,0.0012766000581905246
LinkedList,случайный,вставка,4,0.0013539999490603805
LinkedList,случайный,вставка,5,0.0013421999756246805
LinkedList,случайный,вставка,среднее,0.001382879982702434
LinkedList,случайный,поиск,1,5.899928510189056e-06
LinkedList,случайный,поиск,2,4.899920895695686e-06
LinkedList,случайный,поиск,3,4.800036549568176e-06
LinkedList,случайный,поиск,4,5.09992241859436e-06
LinkedList,случайный,поиск,5,5.00003807246685e-06
LinkedList,случайный,поиск,среднее,5.139969289302826e-06
LinkedList,случайный,удаление,1,2.900022082030773e-06
LinkedList,случайный,удаление,2,2.199900336563587e-06
LinkedList,случайный,удаление,3,2.200016751885414e-06
LinkedList,случайный,удаление,4,2.100015990436077e-06
LinkedList,случайный,удаление,5,2.299901098012924e-06
LinkedList,случайный,удаление,среднее,2.3399712517857552e-06
HashTable,случайный,вставка,1,0.010439200093969703
HashTable,случайный,вставка,2,0.010059899999760091
HashTable,случайный,вставка,3,0.010718900011852384
HashTable,случайный,вставка,4,0.010526199941523373
HashTable,случайный,вставка,5,0.0102259999839589
HashTable,случайный,вставка,среднее,0.01039404000621289
HashTable,случайный,поиск,1,9.549991227686405e-05
HashTable,случайный,поиск,2,9.079999290406704e-05
HashTable,случайный,поиск,3,9.989994578063488e-05
HashTable,случайный,поиск,4,9.240000508725643e-05
HashTable,случайный,поиск,5,9.039998985826969e-05
HashTable,случайный,поиск,среднее,9.379996918141842e-05
HashTable,случайный,удаление,1,4.610000178217888e-05
HashTable,случайный,удаление,2,4.2499974370002747e-05
HashTable,случайный,удаление,3,4.290009383112192e-05
HashTable,случайный,удаление,4,4.2400090023875237e-05
HashTable,случайный,удаление,5,4.269997589290142e-05
HashTable,случайный,удаление,среднее,4.332002718001604e-05
BST,случайный,вставка,1,0.014894199906848371
BST,случайный,вставка,2,0.015171999926678836
BST,случайный,вставка,3,0.015123400022275746
BST,случайный,вставка,4,0.015276000020094216
BST,случайный,вставка,5,0.01524280000012368
BST,случайный,вставка,среднее,0.015141679975204169
BST,случайный,поиск,1,0.00014160003047436476
BST,случайный,поиск,2,0.0001335999695584178
BST,случайный,поиск,3,0.00013259996194392443
BST,случайный,поиск,4,0.0001449999399483204
BST,случайный,поиск,5,0.00013129995204508305
BST,случайный,поиск,среднее,0.0001368199707940221
BST,случайный,удаление,1,8.909997995942831e-05
BST,случайный,удаление,2,6.929994560778141e-05
BST,случайный,удаление,3,6.719992961734533e-05
BST,случайный,удаление,4,6.700004450976849e-05
BST,случайный,удаление,5,6.679992657154799e-05
BST,случайный,удаление,среднее,7.18799652531743e-05
LinkedList,отсортированный,вставка,1,0.0012123000342398882
LinkedList,отсортированный,вставка,2,0.0011566999601200223
LinkedList,отсортированный,вставка,3,0.001145699992775917
LinkedList,отсортированный,вставка,4,0.0011751001002267003
LinkedList,отсортированный,вставка,5,0.0011464999988675117
LinkedList,отсортированный,вставка,среднее,0.0011672600172460078
LinkedList,отсортированный,поиск,1,5.300040356814861e-06
LinkedList,отсортированный,поиск,2,4.900037311017513e-06
LinkedList,отсортированный,поиск,3,4.800036549568176e-06
LinkedList,отсортированный,поиск,4,5.200039595365524e-06
LinkedList,отсортированный,поиск,5,4.799920134246349e-06
LinkedList,отсортированный,поиск,среднее,5.000014789402485e-06
LinkedList,отсортированный,удаление,1,2.400018274784088e-06
LinkedList,отсортированный,удаление,2,2.300017513334751e-06
LinkedList,отсортированный,удаление,3,2.300017513334751e-06
LinkedList,отсортированный,удаление,4,2.300017513334751e-06
LinkedList,отсортированный,удаление,5,2.200016751885414e-06
LinkedList,отсортированный,удаление,среднее,2.300017513334751e-06
HashTable,отсортированный,вставка,1,0.00947619997896254
HashTable,отсортированный,вставка,2,0.00943189999088645
HashTable,отсортированный,вставка,3,0.009878099896013737
HashTable,отсортированный,вставка,4,0.009515199926681817
HashTable,отсортированный,вставка,5,0.009485000045970082
HashTable,отсортированный,вставка,среднее,0.009557279967702925
HashTable,отсортированный,поиск,1,9.810004848986864e-05
HashTable,отсортированный,поиск,2,9.250000584870577e-05
HashTable,отсортированный,поиск,3,9.019998833537102e-05
HashTable,отсортированный,поиск,4,9.129999671131372e-05
HashTable,отсортированный,поиск,5,9.280000813305378e-05
HashTable,отсортированный,поиск,среднее,9.298000950366258e-05
HashTable,отсортированный,удаление,1,4.429998807609081e-05
HashTable,отсортированный,удаление,2,4.549999721348286e-05
HashTable,отсортированный,удаление,3,4.339998122304678e-05
HashTable,отсортированный,удаление,4,4.270009230822325e-05
HashTable,отсортированный,удаление,5,4.349998198449612e-05
HashTable,отсортированный,удаление,среднее,4.3880008161067965e-05
BST,отсортированный,вставка,1,4.526228099945001
BST,отсортированный,вставка,2,4.322803199989721
BST,отсортированный,вставка,3,4.176126900012605
BST,отсортированный,вставка,4,3.965669700060971
BST,отсортированный,вставка,5,3.9622846000129357
BST,отсортированный,вставка,среднее,4.190622500004247
BST,отсортированный,поиск,1,0.030124699929729104
BST,отсортированный,поиск,2,0.030757599975913763
BST,отсортированный,поиск,3,0.03016249998472631
BST,отсортированный,поиск,4,0.03018200001679361
BST,отсортированный,поиск,5,0.030304200015962124
BST,отсортированный,поиск,среднее,0.03030619998462498
BST,отсортированный,удаление,1,0.016157799982465804
BST,отсортированный,удаление,2,0.01620279997587204
BST,отсортированный,удаление,3,0.017003200016915798
BST,отсортированный,удаление,4,0.01792290003504604
BST,отсортированный,удаление,5,0.017416900023818016
BST,отсортированный,удаление,среднее,0.01694072000682354
1 Структура Режим Операция Замер Время (сек)
2 LinkedList случайный вставка 1 0.0013560999650508165
3 LinkedList случайный вставка 2 0.0015854999655857682
4 LinkedList случайный вставка 3 0.0012766000581905246
5 LinkedList случайный вставка 4 0.0013539999490603805
6 LinkedList случайный вставка 5 0.0013421999756246805
7 LinkedList случайный вставка среднее 0.001382879982702434
8 LinkedList случайный поиск 1 5.899928510189056e-06
9 LinkedList случайный поиск 2 4.899920895695686e-06
10 LinkedList случайный поиск 3 4.800036549568176e-06
11 LinkedList случайный поиск 4 5.09992241859436e-06
12 LinkedList случайный поиск 5 5.00003807246685e-06
13 LinkedList случайный поиск среднее 5.139969289302826e-06
14 LinkedList случайный удаление 1 2.900022082030773e-06
15 LinkedList случайный удаление 2 2.199900336563587e-06
16 LinkedList случайный удаление 3 2.200016751885414e-06
17 LinkedList случайный удаление 4 2.100015990436077e-06
18 LinkedList случайный удаление 5 2.299901098012924e-06
19 LinkedList случайный удаление среднее 2.3399712517857552e-06
20 HashTable случайный вставка 1 0.010439200093969703
21 HashTable случайный вставка 2 0.010059899999760091
22 HashTable случайный вставка 3 0.010718900011852384
23 HashTable случайный вставка 4 0.010526199941523373
24 HashTable случайный вставка 5 0.0102259999839589
25 HashTable случайный вставка среднее 0.01039404000621289
26 HashTable случайный поиск 1 9.549991227686405e-05
27 HashTable случайный поиск 2 9.079999290406704e-05
28 HashTable случайный поиск 3 9.989994578063488e-05
29 HashTable случайный поиск 4 9.240000508725643e-05
30 HashTable случайный поиск 5 9.039998985826969e-05
31 HashTable случайный поиск среднее 9.379996918141842e-05
32 HashTable случайный удаление 1 4.610000178217888e-05
33 HashTable случайный удаление 2 4.2499974370002747e-05
34 HashTable случайный удаление 3 4.290009383112192e-05
35 HashTable случайный удаление 4 4.2400090023875237e-05
36 HashTable случайный удаление 5 4.269997589290142e-05
37 HashTable случайный удаление среднее 4.332002718001604e-05
38 BST случайный вставка 1 0.014894199906848371
39 BST случайный вставка 2 0.015171999926678836
40 BST случайный вставка 3 0.015123400022275746
41 BST случайный вставка 4 0.015276000020094216
42 BST случайный вставка 5 0.01524280000012368
43 BST случайный вставка среднее 0.015141679975204169
44 BST случайный поиск 1 0.00014160003047436476
45 BST случайный поиск 2 0.0001335999695584178
46 BST случайный поиск 3 0.00013259996194392443
47 BST случайный поиск 4 0.0001449999399483204
48 BST случайный поиск 5 0.00013129995204508305
49 BST случайный поиск среднее 0.0001368199707940221
50 BST случайный удаление 1 8.909997995942831e-05
51 BST случайный удаление 2 6.929994560778141e-05
52 BST случайный удаление 3 6.719992961734533e-05
53 BST случайный удаление 4 6.700004450976849e-05
54 BST случайный удаление 5 6.679992657154799e-05
55 BST случайный удаление среднее 7.18799652531743e-05
56 LinkedList отсортированный вставка 1 0.0012123000342398882
57 LinkedList отсортированный вставка 2 0.0011566999601200223
58 LinkedList отсортированный вставка 3 0.001145699992775917
59 LinkedList отсортированный вставка 4 0.0011751001002267003
60 LinkedList отсортированный вставка 5 0.0011464999988675117
61 LinkedList отсортированный вставка среднее 0.0011672600172460078
62 LinkedList отсортированный поиск 1 5.300040356814861e-06
63 LinkedList отсортированный поиск 2 4.900037311017513e-06
64 LinkedList отсортированный поиск 3 4.800036549568176e-06
65 LinkedList отсортированный поиск 4 5.200039595365524e-06
66 LinkedList отсортированный поиск 5 4.799920134246349e-06
67 LinkedList отсортированный поиск среднее 5.000014789402485e-06
68 LinkedList отсортированный удаление 1 2.400018274784088e-06
69 LinkedList отсортированный удаление 2 2.300017513334751e-06
70 LinkedList отсортированный удаление 3 2.300017513334751e-06
71 LinkedList отсортированный удаление 4 2.300017513334751e-06
72 LinkedList отсортированный удаление 5 2.200016751885414e-06
73 LinkedList отсортированный удаление среднее 2.300017513334751e-06
74 HashTable отсортированный вставка 1 0.00947619997896254
75 HashTable отсортированный вставка 2 0.00943189999088645
76 HashTable отсортированный вставка 3 0.009878099896013737
77 HashTable отсортированный вставка 4 0.009515199926681817
78 HashTable отсортированный вставка 5 0.009485000045970082
79 HashTable отсортированный вставка среднее 0.009557279967702925
80 HashTable отсортированный поиск 1 9.810004848986864e-05
81 HashTable отсортированный поиск 2 9.250000584870577e-05
82 HashTable отсортированный поиск 3 9.019998833537102e-05
83 HashTable отсортированный поиск 4 9.129999671131372e-05
84 HashTable отсортированный поиск 5 9.280000813305378e-05
85 HashTable отсортированный поиск среднее 9.298000950366258e-05
86 HashTable отсортированный удаление 1 4.429998807609081e-05
87 HashTable отсортированный удаление 2 4.549999721348286e-05
88 HashTable отсортированный удаление 3 4.339998122304678e-05
89 HashTable отсортированный удаление 4 4.270009230822325e-05
90 HashTable отсортированный удаление 5 4.349998198449612e-05
91 HashTable отсортированный удаление среднее 4.3880008161067965e-05
92 BST отсортированный вставка 1 4.526228099945001
93 BST отсортированный вставка 2 4.322803199989721
94 BST отсортированный вставка 3 4.176126900012605
95 BST отсортированный вставка 4 3.965669700060971
96 BST отсортированный вставка 5 3.9622846000129357
97 BST отсортированный вставка среднее 4.190622500004247
98 BST отсортированный поиск 1 0.030124699929729104
99 BST отсортированный поиск 2 0.030757599975913763
100 BST отсортированный поиск 3 0.03016249998472631
101 BST отсортированный поиск 4 0.03018200001679361
102 BST отсортированный поиск 5 0.030304200015962124
103 BST отсортированный поиск среднее 0.03030619998462498
104 BST отсортированный удаление 1 0.016157799982465804
105 BST отсортированный удаление 2 0.01620279997587204
106 BST отсортированный удаление 3 0.017003200016915798
107 BST отсортированный удаление 4 0.01792290003504604
108 BST отсортированный удаление 5 0.017416900023818016
109 BST отсортированный удаление среднее 0.01694072000682354

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

View File

@ -0,0 +1,163 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "f058dc2c",
"metadata": {},
"source": [
"# Отчёт: Задание 1 — Структуры данных\n",
"\n",
"## Цель работы\n",
"\n",
"Разработать три структуры данных «с нуля» в процедурном стиле (без ООП), применить их для хранения записей телефонной книги и провести экспериментальное сравнение производительности ключевых операций.\n",
"\n",
"**Структуры данных:**\n",
"- Связный список (LinkedList)\n",
"- Хеш-таблица (HashTable)\n",
"- Двоичное дерево поиска (BST)\n",
"\n",
"---\n",
"\n",
"## Реализация\n",
"\n",
"### Основные технические решения\n",
"\n",
"#### 1. Связный список\n",
"\n",
"Узел реализован как Python-словарь: `{'name': 'Имя', 'phone': '123', 'next': None}`.\n",
"\n",
"Новые элементы добавляются **в конец** списка за O(1) (без проверки на дубликаты имени). Поиск и удаление работают за линейное время O(n) из-за отсутствия прямого доступа по индексу.\n",
"\n",
"#### 2. Хеш-таблица\n",
"\n",
"Фиксированный массив на **1000 корзин**. Каждая корзина — указатель на связный список (метод цепочек). Хеш-функция: полиномиальная с основанием 31, свёрнутая по модулю размера таблицы. Среднее время операций O(1), при коллизиях — O(k), где k — длина цепочки.\n",
"\n",
"#### 3. Двоичное дерево поиска (BST)\n",
"\n",
"Узел: `{'name': 'Имя', 'phone': '123', 'left': None, 'right': None}`. Сравнение ключей — лексикографическое по полю `name`. Вставка и поиск реализованы итеративно. Удаление — с заменой на минимальный узел правого поддерева. Обход в глубину даёт отсортированный список.\n",
"\n",
"---\n",
"\n",
"## Экспериментальная часть\n",
"\n",
"### Условия проведения замеров\n",
"\n",
"| Параметр | Значение |\n",
"|---|---|\n",
"| Количество записей (N) | 10 000 |\n",
"| Количество замеров на операцию | 5 |\n",
"| Поисковых запросов | 110 (100 существующих + 10 отсутствующих) |\n",
"| Удалений | 50 |\n",
"| Размер хеш-таблицы | 1000 корзин |\n",
"\n",
"**Два набора данных:**\n",
"- `records_shuffled` — случайный порядок записей\n",
"- `records_sorted` — упорядоченный по имени (алфавитный порядок)\n",
"\n",
"---\n",
"\n",
"## Результаты\n",
"\n",
"### Среднее время выполнения (секунды)\n",
"\n",
"| Структура | Режим | Вставка (10000) | Поиск (110) | Удаление (50) |\n",
"|-----------|-------|----------------|-------------|---------------|\n",
"| LinkedList | случайный | 0.001383 | 0.00000514 | 0.00000234 |\n",
"| LinkedList | отсортированный | 0.001167 | 0.00000500 | 0.00000230 |\n",
"| HashTable | случайный | 0.010394 | 0.00009380 | 0.00004332 |\n",
"| HashTable | отсортированный | 0.009557 | 0.00009298 | 0.00004388 |\n",
"| BST | случайный | 0.015142 | 0.00013682 | 0.00007188 |\n",
"| **BST** | **отсортированный** | **4.19062** | **0.030306** | **0.016941** |\n",
"\n",
"### Визуализация\n",
"\n",
"![Сравнение вставки](docs/data/graph_insert.png)\n",
"\n",
"![Сравнение поиска](docs/data/graph_search.png)\n",
"\n",
"![Сравнение удаления](docs/data/graph_delete.png)\n",
"\n",
"![Таблица результатов](docs/data/table_results.png)\n",
"\n",
"---\n",
"\n",
"## Анализ результатов\n",
"\n",
"### 1. Связный список — сверхбыстрая вставка, но линейный поиск\n",
"\n",
"- **Вставка** выполняется за **~0.0012 с** на 10000 элементов, так как добавление происходит в конец списка без проверки дубликатов (O(1) на операцию).\n",
"- **Поиск** и **удаление** в замерах показали микросекунды, но это следствие малого количества операций (110 поисков, 50 удалений) и того, что искомые записи находятся в начале списка. В худшем случае (поиск отсутствующего элемента) сложность остаётся O(n).\n",
"\n",
"**Вывод:** связный список эффективен только при очень малых объёмах данных или когда вставка — единственная частая операция.\n",
"\n",
"### 2. Хеш-таблица — стабильная производительность\n",
"\n",
"Хеш-таблица демонстрирует **устойчивость к порядку входных данных**:\n",
"- Вставка: ~0.010 с (быстрее BST на случайных данных, но медленнее LinkedList)\n",
"- Поиск: ~0.000094 с (в 18 раз быстрее BST на случайных)\n",
"- Удаление: ~0.000043 с (в 1.6 раза быстрее BST)\n",
"\n",
"Размер таблицы (1000 корзин) обеспечивает равномерное распределение ключей, поэтому производительность остаётся стабильной.\n",
"\n",
"### 3. BST катастрофически деградирует на упорядоченных данных\n",
"\n",
"Самый показательный результат эксперимента:\n",
"\n",
"| Операция | Случайный порядок | Отсортированный порядок | Ухудшение |\n",
"|----------|------------------|------------------------|-----------|\n",
"| Вставка | 0.01514 с | **4.19062 с** | **×277** |\n",
"| Поиск | 0.0001368 с | **0.03031 с** | **×221** |\n",
"| Удаление | 0.0000719 с | **0.01694 с** | **×236** |\n",
"\n",
"**Причина:** при вставке отсортированных данных дерево вырождается в линейный список — каждый новый элемент больше предыдущего и помещается только в правую ветку. Высота дерева становится O(n) вместо O(log n), что превращает все операции в линейные.\n",
"\n",
"### 4. Сравнение с теоретическими ожиданиями\n",
"\n",
"| Структура | Теоретическая вставка | Фактическая (случ./сорт.) | \n",
"|-----------|----------------------|---------------------------|\n",
"| LinkedList | O(1) (в конец) | 0.0014 с / 0.0012 с |\n",
"| HashTable | O(1) в среднем | 0.0104 с / 0.0096 с |\n",
"| BST | O(log n) в среднем | 0.0151 с (случ.) |\n",
"| BST | O(n) в худшем | 4.19 с (сорт.) |\n",
"\n",
"---\n",
"\n",
"## Выводы и практические рекомендации\n",
"\n",
"### Выбор структуры в зависимости от задачи\n",
"\n",
"| Сценарий | Рекомендация |\n",
"|----------|--------------|\n",
"| **Частый поиск по ключу** | HashTable (быстрее всего) |\n",
"| **Данные поступают упорядоченно** | HashTable (BST непригоден) |\n",
"| **Только вставка и редкий поиск** | LinkedList (самая быстрая вставка) |\n",
"| **Требуется отсортированный вывод** | BST (обход даёт порядок за O(n)) |\n",
"| **Сбалансированные операции** | HashTable |\n",
"| **Диапазонные запросы** (например, АМ) | BST (при условии балансировки) |\n",
"\n",
"### Теоретическая сложность операций \n",
"| Структура | Insert | Find | Delete | Обход (отсорт.) |\n",
"|-----------|--------|------|--------|-----------------|\n",
"| LinkedList (в конец) | O(1) | O(n) | O(n) | O(n log n) |\n",
"| HashTable | O(1) | O(1) | O(1) | O(n log n) |\n",
"| BST (сбалансированный) | O(log n) | O(log n) | O(log n) | O(n) |\n",
"| BST (вырожденный) | O(n) | O(n) | O(n) | O(n) |\n",
"\n",
"### Ключевой вывод\n",
"\n",
"Для телефонного справочника с частыми поисками и обновлениями оптимальный выбор — **хеш-таблица**. Она обеспечивает предсказуемую скорость вне зависимости от порядка данных.\n",
"\n",
"Обычный **связный список** полезен только как вспомогательная структура (например, для цепочек в хеш-таблице) или при минимальном объёме данных.\n",
"\n",
"**Двоичное дерево поиска** без самобалансировки опасно использовать с реальными данными, которые часто бывают частично или полностью упорядоченными. В таких случаях необходимо применять AVL или красно-чёрные деревья.\n"
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}