Merge pull request '[1] task 1' (#258) from groshevava/2026-rff_mp:groshevava into develop

Reviewed-on: UNN/2026-rff_mp#258
This commit is contained in:
AndreyUrs 2026-05-30 11:49:49 +00:00
commit 93fb15f301
6 changed files with 549 additions and 0 deletions

153
groshevava/docs/data/bst.py Normal file
View File

@ -0,0 +1,153 @@
#реализация справочника на основе бинарного дерева поиска (BST).
#создаём узел
def bst_create_node(name, phone):
return {
'name': name,
'phone': phone,
'left': None,
'right': None
}
#Вставляет запись в BST или обновляет.Возвращает корень дерева
def bst_insert(root, name, phone):
new_node = bst_create_node(name, phone)
if root is None:
return new_node
current = root
parent = None
while current is not None:
parent = current
if name < current['name']:
current = current['left']
elif name > current['name']:
current = current['right']
else:
current['phone'] = phone
return root
#вставляем новый узел
if name < parent['name']:
parent['left'] = new_node
else:
parent['right'] = new_node
return root
#ищет запись в BST по имени. Возвращает телефон или None
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
#удаляет запись из BST по имени. Возвращает новый корень дерева
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
elif parent['left'] == current:
parent['left'] = None
else:
parent['right'] = None
return root
if current['left'] is None:
if parent is None:
return current['right']
elif parent['left'] == current:
parent['left'] = current['right']
else:
parent['right'] = current['right']
return root
if current['right'] is None:
if parent is None:
return current['left']
elif parent['left'] == current:
parent['left'] = current['left']
else:
parent['right'] = current['left']
return root
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 == current:
successor_parent['right'] = successor['right']
else:
successor_parent['left'] = successor['right']
return root
#рекурсивно собирает записи дерева по возрастанию имён
def _bst_in_order_collect(node, records):
if node is not None:
_bst_in_order_collect(node['left'], records)
records.append((node['name'], node['phone']))
_bst_in_order_collect(node['right'], records)
#отсортированный список всех записей
def bst_list_all(root):
records = []
# Для очень глубоких деревьев лучше использовать итеративный обход
_bst_in_order_iterative(root, records)
return records
#центрированный обход дерева.
def _bst_in_order_iterative(root, records):
stack = []
current = root
while current is not None or len(stack) > 0:
# доходим до самого левого узла
while current is not None:
stack.append(current)
current = current['left']
# обрабатываем узел
current = stack.pop()
records.append((current['name'], current['phone']))
#переходим к правому поддереву
current = current['right']

View File

@ -0,0 +1,198 @@
#проведение экспериментов и замер производительности
import time
import random
import csv
from linked_list import ll_insert, ll_find, ll_delete, ll_list_all
from hash_table import ht_create, ht_insert, ht_find, ht_delete, ht_list_all
from bst import bst_insert, bst_find, bst_delete, bst_list_all
#генерирует записи справочника. shuffled- случайный порядок, sorted-отсортированный по имени
def generate_test_data(n=10000, seed=42):
random.seed(seed)
names = [f"User_{i:05d}" for i in range(n)]
phones = [f"+7-999-{i:07d}" for i in range(n)]
records = list(zip(names, phones))
records_shuffled = records.copy()
random.shuffle(records_shuffled)
records_sorted = sorted(records, key=lambda x: x[0])
return records_shuffled, records_sorted
#замеряем время
def measure_insert(ll_structure, ht_structure, bst_structure, records, mode_name):
results = []
# Связный список
start = time.perf_counter()
head = None
for name, phone in records:
head = ll_insert(head, name, phone)
end = time.perf_counter()
results.append(["LinkedList", mode_name, "вставка", end - start])
# Хеш-таблица
start = time.perf_counter()
buckets = ht_create(256)
for name, phone in records:
ht_insert(buckets, name, phone)
end = time.perf_counter()
results.append(["HashTable", mode_name, "вставка", end - start])
# BST
start = time.perf_counter()
root = None
for name, phone in records:
root = bst_insert(root, name, phone)
end = time.perf_counter()
results.append(["BST", mode_name, "вставка", end - start])
return results, head, buckets, root
def measure_find(head, buckets, root, all_names, mode_name):
results = []
# Выбираем 100 случайных существующих и 10 несуществующих имён
existing_names = random.sample(all_names, 100)
non_existing_names = [f"None_{i}" for i in range(10)]
search_names = existing_names + non_existing_names
# Связный список
start = time.perf_counter()
for name in search_names:
ll_find(head, name)
end = time.perf_counter()
results.append(["LinkedList", mode_name, "поиск", end - start])
# Хеш-таблица
start = time.perf_counter()
for name in search_names:
ht_find(buckets, name)
end = time.perf_counter()
results.append(["HashTable", mode_name, "поиск", end - start])
# BST
start = time.perf_counter()
for name in search_names:
bst_find(root, name)
end = time.perf_counter()
results.append(["BST", mode_name, "поиск", end - start])
return results
def measure_delete(head, buckets, root, all_names, mode_name):
results = []
# Выбираем 50 случайных имён для удаления
delete_names = random.sample(all_names, 50)
# Связный список
start = time.perf_counter()
for name in delete_names:
head = ll_delete(head, name)
end = time.perf_counter()
results.append(["LinkedList", mode_name, "удаление", end - start])
# Хеш-таблица
start = time.perf_counter()
for name in delete_names:
ht_delete(buckets, name)
end = time.perf_counter()
results.append(["HashTable", mode_name, "удаление", end - start])
# BST
start = time.perf_counter()
for name in delete_names:
root = bst_delete(root, name)
end = time.perf_counter()
results.append(["BST", mode_name, "удаление", end - start])
return results
#проводим эксперименты
def run_experiments(records_shuffled, records_sorted, repetitions=5):
all_results = [
["Структура", "Режим", "Операция", "Время (сек)"]
]
all_names = [record[0] for record in records_shuffled]
for rep in range(repetitions):
print(f"Повторение {rep + 1}/{repetitions}")
# Шаффлированные данные
results, head, buckets, root = measure_insert(
None, None, None, records_shuffled, "случайный"
)
all_results.extend(results)
results = measure_find(head, buckets, root, all_names, "случайный")
all_results.extend(results)
results = measure_delete(head, buckets, root, all_names, "случайный")
all_results.extend(results)
# Отсортированные данные
results, head, buckets, root = measure_insert(
None, None, None, records_sorted, "отсортированный"
)
all_results.extend(results)
results = measure_find(head, buckets, root, all_names, "отсортированный")
all_results.extend(results)
results = measure_delete(head, buckets, root, all_names, "отсортированный")
all_results.extend(results)
return all_results
def save_results(results, filename="results.csv"):
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerows(results)
print(f"Результаты сохранены в {filename}")
def analyze_results(filename="results.csv"):
from collections import defaultdict
with open(filename, 'r', encoding='utf-8') as f:
reader = csv.reader(f)
next(reader) # пропускаем заголовок
data = list(reader)
# Группируем для вычисления средних
stats = defaultdict(list)
for row in data:
structure, mode, operation, time_str = row
key = (structure, mode, operation)
stats[key].append(float(time_str))
print("\nСредние времена выполнения (сек):")
print("-" * 60)
print(f"{'Структура':<15} {'Режим':<20} {'Операция':<10} {'Время':<10}")
print("-" * 60)
for (structure, mode, operation), times in sorted(stats.items()):
avg_time = sum(times) / len(times)
print(f"{structure:<15} {mode:<20} {operation:<10} {avg_time:<10.6f}")
if __name__ == "__main__":
print("Генерация тестовых данных...")
records_shuffled, records_sorted = generate_test_data(10000)
print("Запуск экспериментов...")
results = run_experiments(records_shuffled, records_sorted, repetitions=5)
save_results(results)
analyze_results()

View File

@ -0,0 +1,43 @@
#Телефонного справочник на основе хеш-таблицы.
#Использует метод цепочек
from linked_list import ll_insert, ll_find, ll_delete, ll_list_all
#Хеш-функция для строки имени.
#Использует полиномиальное хеширование.
def ht_hash(name, bucket_count):
hash_value = 0
p = 31
for char in name:
hash_value = (hash_value * p + ord(char)) % bucket_count
return hash_value
#Создаёт пустую таблицу
def ht_create(bucket_count=128):
return [None] * bucket_count
#Добавляет запись в таблицу.
#Вычисляет хэш, затем вставляет в нужный бакет.
def ht_insert(buckets, name, phone):
index = ht_hash(name, len(buckets))
buckets[index] = ll_insert(buckets[index], name, phone)
#ищет запись в таблице
def ht_find(buckets, name):
index = ht_hash(name, len(buckets))
return ll_find(buckets[index], name)
#удаляет запись
def ht_delete(buckets, name):
index = ht_hash(name, len(buckets))
buckets[index] = ll_delete(buckets[index], name)
#сортировка по имени
def ht_list_all(buckets):
all_records = []
for bucket_head in buckets:
records = ll_list_all(bucket_head)
all_records.extend(records)
all_records.sort(key=lambda x: x[0])
return all_records

View File

@ -0,0 +1,64 @@
#Телефонного справочник - связный список
#создаёт новый узел
def ll_create_node(name, phone):
return {'name': name, 'phone': phone, 'next': None}
#добавляет запись в конец списка или обновляет.
def ll_insert(head, name, phone):
new_node = ll_create_node(name, phone)
if head is None:
return new_node
if head['name'] == name:
new_node['next'] = head['next']
return new_node
current = head
while current['next'] is not None:
if current['next']['name'] == name:
new_node['next'] = current['next']['next']
current['next'] = new_node
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
#собирает все записи связного списка в список name-phone, сортирует по имени
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

View File

@ -0,0 +1,91 @@
Структура,Режим,Операция,Время (сек)
LinkedList,случайный,вставка,7.0379601
HashTable,случайный,вставка,0.06370939999999958
BST,случайный,вставка,0.027558299999999925
LinkedList,случайный,поиск,0.05380779999999952
HashTable,случайный,поиск,0.0008359000000002226
BST,случайный,поиск,0.00036180000000030077
LinkedList,случайный,удаление,0.03279429999999994
HashTable,случайный,удаление,0.00046319999999955286
BST,случайный,удаление,0.0002371000000005452
LinkedList,отсортированный,вставка,6.794934100000001
HashTable,отсортированный,вставка,0.06352280000000121
BST,отсортированный,вставка,6.0836668
LinkedList,отсортированный,поиск,0.06371549999999715
HashTable,отсортированный,поиск,0.0013053000000020631
BST,отсортированный,поиск,0.05756839999999741
LinkedList,отсортированный,удаление,0.038222600000000995
HashTable,отсортированный,удаление,0.0011298000000010688
BST,отсортированный,удаление,0.036374399999999696
LinkedList,случайный,вставка,7.183893999999999
HashTable,случайный,вставка,0.06642779999999959
BST,случайный,вставка,0.025029599999999874
LinkedList,случайный,поиск,0.05042710000000028
HashTable,случайный,поиск,0.0008175000000001376
BST,случайный,поиск,0.00032500000000013074
LinkedList,случайный,удаление,0.04681619999999853
HashTable,случайный,удаление,0.0006166999999983602
BST,случайный,удаление,0.0002557000000003029
LinkedList,отсортированный,вставка,7.153371900000003
HashTable,отсортированный,вставка,0.05732309999999785
BST,отсортированный,вставка,6.7899777999999955
LinkedList,отсортированный,поиск,0.1498364000000052
HashTable,отсортированный,поиск,0.0021344999999968195
BST,отсортированный,поиск,0.08021600000000007
LinkedList,отсортированный,удаление,0.04531419999999997
HashTable,отсортированный,удаление,0.0005183999999971434
BST,отсортированный,удаление,0.032904900000005455
LinkedList,случайный,вставка,7.787066500000002
HashTable,случайный,вставка,0.06794790000000006
BST,случайный,вставка,0.028658900000003484
LinkedList,случайный,поиск,0.055633000000000266
HashTable,случайный,поиск,0.0011372000000022808
BST,случайный,поиск,0.00041319999999700485
LinkedList,случайный,удаление,0.04464529999999911
HashTable,случайный,удаление,0.0006264000000015812
BST,случайный,удаление,0.00025480000000044356
LinkedList,отсортированный,вставка,7.047079400000001
HashTable,отсортированный,вставка,0.07149469999999525
BST,отсортированный,вставка,6.004278499999998
LinkedList,отсортированный,поиск,0.059245700000005286
HashTable,отсортированный,поиск,0.0008623000000014258
BST,отсортированный,поиск,0.061085500000004345
LinkedList,отсортированный,удаление,0.038738300000005665
HashTable,отсортированный,удаление,0.00047229999999842676
BST,отсортированный,удаление,0.03476669999999871
LinkedList,случайный,вставка,7.814853800000002
HashTable,случайный,вставка,0.06793270000000007
BST,случайный,вставка,0.026476199999990513
LinkedList,случайный,поиск,0.056167000000002076
HashTable,случайный,поиск,0.0007876000000095473
BST,случайный,поиск,0.0003126000000008844
LinkedList,случайный,удаление,0.042319900000009625
HashTable,случайный,удаление,0.000520099999988588
BST,случайный,удаление,0.00023889999999937572
LinkedList,отсортированный,вставка,7.297540700000013
HashTable,отсортированный,вставка,0.06405399999999872
BST,отсортированный,вставка,6.252882799999995
LinkedList,отсортированный,поиск,0.058841400000005706
HashTable,отсортированный,поиск,0.0008604000000076439
BST,отсортированный,поиск,0.05284110000000908
LinkedList,отсортированный,удаление,0.03360689999999522
HashTable,отсортированный,удаление,0.00047010000000113905
BST,отсортированный,удаление,0.02865070000000003
LinkedList,случайный,вставка,7.937439900000001
HashTable,случайный,вставка,0.06798210000000893
BST,случайный,вставка,0.042214500000000044
LinkedList,случайный,поиск,0.0645776000000069
HashTable,случайный,поиск,0.0007535999999959131
BST,случайный,поиск,0.0003451000000040949
LinkedList,случайный,удаление,0.04297359999999628
HashTable,случайный,удаление,0.0005001999999905138
BST,случайный,удаление,0.00021639999999933934
LinkedList,отсортированный,вставка,7.474806200000003
HashTable,отсортированный,вставка,0.06952760000000069
BST,отсортированный,вставка,6.475523199999998
LinkedList,отсортированный,поиск,0.054521199999996384
HashTable,отсортированный,поиск,0.0008888999999925318
BST,отсортированный,поиск,0.049161900000001424
LinkedList,отсортированный,удаление,0.03957100000000935
HashTable,отсортированный,удаление,0.0004850999999916894
BST,отсортированный,удаление,0.03728519999999946
1 Структура Режим Операция Время (сек)
2 LinkedList случайный вставка 7.0379601
3 HashTable случайный вставка 0.06370939999999958
4 BST случайный вставка 0.027558299999999925
5 LinkedList случайный поиск 0.05380779999999952
6 HashTable случайный поиск 0.0008359000000002226
7 BST случайный поиск 0.00036180000000030077
8 LinkedList случайный удаление 0.03279429999999994
9 HashTable случайный удаление 0.00046319999999955286
10 BST случайный удаление 0.0002371000000005452
11 LinkedList отсортированный вставка 6.794934100000001
12 HashTable отсортированный вставка 0.06352280000000121
13 BST отсортированный вставка 6.0836668
14 LinkedList отсортированный поиск 0.06371549999999715
15 HashTable отсортированный поиск 0.0013053000000020631
16 BST отсортированный поиск 0.05756839999999741
17 LinkedList отсортированный удаление 0.038222600000000995
18 HashTable отсортированный удаление 0.0011298000000010688
19 BST отсортированный удаление 0.036374399999999696
20 LinkedList случайный вставка 7.183893999999999
21 HashTable случайный вставка 0.06642779999999959
22 BST случайный вставка 0.025029599999999874
23 LinkedList случайный поиск 0.05042710000000028
24 HashTable случайный поиск 0.0008175000000001376
25 BST случайный поиск 0.00032500000000013074
26 LinkedList случайный удаление 0.04681619999999853
27 HashTable случайный удаление 0.0006166999999983602
28 BST случайный удаление 0.0002557000000003029
29 LinkedList отсортированный вставка 7.153371900000003
30 HashTable отсортированный вставка 0.05732309999999785
31 BST отсортированный вставка 6.7899777999999955
32 LinkedList отсортированный поиск 0.1498364000000052
33 HashTable отсортированный поиск 0.0021344999999968195
34 BST отсортированный поиск 0.08021600000000007
35 LinkedList отсортированный удаление 0.04531419999999997
36 HashTable отсортированный удаление 0.0005183999999971434
37 BST отсортированный удаление 0.032904900000005455
38 LinkedList случайный вставка 7.787066500000002
39 HashTable случайный вставка 0.06794790000000006
40 BST случайный вставка 0.028658900000003484
41 LinkedList случайный поиск 0.055633000000000266
42 HashTable случайный поиск 0.0011372000000022808
43 BST случайный поиск 0.00041319999999700485
44 LinkedList случайный удаление 0.04464529999999911
45 HashTable случайный удаление 0.0006264000000015812
46 BST случайный удаление 0.00025480000000044356
47 LinkedList отсортированный вставка 7.047079400000001
48 HashTable отсортированный вставка 0.07149469999999525
49 BST отсортированный вставка 6.004278499999998
50 LinkedList отсортированный поиск 0.059245700000005286
51 HashTable отсортированный поиск 0.0008623000000014258
52 BST отсортированный поиск 0.061085500000004345
53 LinkedList отсортированный удаление 0.038738300000005665
54 HashTable отсортированный удаление 0.00047229999999842676
55 BST отсортированный удаление 0.03476669999999871
56 LinkedList случайный вставка 7.814853800000002
57 HashTable случайный вставка 0.06793270000000007
58 BST случайный вставка 0.026476199999990513
59 LinkedList случайный поиск 0.056167000000002076
60 HashTable случайный поиск 0.0007876000000095473
61 BST случайный поиск 0.0003126000000008844
62 LinkedList случайный удаление 0.042319900000009625
63 HashTable случайный удаление 0.000520099999988588
64 BST случайный удаление 0.00023889999999937572
65 LinkedList отсортированный вставка 7.297540700000013
66 HashTable отсортированный вставка 0.06405399999999872
67 BST отсортированный вставка 6.252882799999995
68 LinkedList отсортированный поиск 0.058841400000005706
69 HashTable отсортированный поиск 0.0008604000000076439
70 BST отсортированный поиск 0.05284110000000908
71 LinkedList отсортированный удаление 0.03360689999999522
72 HashTable отсортированный удаление 0.00047010000000113905
73 BST отсортированный удаление 0.02865070000000003
74 LinkedList случайный вставка 7.937439900000001
75 HashTable случайный вставка 0.06798210000000893
76 BST случайный вставка 0.042214500000000044
77 LinkedList случайный поиск 0.0645776000000069
78 HashTable случайный поиск 0.0007535999999959131
79 BST случайный поиск 0.0003451000000040949
80 LinkedList случайный удаление 0.04297359999999628
81 HashTable случайный удаление 0.0005001999999905138
82 BST случайный удаление 0.00021639999999933934
83 LinkedList отсортированный вставка 7.474806200000003
84 HashTable отсортированный вставка 0.06952760000000069
85 BST отсортированный вставка 6.475523199999998
86 LinkedList отсортированный поиск 0.054521199999996384
87 HashTable отсортированный поиск 0.0008888999999925318
88 BST отсортированный поиск 0.049161900000001424
89 LinkedList отсортированный удаление 0.03957100000000935
90 HashTable отсортированный удаление 0.0004850999999916894
91 BST отсортированный удаление 0.03728519999999946

BIN
groshevava/docs/task_1.doc Normal file

Binary file not shown.