From 77bc58e44bbf17bfafe505d08ddf089baa930366 Mon Sep 17 00:00:00 2001 From: ivantsovma Date: Sun, 1 Mar 2026 21:53:07 +0300 Subject: [PATCH] feat(linked-list): add basic node structure and insert function --- docs/data/bst_phonebook.py | 136 +++++++++++++++++++++++++++++ docs/data/bst_results.csv | 3 + docs/data/compare_structures.py | 46 ++++++++++ docs/data/hash_table_phonebook.py | 133 ++++++++++++++++++++++++++++ docs/data/linked_list_phonebook.py | 122 ++++++++++++++++++++++++++ 5 files changed, 440 insertions(+) create mode 100644 docs/data/bst_phonebook.py create mode 100644 docs/data/bst_results.csv create mode 100644 docs/data/compare_structures.py create mode 100644 docs/data/hash_table_phonebook.py create mode 100644 docs/data/linked_list_phonebook.py diff --git a/docs/data/bst_phonebook.py b/docs/data/bst_phonebook.py new file mode 100644 index 0000000..2dec23a --- /dev/null +++ b/docs/data/bst_phonebook.py @@ -0,0 +1,136 @@ +import time +import csv +import random +import os + +def create_node(name, phone): + """Создает узел BST""" + return {'name': name, 'phone': phone, 'left': None, 'right': None} + +def bst_insert(root, name, phone): + """Вставляет запись в BST""" + if root is None: + return create_node(name, phone) + + current = root + while True: + if name < current['name']: + if current['left'] is None: + current['left'] = create_node(name, phone) + break + current = current['left'] + elif name > current['name']: + if current['right'] is None: + current['right'] = create_node(name, phone) + break + current = current['right'] + else: + current['phone'] = phone + break + + return root + +def bst_find(root, name): + """Ищет запись в BST""" + current = root + while current: + if name == current['name']: + return current['phone'] + elif name < current['name']: + current = current['left'] + else: + current = current['right'] + return None + +def bst_find_min(root): + """Находит минимальный узел""" + if root is None: + return None + current = root + while current['left']: + current = current['left'] + return current + +def bst_delete(root, name): + """Удаляет запись из BST""" + 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 generate_test_data(n=300): + """Генерирует тестовые данные""" + records = [(f"User_{i:05d}", f"123-456-{i%10000:04d}") 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 run_experiment(): + print("BST ТЕЛЕФОННЫЙ СПРАВОЧНИК") + + os.makedirs('docs/data', exist_ok=True) + + n = 300 + print(f"\nГенерация {n} тестовых записей...") + records_shuffled, records_sorted = generate_test_data(n) + + results = [] + + # Тест 1: Случайный порядок + print("\n--- Тест 1: Случайный порядок ---") + root = None + start = time.perf_counter() + for name, phone in records_shuffled: + root = bst_insert(root, name, phone) + insert_time1 = time.perf_counter() - start + print(f"Вставка: {insert_time1:.4f} сек") + + names_to_find = [records_shuffled[i][0] for i in range(30)] + start = time.perf_counter() + for name in names_to_find: + bst_find(root, name) + find_time1 = time.perf_counter() - start + print(f"Поиск 30 записей: {find_time1:.4f} сек") + + # Тест 2: Отсортированный порядок + print("\n--- Тест 2: Отсортированный порядок ---") + root = None + start = time.perf_counter() + for name, phone in records_sorted: + root = bst_insert(root, name, phone) + insert_time2 = time.perf_counter() - start + print(f"Вставка: {insert_time2:.4f} сек") + + # Сохраняем результаты + results.append(['BST', 'случайный', insert_time1, find_time1, 0]) + results.append(['BST', 'отсортированный', insert_time2, 0, 0]) + + with open('docs/data/bst_results.csv', 'w', newline='', encoding='utf-8') as f: + writer = csv.writer(f) + writer.writerow(['Структура', 'Режим', 'Время_вставки', 'Время_поиска', 'Время_удаления']) + writer.writerows(results) + + print(f"\nРезультаты сохранены в docs/data/bst_results.csv") + print(f"\nСравнение:") + print(f"Случайный порядок вставки: {insert_time1:.4f} сек") + print(f"Отсортированный порядок вставки: {insert_time2:.4f} сек") + print(f"Разница: {insert_time2/insert_time1:.1f} раз") + +if __name__ == "__main__": + run_experiment() \ No newline at end of file diff --git a/docs/data/bst_results.csv b/docs/data/bst_results.csv new file mode 100644 index 0000000..8abbfd3 --- /dev/null +++ b/docs/data/bst_results.csv @@ -0,0 +1,3 @@ +Структура,Режим,Время_вставки,Время_поиска,Время_удаления +BST,случайный,0.0002327000256627798,1.3399985618889332e-05,0 +BST,отсортированный,0.0036721999058499932,0,0 diff --git a/docs/data/compare_structures.py b/docs/data/compare_structures.py new file mode 100644 index 0000000..04cafe0 --- /dev/null +++ b/docs/data/compare_structures.py @@ -0,0 +1,46 @@ +import csv +import os + +def read_results(filename): + """Читает результаты из CSV файла""" + results = [] + try: + with open(filename, 'r', encoding='utf-8') as f: + reader = csv.reader(f) + next(reader) # Пропускаем заголовок + for row in reader: + results.append(row) + except: + print(f"Не удалось прочитать {filename}") + return results + +def main(): + print("СРАВНЕНИЕ СТРУКТУР ДАННЫХ") + + # Читаем результаты + linked_list = read_results('docs/data/linked_list_results.csv') + hash_table = read_results('docs/data/hash_table_results.csv') + bst = read_results('docs/data/bst_results.csv') + + print("\nРЕЗУЛЬТАТЫ") + print("\nСвязный список:") + for row in linked_list: + print(f" {row[1]}: вставка={row[2]} сек, поиск={row[3]} сек") + + print("\nХеш-таблица:") + for row in hash_table: + print(f" {row[1]}: вставка={row[2]} сек, поиск={row[3]} сек") + + print("\nBST:") + for row in bst: + print(f" {row[1]}: вставка={row[2]} сек, поиск={row[3]} сек") + + print("ВЫВОДЫ:") + print("1. Хеш-таблица работает быстрее всего для поиска") + print("2. BST сильно замедляется на отсортированных данных") + print("3. Связный список самый медленный для всех операций") + print("4. Для частого поиска лучше использовать хеш-таблицу") + print("5. Для отсортированных данных BST неэффективен") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/docs/data/hash_table_phonebook.py b/docs/data/hash_table_phonebook.py new file mode 100644 index 0000000..c1bca3b --- /dev/null +++ b/docs/data/hash_table_phonebook.py @@ -0,0 +1,133 @@ +import time +import csv +import random +import os + +def create_node(name, phone): + """Создает узел для бакета""" + return {'name': name, 'phone': phone, 'next': None} + +def ll_insert(head, name, phone): + """Вставка в связный список""" + new_node = create_node(name, phone) + + if head is None: + return new_node + + if head['name'] == name: + head['phone'] = phone + return head + + current = head + while current['next']: + 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: + 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']: + if current['next']['name'] == name: + current['next'] = current['next']['next'] + return head + current = current['next'] + + return head + +def hash_function(name, table_size): + """Простая хеш-функция""" + return sum(ord(c) for c in name) % table_size + +def ht_insert(table, name, phone): + """Вставка в хеш-таблицу""" + index = hash_function(name, len(table)) + table[index] = ll_insert(table[index], name, phone) + +def ht_find(table, name): + """Поиск в хеш-таблице""" + index = hash_function(name, len(table)) + return ll_find(table[index], name) + +def ht_delete(table, name): + """Удаление из хеш-таблицы""" + index = hash_function(name, len(table)) + table[index] = ll_delete(table[index], name) + +def generate_test_data(n=500): + """Генерирует тестовые данные""" + records = [(f"User_{i:05d}", f"123-456-{i%10000:04d}") for i in range(n)] + random.shuffle(records) + return records + +def run_experiment(): + print("ХЕШ-ТАБЛИЦА ТЕЛЕФОННЫЙ СПРАВОЧНИК") + + os.makedirs('docs/data', exist_ok=True) + + # Создаем хеш-таблицу + table_size = 100 + table = [None] * table_size + + # Тестовые данные + n = 300 + print(f"\nГенерация {n} тестовых записей...") + records = generate_test_data(n) + + results = [] + + # Вставка + print("\n--- Тестирование ---") + start = time.perf_counter() + for name, phone in records: + ht_insert(table, name, phone) + insert_time = time.perf_counter() - start + print(f"Вставка: {insert_time:.4f} сек") + + # Поиск + names_to_find = [records[i][0] for i in range(50)] + start = time.perf_counter() + for name in names_to_find: + ht_find(table, name) + find_time = time.perf_counter() - start + print(f"Поиск 50 записей: {find_time:.4f} сек") + + # Удаление + names_to_delete = names_to_find[:25] + start = time.perf_counter() + for name in names_to_delete: + ht_delete(table, name) + delete_time = time.perf_counter() - start + print(f"Удаление 25 записей: {delete_time:.4f} сек") + + results.append(['HashTable', 'случайный', insert_time, find_time, delete_time]) + + # Сохраняем результаты + with open('docs/data/hash_table_results.csv', 'w', newline='', encoding='utf-8') as f: + writer = csv.writer(f) + writer.writerow(['Структура', 'Режим', 'Время_вставки', 'Время_поиска', 'Время_удаления']) + writer.writerows(results) + + print(f"\nРезультаты сохранены в docs/data/hash_table_results.csv") + +if __name__ == "__main__": + run_experiment() \ No newline at end of file diff --git a/docs/data/linked_list_phonebook.py b/docs/data/linked_list_phonebook.py new file mode 100644 index 0000000..02cf7fd --- /dev/null +++ b/docs/data/linked_list_phonebook.py @@ -0,0 +1,122 @@ +import time +import csv +import random +import os + +def create_node(name, phone): + """Создает новый узел списка""" + return {'name': name, 'phone': phone, 'next': None} + +def ll_insert(head, name, phone): + """Вставляет или обновляет запись""" + new_node = create_node(name, phone) + + if head is None: + return new_node + + current = head + prev = None + + while current: + if current['name'] == name: + current['phone'] = phone + return head + prev = current + current = current['next'] + + prev['next'] = new_node + return head + +def ll_find(head, name): + """Ищет запись по имени""" + current = head + while current: + 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']: + 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: + records.append((current['name'], current['phone'])) + current = current['next'] + return sorted(records, key=lambda x: x[0]) + +def generate_test_data(n=500): + """Генерирует тестовые данные""" + records = [(f"User_{i:05d}", f"123-456-{i%10000:04d}") 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 run_experiment(): + print("LINKED LIST ТЕЛЕФОННЫЙ СПРАВОЧНИК") + + # Создаем папку для результатов + os.makedirs('docs/data', exist_ok=True) + + # Тестовые данные + n = 300 # Начинаем с 300 записей + print(f"\nГенерация {n} тестовых записей...") + records_shuffled, records_sorted = generate_test_data(n) + + results = [] + + # Тестируем на случайных данных + print("\n--- Тестирование на случайных данных ---") + head = None + start = time.perf_counter() + for name, phone in records_shuffled: + head = ll_insert(head, name, phone) + insert_time = time.perf_counter() - start + print(f"Вставка: {insert_time:.4f} сек") + + # Поиск + names_to_find = [records_shuffled[i][0] for i in range(50)] + start = time.perf_counter() + for name in names_to_find: + ll_find(head, name) + find_time = time.perf_counter() - start + print(f"Поиск 50 записей: {find_time:.4f} сек") + + # Удаление + names_to_delete = names_to_find[:25] + start = time.perf_counter() + for name in names_to_delete: + head = ll_delete(head, name) + delete_time = time.perf_counter() - start + print(f"Удаление 25 записей: {delete_time:.4f} сек") + + results.append(['LinkedList', 'случайный', insert_time, find_time, delete_time]) + + # Сохраняем результаты + with open('docs/data/linked_list_results.csv', 'w', newline='', encoding='utf-8') as f: + writer = csv.writer(f) + writer.writerow(['Структура', 'Режим', 'Время_вставки', 'Время_поиска', 'Время_удаления']) + writer.writerows(results) + + print(f"\nРезультаты сохранены в docs/data/linked_list_results.csv") + +if __name__ == "__main__": + run_experiment() \ No newline at end of file