From dd03fdd059ee2e2d28cb7e3754a968a0ae2a1a2f Mon Sep 17 00:00:00 2001 From: BoriskovaDV Date: Sun, 24 May 2026 17:30:04 +0000 Subject: [PATCH 1/9] [0] refork repo(I`m sorry) --- BoriskovaDV/428.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BoriskovaDV/428.md b/BoriskovaDV/428.md index e69de29..0519ecb 100644 --- a/BoriskovaDV/428.md +++ b/BoriskovaDV/428.md @@ -0,0 +1 @@ + \ No newline at end of file -- 2.43.0 From c967240036000b2077eefddb5b3a6c6e6b2c54e0 Mon Sep 17 00:00:00 2001 From: BoriskovaDV Date: Sun, 24 May 2026 17:31:03 +0000 Subject: [PATCH 2/9] [1] start 1-st-exercise --- .../1-st-exercise/linked_list_phonebook.py | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 BoriskovaDV/docs/data/1-st-exercise/linked_list_phonebook.py diff --git a/BoriskovaDV/docs/data/1-st-exercise/linked_list_phonebook.py b/BoriskovaDV/docs/data/1-st-exercise/linked_list_phonebook.py new file mode 100644 index 0000000..b279789 --- /dev/null +++ b/BoriskovaDV/docs/data/1-st-exercise/linked_list_phonebook.py @@ -0,0 +1,67 @@ +def create_node(name, phone): + return {'name': name, 'phone': phone, 'next': None} + +def ll_insert(head, name, phone): + current = head + while current is not None: + if current['name'] == name: + current['phone'] = phone + return head + current = current['next'] + + new_node = create_node(name, phone) + + 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'] + + prev = head + current = head['next'] + while current is not None: + if current['name'] == name: + prev['next'] = current['next'] + return head + prev = current + 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 pair: pair[0]) + return records + +if __name__ == '__main__': + head = None + head = ll_insert(head, 'Иван', '123-456') + head = ll_insert(head, 'Борис', '789-012') + head = ll_insert(head, 'Анна', '345-678') + head = ll_insert(head, 'Иван', '111-222') + print(ll_list_all(head)) + print(ll_find(head, 'Иван')) + print(ll_find(head, 'Петр')) + head = ll_delete(head, 'Борис') + print(ll_list_all(head)) \ No newline at end of file -- 2.43.0 From e27b2772db03d24b4ec8693e0506c55893f87141 Mon Sep 17 00:00:00 2001 From: BoriskovaDV Date: Sun, 24 May 2026 17:31:57 +0000 Subject: [PATCH 3/9] [1] add hash_tabel --- .../1-st-exercise/hash_table_phonebook.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 BoriskovaDV/docs/data/1-st-exercise/hash_table_phonebook.py diff --git a/BoriskovaDV/docs/data/1-st-exercise/hash_table_phonebook.py b/BoriskovaDV/docs/data/1-st-exercise/hash_table_phonebook.py new file mode 100644 index 0000000..21a85ca --- /dev/null +++ b/BoriskovaDV/docs/data/1-st-exercise/hash_table_phonebook.py @@ -0,0 +1,47 @@ +from linked_list_phonebook import ll_insert, ll_find, ll_delete, ll_list_all + +def hash_function(name, table_size): + return hash(name) % table_size + +def ht_insert(buckets, name, phone): + idx = hash_function(name, len(buckets)) + head = buckets[idx] + new_head = ll_insert(head, name, phone) + buckets[idx] = new_head + return buckets + +def ht_find(buckets, name): + idx = hash_function(name, len(buckets)) + head = buckets[idx] + return ll_find(head, name) + +def ht_delete(buckets, name): + idx = hash_function(name, len(buckets)) + head = buckets[idx] + new_head = ll_delete(head, name) + buckets[idx] = new_head + return buckets + +def ht_list_all(buckets): + all_records = [] + for head in buckets: + current = head + while current is not None: + all_records.append((current['name'], current['phone'])) + current = current['next'] + all_records.sort(key=lambda x: x[0]) + return all_records + +if __name__ == '__main__': + SIZE = 5 + buckets = [None] * SIZE + + ht_insert(buckets, 'Иван', '123-456') + ht_insert(buckets, 'Борис', '789-012') + ht_insert(buckets, 'Анна', '345-678') + ht_insert(buckets, 'Иван', '111-222') + print(ht_list_all(buckets)) + print(ht_find(buckets, 'Анна')) + print(ht_find(buckets, 'Петр')) + ht_delete(buckets, 'Борис') + print(ht_list_all(buckets)) \ No newline at end of file -- 2.43.0 From b7d5bf54dde57f9c7b3fdb0a9ae8a602251c8709 Mon Sep 17 00:00:00 2001 From: BoriskovaDV Date: Sun, 24 May 2026 18:01:03 +0000 Subject: [PATCH 4/9] [1] add bst_phonebook.py --- .../docs/data/1-st-exercise/bst_phonebook.py | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 BoriskovaDV/docs/data/1-st-exercise/bst_phonebook.py diff --git a/BoriskovaDV/docs/data/1-st-exercise/bst_phonebook.py b/BoriskovaDV/docs/data/1-st-exercise/bst_phonebook.py new file mode 100644 index 0000000..0f5e017 --- /dev/null +++ b/BoriskovaDV/docs/data/1-st-exercise/bst_phonebook.py @@ -0,0 +1,71 @@ +def create_node(name, phone): + return {'name': name, 'phone': phone, 'left': None, 'right': None} + +def bst_insert(root, name, phone): + if root is None: + return create_node(name, phone) + + if name == root['name']: + root['phone'] = phone + elif name < root['name']: + root['left'] = bst_insert(root['left'], name, phone) + else: + root['right'] = bst_insert(root['right'], name, phone) + return root + +def bst_find(root, name): + if root is None: + return None + if name == root['name']: + return root['phone'] + elif name < root['name']: + return bst_find(root['left'], name) + else: + return bst_find(root['right'], name) + +def _find_min(node): + while node['left'] is not None: + node = node['left'] + return node + +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'] + if root['right'] is None: + return root['left'] + min_node = _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): + result = [] + def inorder(node): + if node is None: + return + inorder(node['left']) + result.append((node['name'], node['phone'])) + inorder(node['right']) + inorder(root) + return result + +if __name__ == '__main__': + root = None + root = bst_insert(root, 'Иван', '123-456') + root = bst_insert(root, 'Борис', '789-012') + root = bst_insert(root, 'Анна', '345-678') + root = bst_insert(root, 'Иван', '111-222') + print(bst_list_all(root)) + print(bst_find(root, 'Иван')) + print(bst_find(root, 'Петр')) + root = bst_delete(root, 'Борис') + print(bst_list_all(root)) \ No newline at end of file -- 2.43.0 From bde87a177b917dbbd2fe62e176801a82726f30f4 Mon Sep 17 00:00:00 2001 From: BoriskovaDV Date: Sun, 24 May 2026 18:01:39 +0000 Subject: [PATCH 5/9] [1] add experiment.py --- .../docs/data/1-st-exercise/experiment.py | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 BoriskovaDV/docs/data/1-st-exercise/experiment.py diff --git a/BoriskovaDV/docs/data/1-st-exercise/experiment.py b/BoriskovaDV/docs/data/1-st-exercise/experiment.py new file mode 100644 index 0000000..40586c3 --- /dev/null +++ b/BoriskovaDV/docs/data/1-st-exercise/experiment.py @@ -0,0 +1,126 @@ +import random +import time +import csv +import sys +sys.setrecursionlimit(20000) + +from linked_list_phonebook import ll_insert, ll_find, ll_delete, ll_list_all +from hash_table_phonebook import ht_insert, ht_find, ht_delete, ht_list_all +from bst_phonebook import bst_insert, bst_find, bst_delete, bst_list_all + +def generate_records(n, seed=42): + random.seed(seed) + records = [] + for i in range(1, n+1): + name = f"User_{i:05d}" + phone = f"{random.randint(100,999)}-{random.randint(1000,9999)}" + records.append((name, phone)) + return records + +def prepare_datasets(base_records): + shuffled = base_records.copy() + random.shuffle(shuffled) + sorted_records = sorted(base_records, key=lambda x: x[0]) + return shuffled, sorted_records + +def run_experiment(struct_funcs, records, mode_name, repeats=5): + results = [] + for rep in range(repeats): + struct = struct_funcs['create']() + + start = time.perf_counter() + for name, phone in records: + struct = struct_funcs['insert'](struct, name, phone) + end = time.perf_counter() + insert_time = end - start + + existing_names = [name for name, _ in records] + sample_existing = random.sample(existing_names, 100) + nonexistent = [f"NotExist_{i}" for i in range(10)] + search_names = sample_existing + nonexistent + random.shuffle(search_names) + + start = time.perf_counter() + for name in search_names: + _ = struct_funcs['find'](struct, name) + end = time.perf_counter() + find_time = end - start + + to_delete = random.sample(existing_names, 50) + start = time.perf_counter() + for name in to_delete: + struct = struct_funcs['delete'](struct, name) + end = time.perf_counter() + delete_time = end - start + + results.append({ + 'structure': struct_funcs['name'], + 'mode': mode_name, + 'repetition': rep+1, + 'insert_time': insert_time, + 'find_time': find_time, + 'delete_time': delete_time + }) + return results + +def main(): + N = 10000 + base_records = generate_records(N) + shuffled, sorted_records = prepare_datasets(base_records) + + structures = { + 'LinkedList': { + 'name': 'LinkedList', + 'create': lambda: None, + 'insert': ll_insert, + 'find': ll_find, + 'delete': ll_delete, + 'list_all': ll_list_all + }, + 'HashTable': { + 'name': 'HashTable', + 'create': lambda: [None] * 10, + 'insert': ht_insert, + 'find': ht_find, + 'delete': ht_delete, + 'list_all': ht_list_all + }, + 'BST': { + 'name': 'BST', + 'create': lambda: None, + 'insert': bst_insert, + 'find': bst_find, + 'delete': bst_delete, + 'list_all': bst_list_all + } + } + + all_results = [] + repeats = 5 + + for struct_name, funcs in structures.items(): + print(f"Testing {struct_name} on random order...") + res_random = run_experiment(funcs, shuffled, 'random', repeats) + all_results.extend(res_random) + + print(f"Testing {struct_name} on sorted order...") + res_sorted = run_experiment(funcs, sorted_records, 'sorted', repeats) + all_results.extend(res_sorted) + + with open('experiment_results.csv', 'w', newline='', encoding='utf-8') as f: + writer = csv.writer(f) + writer.writerow(['Structure', 'Mode', 'Repeat', 'Insert (sec)', 'Search (sec)', 'Delete (sec)']) + for r in all_results: + writer.writerow([ + r['structure'], + r['mode'], + r['repetition'], + f"{r['insert_time']:.6f}", + f"{r['find_time']:.6f}", + f"{r['delete_time']:.6f}" + ]) + + print("Experiment finished. Results saved to experiment_results.csv") + +if __name__ == '__main__': + main() \ No newline at end of file -- 2.43.0 From 5597f8a8a700dcc50179fcde7c9242be6ed6527d Mon Sep 17 00:00:00 2001 From: BoriskovaDV Date: Sun, 24 May 2026 18:02:07 +0000 Subject: [PATCH 6/9] [1] add plot_results.py --- .../docs/data/1-st-exercise/plot_results.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 BoriskovaDV/docs/data/1-st-exercise/plot_results.py diff --git a/BoriskovaDV/docs/data/1-st-exercise/plot_results.py b/BoriskovaDV/docs/data/1-st-exercise/plot_results.py new file mode 100644 index 0000000..d12703f --- /dev/null +++ b/BoriskovaDV/docs/data/1-st-exercise/plot_results.py @@ -0,0 +1,39 @@ +import pandas as pd +import matplotlib.pyplot as plt +import numpy as np + +df = pd.read_csv('experiment_results.csv') + +mean_times = df.groupby(['Structure', 'Mode'])[['Insert (sec)', 'Search (sec)', 'Delete (sec)']].mean().reset_index() + +structures = mean_times['Structure'].unique() +modes = mean_times['Mode'].unique() + +fig, axes = plt.subplots(1, 3, figsize=(15, 5)) + +operations = ['Insert (sec)', 'Search (sec)', 'Delete (sec)'] +titles = ['Insertion', 'Search', 'Deletion'] + +for ax, op, title in zip(axes, operations, titles): + x = np.arange(len(structures)) + width = 0.35 + + random_vals = [] + sorted_vals = [] + for s in structures: + random_row = mean_times[(mean_times['Structure'] == s) & (mean_times['Mode'] == 'random')] + sorted_row = mean_times[(mean_times['Structure'] == s) & (mean_times['Mode'] == 'sorted')] + random_vals.append(random_row[op].values[0] if not random_row.empty else 0) + sorted_vals.append(sorted_row[op].values[0] if not sorted_row.empty else 0) + + ax.bar(x - width/2, random_vals, width, label='Random') + ax.bar(x + width/2, sorted_vals, width, label='Sorted') + ax.set_xticks(x) + ax.set_xticklabels(structures) + ax.set_ylabel('Time (seconds)') + ax.set_title(title) + ax.legend() + +plt.tight_layout() +plt.savefig('performance_comparison.png', dpi=150) +plt.show() \ No newline at end of file -- 2.43.0 From 79dc0854a1fe67dc4e9dda2a3b830acb9b632781 Mon Sep 17 00:00:00 2001 From: BoriskovaDV Date: Sun, 24 May 2026 19:51:53 +0000 Subject: [PATCH 7/9] Upload files to "BoriskovaDV/docs" --- BoriskovaDV/docs/performance_comparison.png | Bin 0 -> 46891 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 BoriskovaDV/docs/performance_comparison.png diff --git a/BoriskovaDV/docs/performance_comparison.png b/BoriskovaDV/docs/performance_comparison.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba8bbf71307eb0ab457619c14ad52133a68d892 GIT binary patch literal 46891 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
    Y}WpXXlh{R%r) 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 X$rpXoAA}s`&*F6ke~MfC(P#e!mRIDR literal 0 HcmV?d00001 -- 2.43.0 From e3f4f4c57f687f15e3ea6a690276474b13d64e62 Mon Sep 17 00:00:00 2001 From: BoriskovaDV Date: Sun, 24 May 2026 19:52:19 +0000 Subject: [PATCH 8/9] [1] add plots and csv results --- .../data/1-st-exercise/experiment_results.csv | 31 ++++++++++++++++++ .../1-st-exercise/performance_comparison.png | Bin 0 -> 46891 bytes 2 files changed, 31 insertions(+) create mode 100644 BoriskovaDV/docs/data/1-st-exercise/experiment_results.csv create mode 100644 BoriskovaDV/docs/data/1-st-exercise/performance_comparison.png diff --git a/BoriskovaDV/docs/data/1-st-exercise/experiment_results.csv b/BoriskovaDV/docs/data/1-st-exercise/experiment_results.csv new file mode 100644 index 0000000..c699422 --- /dev/null +++ b/BoriskovaDV/docs/data/1-st-exercise/experiment_results.csv @@ -0,0 +1,31 @@ +Structure,Mode,Repeat,Insert (sec),Search (sec),Delete (sec) +LinkedList,random,1,4.432559,0.034196,0.014270 +LinkedList,random,2,4.999931,0.038043,0.020281 +LinkedList,random,3,4.771456,0.030191,0.014131 +LinkedList,random,4,4.707315,0.033500,0.016198 +LinkedList,random,5,4.721361,0.036586,0.011988 +LinkedList,sorted,1,4.139028,0.024011,0.010482 +LinkedList,sorted,2,4.212383,0.024592,0.011765 +LinkedList,sorted,3,4.674211,0.027756,0.012189 +LinkedList,sorted,4,4.610210,0.031519,0.012244 +LinkedList,sorted,5,4.565687,0.029739,0.012747 +HashTable,random,1,0.659990,0.003889,0.001728 +HashTable,random,2,0.666055,0.005980,0.002002 +HashTable,random,3,0.669948,0.004087,0.002176 +HashTable,random,4,0.661882,0.007439,0.001897 +HashTable,random,5,0.680420,0.004016,0.001649 +HashTable,sorted,1,0.648261,0.004277,0.002922 +HashTable,sorted,2,0.654924,0.004136,0.001793 +HashTable,sorted,3,0.645509,0.003900,0.002249 +HashTable,sorted,4,0.637906,0.004056,0.001657 +HashTable,sorted,5,0.643536,0.003846,0.001741 +BST,random,1,0.029415,0.000515,0.000183 +BST,random,2,0.027684,0.000216,0.000142 +BST,random,3,0.026213,0.000252,0.000159 +BST,random,4,0.026987,0.000207,0.000135 +BST,random,5,0.028321,0.000271,0.000183 +BST,sorted,1,10.293772,0.093178,0.053520 +BST,sorted,2,10.142204,0.088924,0.049079 +BST,sorted,3,10.142037,0.078281,0.059416 +BST,sorted,4,10.139818,0.100162,0.056881 +BST,sorted,5,10.102982,0.082247,0.051973 diff --git a/BoriskovaDV/docs/data/1-st-exercise/performance_comparison.png b/BoriskovaDV/docs/data/1-st-exercise/performance_comparison.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba8bbf71307eb0ab457619c14ad52133a68d892 GIT binary patch literal 46891 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
      Y}WpXXlh{R%r) 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 X$rpXoAA}s`&*F6ke~MfC(P#e!mRIDR literal 0 HcmV?d00001 -- 2.43.0 From e0b142c9946d94f6866d1fbdabcd2c5773bd4f71 Mon Sep 17 00:00:00 2001 From: BoriskovaDV Date: Sun, 24 May 2026 19:53:07 +0000 Subject: [PATCH 9/9] [1] add report for lab1 --- BoriskovaDV/docs/report1.md | 94 +++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 BoriskovaDV/docs/report1.md diff --git a/BoriskovaDV/docs/report1.md b/BoriskovaDV/docs/report1.md new file mode 100644 index 0000000..d37b89f --- /dev/null +++ b/BoriskovaDV/docs/report1.md @@ -0,0 +1,94 @@ +# Отчёт по лабораторной работе «Структуры данных для телефонного справочника» + +## 1. Постановка задачи + +В рамках работы требовалось реализовать три структуры данных «с нуля» (без использования встроенных коллекций, кроме базовых списков): + +- связный список, +- хеш-таблицу с цепочками, +- двоичное дерево поиска (несбалансированное). + +Для каждой структуры необходимо реализовать операции `insert`, `find`, `delete` и `list_all` (возврат всех записей, отсортированных по имени). Затем на наборе из 10 000 записей выполнить экспериментальное сравнение производительности в двух режимах: при случайном порядке вставки и при вставке записей, отсортированных по имени. Каждый эксперимент повторялся 5 раз. + +## 2. Результаты измерений + +Ниже приведены усреднённые по 5 повторам времена выполнения операций (в секундах). Исходные сырые данные сохранены в файле `experiment_results.csv`. + +| Структура | Режим | Вставка (с) | Поиск 110 имён (с) | Удаление 50 записей (с) | +|-------------|-------------|-------------|--------------------|-------------------------| +| LinkedList | случайный | 4.7265 | 0.0345 | 0.0154 | +| LinkedList | сортир. | 4.4403 | 0.0275 | 0.0119 | +| HashTable | случайный | 0.6677 | 0.0051 | 0.0019 | +| HashTable | сортир. | 0.6460 | 0.0040 | 0.0021 | +| BST | случайный | 0.0277 | 0.00029 | 0.00016 | +| BST | сортир. | 10.1642 | 0.0886 | 0.0542 | + +### Примечания к методике + +- **Вставка** – добавление всех 10 000 записей в пустую структуру. +- **Поиск** – 100 заведомо существующих имён + 10 несуществующих (общее количество вызовов 110). +- **Удаление** – 50 случайных существующих записей. +- Все замеры выполнены с помощью `time.perf_counter()`. +- Для хеш-таблицы использовалось 10 корзин. +- Рекурсивная глубина BST увеличена до 20 000, чтобы избежать переполнения стека. + +## 3. Анализ полученных данных + +### 3.1. Поведение BST при разных порядках ввода + +Двоичное дерево поиска сильно зависит от порядка поступления ключей. При случайном порядке средняя высота близка к логарифмической, что даёт отличную производительность: + +- вставка – **0.0277 с**, +- поиск – **0.00029 с** (самый быстрый среди всех структур в этом режиме). + +Однако при вставке отсортированных данных дерево вырождается в линейный список (каждый новый узел добавляется только в правое поддерево). Последствия: + +- время вставки возрастает **в 367 раз** (с 0.0277 до 10.16 с), +- поиск замедляется **в 305 раз**, +- удаление – **в 339 раз**. + +Вырожденное BST на отсортированных данных работает **медленнее даже связного списка** (вставка 10.16 с против 4.44 с, поиск 0.088 с против 0.027 с), что объясняется накладными расходами на рекурсивные вызовы и проверки. + +### 3.2. Хеш-таблица – устойчивость к порядку + +Хеш-таблица использует функцию `hash(name) % size`, которая равномерно рассеивает имена независимо от их лексикографического порядка. Поэтому результаты в двух режимах практически идентичны: + +- вставка: 0.668 с (случайный) против 0.646 с (отсортированный) – разница менее 4%, +- поиск: 0.0051 с против 0.0040 с, +- удаление: 0.0019 с против 0.0021 с. + +Небольшие расхождения находятся в пределах случайной вариации (зависит от коллизий, которые немного различаются при разном порядке вставки). Средняя сложность операций остаётся **O(1)**. + +### 3.3. Связный список – ожидаемо медленный + +Линейный список не обеспечивает прямого доступа, поэтому все операции (кроме удаления после нахождения) требуют обхода в среднем половины списка. Даже при сравнительно небольшом объёме данных (10 000 записей) времена велики: + +- вставка ≈ **4.6 с** (на два порядка хуже, чем у хеш-таблицы и BST на случайных данных), +- поиск ≈ **0.03 с** (в 6–10 раз медленнее, чем у других структур). + +Интересно, что на отсортированных данных список показывает немного лучшее время, чем на случайных. Причина: при вставке в конец отсортированного списка (имена идут в алфавитном порядке) новые узлы добавляются без поиска дубликатов? Но алгоритм `ll_insert` сначала проверяет наличие имени, проходя весь список. Поскольку все имена уникальны и не обновляются, каждый проход идёт до конца. Однако в отсортированном режиме имена добавляются в порядке возрастания, и при проверке дубликата мы проходим по уже существующим элементам, которые все меньше нового? Да, в отсортированном режиме каждое новое имя больше всех предыдущих, поэтому при поиске дубликата мы обходим весь существующий список. В случайном режиме новые имена могут встречаться раньше, и поиск останавливается раньше? Но в любом случае разница небольшая (около 6%), и в целом список остаётся медленным. + +### 3.4. Сравнение удаления + +Удаление в списке требует сначала найти элемент (O(n)), затем перелинковку. В хеш-таблице удаление сводится к удалению в коротком списке корзины (почти O(1)). В BST на случайных данных удаление очень быстрое (0.00016 с), на отсортированных – катастрофически замедляется (0.054 с). Для хеш-таблицы удаление немного быстрее, чем вставка, что естественно: при удалении не нужно создавать новый узел. + +## 4. Выводы и практические рекомендации + +Проведённое исследование наглядно демонстрирует сильные и слабые стороны каждой структуры. + +1. **Хеш-таблица** – лучший выбор для задач, где приоритетом является скорость всех операций (вставка, поиск, удаление), а порядок вывода данных не важен или может быть получен отдельной сортировкой. Стабильно высокая производительность вне зависимости от характера входных данных. В реальных проектах именно хеш-таблицы лежат в основе словарей (Python `dict`, Java `HashMap`). + +2. **Двоичное дерево поиска** – эффективно только при случайном или близком к случайному порядке поступления ключей. Даёт логарифмическую сложность и при этом позволяет получать данные в отсортированном виде за O(n) без дополнительной сортировки. Однако на реальных данных (например, заведомо отсортированных) производительность падает до O(n), что делает его непригодным без механизмов балансировки. На практике применяются сбалансированные варианты (AVL, красно-чёрные деревья). + +3. **Связный список** – не подходит для коллекций объёмом более нескольких сотен элементов из-за линейной сложности основных операций. Может использоваться только в очень специфических сценариях: очень редкий поиск, постоянные вставки/удаления в начало (но не в конец), или как строительный блок для других структур (например, для цепочек в хеш-таблице, что и было сделано в данной работе). + +### Итоговая таблица применимости + +| Критерий | Рекомендуемая структура | +|---------------------------------|---------------------------------------| +| Максимальная скорость всех операций | Хеш-таблица | +| Нужны данные в отсортированном порядке + данные поступают случайно | BST (но лучше сбалансированное) | +| Данные поступают уже отсортированными | Хеш-таблица (или балансируемое дерево) | +| Очень маленький объём (< 100 записей) | Любая, но проще список | + +В реальной разработке для телефонного справочника с большим числом записей и частыми запросами поиска оптимальным решением будет **хеш-таблица**. Если же дополнительно требуется частый вывод всего справочника по алфавиту, стоит рассмотреть сбалансированное дерево (например, встроенный в Python модуль `bisect` не даёт структуры данных, а `sortedcontainers` – сторонний). \ No newline at end of file -- 2.43.0