forked from UNN/2026-rff_mp
feat(linked-list): add basic node structure and insert function
This commit is contained in:
parent
68114824da
commit
77bc58e44b
136
docs/data/bst_phonebook.py
Normal file
136
docs/data/bst_phonebook.py
Normal file
|
|
@ -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()
|
||||||
3
docs/data/bst_results.csv
Normal file
3
docs/data/bst_results.csv
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
Структура,Режим,Время_вставки,Время_поиска,Время_удаления
|
||||||
|
BST,случайный,0.0002327000256627798,1.3399985618889332e-05,0
|
||||||
|
BST,отсортированный,0.0036721999058499932,0,0
|
||||||
|
46
docs/data/compare_structures.py
Normal file
46
docs/data/compare_structures.py
Normal file
|
|
@ -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()
|
||||||
133
docs/data/hash_table_phonebook.py
Normal file
133
docs/data/hash_table_phonebook.py
Normal file
|
|
@ -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()
|
||||||
122
docs/data/linked_list_phonebook.py
Normal file
122
docs/data/linked_list_phonebook.py
Normal file
|
|
@ -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()
|
||||||
Loading…
Reference in New Issue
Block a user