Пункт 3: реализованы структуры данных (LinkedList, HashTable, BST)

This commit is contained in:
semyanovra 2026-05-15 18:43:27 +03:00
parent f42be3b51a
commit b367852062
3 changed files with 208 additions and 0 deletions

88
src/bst.py Normal file
View File

@ -0,0 +1,88 @@
# bst.py
# Двоичное дерево поиска по имени
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['left'] = bst_insert(root['left'], name, phone)
elif name > root['name']:
root['right'] = bst_insert(root['right'], name, phone)
else: # имя уже существует обновляем телефон
root['phone'] = phone
return root
def bst_find(root, name):
"""Возвращает телефон или None."""
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 _min_node(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
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']
# Узел с двумя детьми: находим минимальный в правом поддереве
temp = _min_node(root['right'])
root['name'] = temp['name']
root['phone'] = temp['phone']
root['right'] = bst_delete(root['right'], temp['name'])
return root
def bst_list_all(root):
"""
Центрированный (in-order) обход возвращает записи,
уже отсортированные по имени.
"""
def _inorder(node, result):
if node is None:
return
_inorder(node['left'], result)
result.append((node['name'], node['phone']))
_inorder(node['right'], result)
records = []
_inorder(root, records)
return records

46
src/hash_table.py Normal file
View File

@ -0,0 +1,46 @@
# hash_table.py
# Хеш-таблица с цепочками (использует linked_list.py)
import linked_list as ll
def create_hash_table(size=1000):
"""
Создаёт пустую хеш-таблицу.
size количество корзин (рекомендуется простое число).
"""
return [None] * size
def _hash(name, table_size):
"""Простая хеш-функция на основе суммы кодов символов."""
return sum(ord(ch) for ch in name) % table_size
def ht_insert(table, name, phone):
"""Вставляет или обновляет запись."""
idx = _hash(name, len(table))
# Вставляем в связный список в этой корзине
table[idx] = ll.ll_insert(table[idx], name, phone)
def ht_find(table, name):
"""Ищет телефон по имени."""
idx = _hash(name, len(table))
return ll.ll_find(table[idx], name)
def ht_delete(table, name):
"""Удаляет запись по имени."""
idx = _hash(name, len(table))
table[idx] = ll.ll_delete(table[idx], name)
def ht_list_all(table):
"""
Собирает все записи из всех корзин,
возвращает отсортированный по имени список.
"""
records = []
for bucket in table:
# Каждая корзина голова связного списка
current = bucket
while current is not None:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return record

74
src/linked_list.py Normal file
View File

@ -0,0 +1,74 @@
# linked_list.py
# Связный список для телефонного справочника
def create_node(name, phone):
"""Создаёт новый узел-словарь."""
return {'name': name, 'phone': phone, 'next': None}
def ll_insert(head, name, phone):
"""
Вставляет или обновляет запись.
Если имя уже существует обновляет телефон.
Если нет добавляет в конец списка.
Возвращает голову списка (может измениться, если вставка в начало).
"""
# Если список пуст создаём первый узел
if head is None:
return create_node(name, phone)
# Проверяем, не находится ли имя в первом узле
if head['name'] == name:
head['phone'] = phone
return head
# Ищем узел с таким именем или конец списка
current = head
while current['next'] is not None:
if current['next']['name'] == name:
current['next']['phone'] = phone
return head
current = current['next']
# Имя не найдено добавляем в конец
current['next'] = create_node(name, phone)
return head
def ll_find(head, name):
"""Ищет телефон по имени. Возвращает phone или None."""
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):
"""
Возвращает список всех записей в виде [(name, phone), ...],
отсортированный по имени. Сама структура не сортируется.
"""
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 record