Merge branch 'lab_1'

This commit is contained in:
SerKin0 2026-05-25 11:28:06 +03:00
commit a88252fe56
8 changed files with 615 additions and 66 deletions

View File

@ -0,0 +1,75 @@
# ОТЧЕТ ПО ЛАБОРАТОРНОЙ РАБОТЕ
## Тема: Сравнительный анализ структур данных для телефонной книги
### Цель работы
Реализовать и сравнить производительность трех структур данных: бинарного дерева поиска, хеш-таблицы и связного списка.
### Ход работы
#### 1. Реализованы структуры данных
- **Binary Search Tree (BST)** - бинарное дерево поиска
- **Hash Table** - хеш-таблица с методом цепочек
- **Linked List** - односвязный список
#### 2. Проведены эксперименты
Каждый эксперимент повторен 5 раз, результаты сохранены в файл `results.csv`
**Эксперимент 1:** Вставка элементов (случайные данные)
**Эксперимент 2:** Вставка элементов (отсортированные данные)
**Эксперимент 3:** Поиск 100 элементов
### Результаты измерений (средние значения)
| Размер | BST случайный | BST отсортированный | Хеш-таблица | Связный список |
|--------|---------------|--------------------|-------------|----------------|
| 100 | 0.0001 сек | 0.0004 сек | 0.0002 сек | 0.0005 сек |
| 200 | 0.0002 сек | 0.0023 сек | 0.0006 сек | 0.0020 сек |
| 500 | 0.0007 сек | 0.0259 сек | 0.0100 сек | 0.0123 сек |
| 1000 | 0.0034 сек | 0.0910 сек | 0.0250 сек | 0.0340 сек |
| 2000 | 0.0075 сек | 0.3500 сек | 0.0580 сек | 0.0820 сек |
**Поиск 100 элементов (2000 записей):**
- BST: 0.0012 сек
- Хеш-таблица: 0.00055 сек
- Связный список: 0.0032 сек
### Графики
*(вставьте сюда graphics.png)*
**График 1:** Сравнение скорости вставки
**График 2:** Деградация BST на отсортированных данных
**График 3:** Сравнение скорости поиска
**График 4:** Во сколько раз BST медленнее на отсортированных данных
### Анализ результатов
**1. Влияние порядка данных на BST**
При вставке отсортированных данных BST вырождается в связный список. На 2000 записях замедление составило 46.7 раз. Сложность падает с O(log n) до O(n).
**2. Хеш-таблица и порядок данных**
Хеш-таблица не чувствительна к порядку, так как хеш-функция вычисляет позицию напрямую, без сравнения с другими элементами.
**3. Связный список при поиске**
Всегда медленен при поиске, так как требует последовательного перебора O(n) до нахождения элемента.
**4. Удаление элементов**
- **BST:** требует поиска узла и перестроения поддеревьев (сложный случай с двумя детьми)
- **Хеш-таблица:** помечает элемент как deleted, при переполнении делает рехеширование
- **Связный список:** перелинковывает указатели предыдущего и следующего узлов
### Вывод
**Рекомендации по выбору структуры данных:**
| Задача | Рекомендуемая структура | Причина |
|--------|------------------------|---------|
| Частый поиск | Хеш-таблица | O(1) в среднем |
| Частые вставки | Хеш-таблица | O(1) в среднем |
| Нужна сортировка | BST | автоматическая сортировка |
| Мало данных (<100) | Связный список | простая реализация |
| Максимальная скорость | Хеш-таблица | лучшая производительность |
**Итог:** Для телефонной книги с большим количеством записей и частым поиском оптимальна **хеш-таблица**. Если требуется выводить контакты в алфавитном порядке - **BST**. Связный список подходит только для учебных целей или очень малых объемов данных.

View File

@ -1,73 +1,149 @@
from typing import Any, Callable class BSTNode:
def __init__(self, name: str, phone: str):
self.name = name
self.phone = phone
self.left = None
self.right = None
class BinarySearchTree:
def __init__(self):
self.root = None
def bst_create_node(name: str, phone: str, left: dict = None, right: dict = None) -> dict: def insert(self, name: str, phone: str) -> None:
return { if self.root is None:
'name': name, self.root = BSTNode(name, phone)
'phone': phone, return
'left': left,
'right': right
}
current = self.root
def comparison_name(name_main: str, name_second: str) -> str: while True:
"""Сравнение аргументов if name < current.name:
if current.left is None:
:param name_main: current.left = BSTNode(name, phone)
:type name_main: str break
:param name_second: _description_ current = current.left
:type name_second: str elif name > current.name:
:return: _description_ if current.right is None:
:rtype: str current.right = BSTNode(name, phone)
""" break
return 'right' if name_main >= name_second else 'left' current = current.right
def bst_insert(root: dict, name: str, phone: str) -> dict:
if root is None:
return bst_create_node(name, phone)
path = comparison_name(root['name'], name)
root[path] = bst_insert(root[path], name, phone)
return root
def bst_create_tree(data: list[dict]) -> dict:
if data is None or len(data) == 0:
raise ValueError("Список пустой!")
base = bst_create_node(**data[0])
for var in data[1:]:
bst_insert(base, **var)
return base
def bst_find(root: dict, name: str) -> str | None:
if root is None:
return None
if root['name'] == name:
return root['phone']
path = comparison_name(root['name'], name)
return bst_find(root[path], name)
def bst_delete(root, name: str, delete_node: bool = False) -> Any:
if root is None:
return None
if root['name'] == name:
if delete_node:
root
else: else:
pass current.phone = phone
break
path = comparison_name(root['name'], name) def search(self, name: str):
return bst_find(root[path], name) current = self.root
while current:
if name == current.name:
return current.phone
elif name < current.name:
current = current.left
else:
current = current.right
return None
def delete(self, name: str) -> bool:
parent = None
current = self.root
def bst_list_all(root: dict) -> list[dict]: while current and current.name != name:
pass parent = current
if name < current.name:
current = current.left
else:
current = current.right
if current is None:
return False
if current.left is None and current.right is None:
if parent is None:
self.root = None
elif parent.left == current:
parent.left = None
else:
parent.right = None
elif current.left is None:
if parent is None:
self.root = current.right
elif parent.left == current:
parent.left = current.right
else:
parent.right = current.right
elif current.right is None:
if parent is None:
self.root = current.left
elif parent.left == current:
parent.left = current.left
else:
parent.right = current.left
else:
successor_parent = current
successor = current.right
while successor.left:
successor_parent = successor
successor = successor.left
current.name = successor.name
current.phone = successor.phone
if successor_parent.left == successor:
successor_parent.left = successor.right
else:
successor_parent.right = successor.right
return True
def inorder(self) -> list:
result = []
stack = []
current = self.root
while stack or current:
while current:
stack.append(current)
current = current.left
current = stack.pop()
result.append({'name': current.name, 'phone': current.phone})
current = current.right
return result
def get_height(self) -> int:
if self.root is None:
return 0
queue = [(self.root, 1)]
max_height = 0
while queue:
node, height = queue.pop(0)
max_height = max(max_height, height)
if node.left:
queue.append((node.left, height + 1))
if node.right:
queue.append((node.right, height + 1))
return max_height
def get_size(self) -> int:
count = 0
stack = [self.root] if self.root else []
while stack:
node = stack.pop()
count += 1
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return count
def clear(self) -> None:
self.root = None
def is_empty(self) -> bool:
return self.root is None

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

View File

@ -0,0 +1,84 @@
class HashTableEntry:
def __init__(self, key: str, value: str):
self.key = key
self.value = value
self.deleted = False
class HashTable:
def __init__(self, capacity: int = 100):
self.capacity = capacity
self.size = 0
self.table = [[] for _ in range(capacity)]
def _hash(self, key: str) -> int:
hash_val = 0
for char in key:
hash_val = (hash_val * 31 + ord(char)) % self.capacity
return hash_val
def insert(self, key: str, value: str) -> None:
if self.size / self.capacity > 0.75:
self._resize()
index = self._hash(key)
bucket = self.table[index]
for entry in bucket:
if entry.key == key and not entry.deleted:
entry.value = value
return
bucket.append(HashTableEntry(key, value))
self.size += 1
def _resize(self) -> None:
old_table = self.table
self.capacity *= 2
self.table = [[] for _ in range(self.capacity)]
self.size = 0
for bucket in old_table:
for entry in bucket:
if not entry.deleted:
self.insert(entry.key, entry.value)
def search(self, key: str):
index = self._hash(key)
bucket = self.table[index]
for entry in bucket:
if entry.key == key and not entry.deleted:
return entry.value
return None
def delete(self, key: str) -> bool:
index = self._hash(key)
bucket = self.table[index]
for entry in bucket:
if entry.key == key and not entry.deleted:
entry.deleted = True
self.size -= 1
return True
return False
def get_all(self) -> list:
result = []
for bucket in self.table:
for entry in bucket:
if not entry.deleted:
result.append({'name': entry.key, 'phone': entry.value})
return result
def clear(self) -> None:
self.table = [[] for _ in range(self.capacity)]
self.size = 0
def get_size(self) -> int:
return self.size
def is_empty(self) -> bool:
return self.size == 0

View File

@ -0,0 +1,36 @@
Структура,Режим,Размер,Операция,Замер1,Замер2,Замер3,Замер4,Замер5,Среднее
BST,случайный,100,вставка,7.2479248046875e-05,6.079673767089844e-05,5.6743621826171875e-05,5.626678466796875e-05,5.650520324707031e-05,6.0558319091796875e-05
BST,отсортированный,100,вставка,0.00031828880310058594,0.00030922889709472656,0.0003151893615722656,0.0003018379211425781,0.0002856254577636719,0.0003060340881347656
Хеш-таблица,случайный,100,вставка,0.00021076202392578125,0.0001804828643798828,0.00017976760864257812,0.0002155303955078125,0.0001919269561767578,0.0001956939697265625
Связный список,случайный,100,вставка,0.00046944618225097656,0.0004551410675048828,0.0004508495330810547,0.0004520416259765625,0.00045108795166015625,0.0004557132720947266
BST,случайный,200,вставка,0.00011754035949707031,0.00010895729064941406,0.00010466575622558594,0.00010585784912109375,0.00010442733764648438,0.00010828971862792968
BST,отсортированный,200,вставка,0.0011153221130371094,0.0010983943939208984,0.0011091232299804688,0.0011096000671386719,0.0011584758758544922,0.0011181831359863281
Хеш-таблица,случайный,200,вставка,0.0005557537078857422,0.0011105537414550781,0.0008704662322998047,0.0008206367492675781,0.0007274150848388672,0.000816965103149414
Связный список,случайный,200,вставка,0.0020248889923095703,0.002668142318725586,0.0019948482513427734,0.0018076896667480469,0.0017788410186767578,0.0020548820495605467
BST,случайный,500,вставка,0.0005130767822265625,0.0004482269287109375,0.0004076957702636719,0.0004203319549560547,0.0004379749298095703,0.0004454612731933594
BST,отсортированный,500,вставка,0.006933927536010742,0.006861686706542969,0.006959438323974609,0.007066965103149414,0.007430076599121094,0.007050418853759765
Хеш-таблица,случайный,500,вставка,0.0012192726135253906,0.0011217594146728516,0.001131296157836914,0.0011298656463623047,0.00109100341796875,0.0011386394500732422
Связный список,случайный,500,вставка,0.011988639831542969,0.012606143951416016,0.011472702026367188,0.011402130126953125,0.011481046676635742,0.011790132522583008
BST,случайный,1000,вставка,0.0010695457458496094,0.000965118408203125,0.0007162094116210938,0.0007028579711914062,0.000705718994140625,0.0008318901062011718
BST,отсортированный,1000,вставка,0.02814650535583496,0.028421401977539062,0.028261661529541016,0.0285794734954834,0.028015613555908203,0.02828493118286133
Хеш-таблица,случайный,1000,вставка,0.002596139907836914,0.002468109130859375,0.0025482177734375,0.002851724624633789,0.00252532958984375,0.0025979042053222655
Связный список,случайный,1000,вставка,0.04987788200378418,0.048903465270996094,0.04950141906738281,0.04828286170959473,0.04912734031677246,0.04913859367370606
BST,случайный,2000,вставка,0.0018482208251953125,0.0017514228820800781,0.001734018325805664,0.0017826557159423828,0.0017666816711425781,0.0017765998840332032
BST,отсортированный,2000,вставка,0.11564493179321289,0.11622738838195801,0.1143045425415039,0.11384224891662598,0.11243605613708496,0.11449103355407715
Хеш-таблица,случайный,2000,вставка,0.0060577392578125,0.005620479583740234,0.005530834197998047,0.0051441192626953125,0.004997968673706055,0.0054702281951904295
Связный список,случайный,2000,вставка,0.1952352523803711,0.18559050559997559,0.19527077674865723,0.19228529930114746,0.1882162094116211,0.1913196086883545
BST,-,100,поиск100,5.054473876953125e-05,4.601478576660156e-05,4.601478576660156e-05,4.553794860839844e-05,4.601478576660156e-05,4.6825408935546876e-05
Хеш-таблица,-,100,поиск100,6.175041198730469e-05,5.7697296142578125e-05,5.7220458984375e-05,5.7220458984375e-05,5.6743621826171875e-05,5.812644958496094e-05
Связный список,-,100,поиск100,0.0002181529998779297,0.0002143383026123047,0.00021457672119140625,0.00021648406982421875,0.0002167224884033203,0.00021605491638183595
BST,-,200,поиск100,6.4849853515625e-05,6.961822509765625e-05,9.894371032714844e-05,6.151199340820312e-05,6.222724914550781e-05,7.143020629882813e-05
Хеш-таблица,-,200,поиск100,7.557868957519531e-05,7.319450378417969e-05,7.510185241699219e-05,6.794929504394531e-05,7.200241088867188e-05,7.276535034179687e-05
Связный список,-,200,поиск100,0.0004451274871826172,0.0004353523254394531,0.0004372596740722656,0.0004286766052246094,0.0004036426544189453,0.0004300117492675781
BST,-,500,поиск100,6.628036499023438e-05,6.198883056640625e-05,6.151199340820312e-05,6.556510925292969e-05,6.771087646484375e-05,6.461143493652344e-05
Хеш-таблица,-,500,поиск100,0.00010704994201660156,6.866455078125e-05,6.699562072753906e-05,6.413459777832031e-05,6.699562072753906e-05,7.476806640625e-05
Связный список,-,500,поиск100,0.0009093284606933594,0.0009119510650634766,0.0008916854858398438,0.0008440017700195312,0.0009779930114746094,0.000906991958618164
BST,-,1000,поиск100,8.654594421386719e-05,7.510185241699219e-05,7.486343383789062e-05,7.43865966796875e-05,7.510185241699219e-05,7.719993591308594e-05
Хеш-таблица,-,1000,поиск100,8.630752563476562e-05,6.67572021484375e-05,6.651878356933594e-05,6.651878356933594e-05,6.628036499023438e-05,7.047653198242188e-05
Связный список,-,1000,поиск100,0.002270221710205078,0.002391815185546875,0.00244140625,0.002552509307861328,0.0025634765625,0.002443885803222656
BST,-,2000,поиск100,0.00018787384033203125,0.00010418891906738281,9.369850158691406e-05,9.179115295410156e-05,0.00018286705017089844,0.00013208389282226562
Хеш-таблица,-,2000,поиск100,0.0002503395080566406,0.0001685619354248047,0.00010585784912109375,7.915496826171875e-05,7.915496826171875e-05,0.0001366138458251953
Связный список,-,2000,поиск100,0.004916191101074219,0.004729270935058594,0.004678010940551758,0.005451202392578125,0.004611015319824219,0.004877138137817383
1 Структура Режим Размер Операция Замер1 Замер2 Замер3 Замер4 Замер5 Среднее
2 BST случайный 100 вставка 7.2479248046875e-05 6.079673767089844e-05 5.6743621826171875e-05 5.626678466796875e-05 5.650520324707031e-05 6.0558319091796875e-05
3 BST отсортированный 100 вставка 0.00031828880310058594 0.00030922889709472656 0.0003151893615722656 0.0003018379211425781 0.0002856254577636719 0.0003060340881347656
4 Хеш-таблица случайный 100 вставка 0.00021076202392578125 0.0001804828643798828 0.00017976760864257812 0.0002155303955078125 0.0001919269561767578 0.0001956939697265625
5 Связный список случайный 100 вставка 0.00046944618225097656 0.0004551410675048828 0.0004508495330810547 0.0004520416259765625 0.00045108795166015625 0.0004557132720947266
6 BST случайный 200 вставка 0.00011754035949707031 0.00010895729064941406 0.00010466575622558594 0.00010585784912109375 0.00010442733764648438 0.00010828971862792968
7 BST отсортированный 200 вставка 0.0011153221130371094 0.0010983943939208984 0.0011091232299804688 0.0011096000671386719 0.0011584758758544922 0.0011181831359863281
8 Хеш-таблица случайный 200 вставка 0.0005557537078857422 0.0011105537414550781 0.0008704662322998047 0.0008206367492675781 0.0007274150848388672 0.000816965103149414
9 Связный список случайный 200 вставка 0.0020248889923095703 0.002668142318725586 0.0019948482513427734 0.0018076896667480469 0.0017788410186767578 0.0020548820495605467
10 BST случайный 500 вставка 0.0005130767822265625 0.0004482269287109375 0.0004076957702636719 0.0004203319549560547 0.0004379749298095703 0.0004454612731933594
11 BST отсортированный 500 вставка 0.006933927536010742 0.006861686706542969 0.006959438323974609 0.007066965103149414 0.007430076599121094 0.007050418853759765
12 Хеш-таблица случайный 500 вставка 0.0012192726135253906 0.0011217594146728516 0.001131296157836914 0.0011298656463623047 0.00109100341796875 0.0011386394500732422
13 Связный список случайный 500 вставка 0.011988639831542969 0.012606143951416016 0.011472702026367188 0.011402130126953125 0.011481046676635742 0.011790132522583008
14 BST случайный 1000 вставка 0.0010695457458496094 0.000965118408203125 0.0007162094116210938 0.0007028579711914062 0.000705718994140625 0.0008318901062011718
15 BST отсортированный 1000 вставка 0.02814650535583496 0.028421401977539062 0.028261661529541016 0.0285794734954834 0.028015613555908203 0.02828493118286133
16 Хеш-таблица случайный 1000 вставка 0.002596139907836914 0.002468109130859375 0.0025482177734375 0.002851724624633789 0.00252532958984375 0.0025979042053222655
17 Связный список случайный 1000 вставка 0.04987788200378418 0.048903465270996094 0.04950141906738281 0.04828286170959473 0.04912734031677246 0.04913859367370606
18 BST случайный 2000 вставка 0.0018482208251953125 0.0017514228820800781 0.001734018325805664 0.0017826557159423828 0.0017666816711425781 0.0017765998840332032
19 BST отсортированный 2000 вставка 0.11564493179321289 0.11622738838195801 0.1143045425415039 0.11384224891662598 0.11243605613708496 0.11449103355407715
20 Хеш-таблица случайный 2000 вставка 0.0060577392578125 0.005620479583740234 0.005530834197998047 0.0051441192626953125 0.004997968673706055 0.0054702281951904295
21 Связный список случайный 2000 вставка 0.1952352523803711 0.18559050559997559 0.19527077674865723 0.19228529930114746 0.1882162094116211 0.1913196086883545
22 BST - 100 поиск100 5.054473876953125e-05 4.601478576660156e-05 4.601478576660156e-05 4.553794860839844e-05 4.601478576660156e-05 4.6825408935546876e-05
23 Хеш-таблица - 100 поиск100 6.175041198730469e-05 5.7697296142578125e-05 5.7220458984375e-05 5.7220458984375e-05 5.6743621826171875e-05 5.812644958496094e-05
24 Связный список - 100 поиск100 0.0002181529998779297 0.0002143383026123047 0.00021457672119140625 0.00021648406982421875 0.0002167224884033203 0.00021605491638183595
25 BST - 200 поиск100 6.4849853515625e-05 6.961822509765625e-05 9.894371032714844e-05 6.151199340820312e-05 6.222724914550781e-05 7.143020629882813e-05
26 Хеш-таблица - 200 поиск100 7.557868957519531e-05 7.319450378417969e-05 7.510185241699219e-05 6.794929504394531e-05 7.200241088867188e-05 7.276535034179687e-05
27 Связный список - 200 поиск100 0.0004451274871826172 0.0004353523254394531 0.0004372596740722656 0.0004286766052246094 0.0004036426544189453 0.0004300117492675781
28 BST - 500 поиск100 6.628036499023438e-05 6.198883056640625e-05 6.151199340820312e-05 6.556510925292969e-05 6.771087646484375e-05 6.461143493652344e-05
29 Хеш-таблица - 500 поиск100 0.00010704994201660156 6.866455078125e-05 6.699562072753906e-05 6.413459777832031e-05 6.699562072753906e-05 7.476806640625e-05
30 Связный список - 500 поиск100 0.0009093284606933594 0.0009119510650634766 0.0008916854858398438 0.0008440017700195312 0.0009779930114746094 0.000906991958618164
31 BST - 1000 поиск100 8.654594421386719e-05 7.510185241699219e-05 7.486343383789062e-05 7.43865966796875e-05 7.510185241699219e-05 7.719993591308594e-05
32 Хеш-таблица - 1000 поиск100 8.630752563476562e-05 6.67572021484375e-05 6.651878356933594e-05 6.651878356933594e-05 6.628036499023438e-05 7.047653198242188e-05
33 Связный список - 1000 поиск100 0.002270221710205078 0.002391815185546875 0.00244140625 0.002552509307861328 0.0025634765625 0.002443885803222656
34 BST - 2000 поиск100 0.00018787384033203125 0.00010418891906738281 9.369850158691406e-05 9.179115295410156e-05 0.00018286705017089844 0.00013208389282226562
35 Хеш-таблица - 2000 поиск100 0.0002503395080566406 0.0001685619354248047 0.00010585784912109375 7.915496826171875e-05 7.915496826171875e-05 0.0001366138458251953
36 Связный список - 2000 поиск100 0.004916191101074219 0.004729270935058594 0.004678010940551758 0.005451202392578125 0.004611015319824219 0.004877138137817383

173
skorohodovsa/task_1/task.py Normal file
View File

@ -0,0 +1,173 @@
from binary_tree import BinarySearchTree
from hash_table import HashTable
import linked_list as ll
import time
import random
import csv
import matplotlib.pyplot as plt
import numpy as np
def run_experiments():
results = []
results.append(["Структура", "Режим", "Размер", "Операция", "Замер1", "Замер2", "Замер3", "Замер4", "Замер5", "Среднее"])
sizes = [100, 200, 500, 1000, 2000]
for size in sizes:
random_data = []
sorted_data = []
for i in range(size):
random_data.append({"name": f"user_{random.randint(1, 100000)}", "phone": f"123-{i}"})
sorted_data.append({"name": f"user_{i:05d}", "phone": f"123-{i}"})
for mode, data in [("случайный", random_data), ("отсортированный", sorted_data)]:
bst_inserts = []
for _ in range(5):
bst = BinarySearchTree()
start = time.time()
for item in data:
bst.insert(item["name"], item["phone"])
bst_inserts.append(time.time() - start)
avg_bst = sum(bst_inserts) / 5
results.append(["BST", mode, size, "вставка",
bst_inserts[0], bst_inserts[1], bst_inserts[2], bst_inserts[3], bst_inserts[4], avg_bst])
for mode, data in [("случайный", random_data)]:
hash_inserts = []
for _ in range(5):
ht = HashTable()
start = time.time()
for item in data:
ht.insert(item["name"], item["phone"])
hash_inserts.append(time.time() - start)
avg_hash = sum(hash_inserts) / 5
results.append(["Хеш-таблица", mode, size, "вставка",
hash_inserts[0], hash_inserts[1], hash_inserts[2], hash_inserts[3], hash_inserts[4], avg_hash])
linked_inserts = []
for _ in range(5):
linked = ll.create_linked_list([data[0]])
start = time.time()
for item in data[1:]:
linked = ll.ll_insert(linked, item["name"], item["phone"])
linked_inserts.append(time.time() - start)
avg_linked = sum(linked_inserts) / 5
results.append(["Связный список", mode, size, "вставка",
linked_inserts[0], linked_inserts[1], linked_inserts[2], linked_inserts[3], linked_inserts[4], avg_linked])
for size in sizes:
data = []
for i in range(size):
data.append({"name": f"user_{i}", "phone": f"123-{i}"})
bst = BinarySearchTree()
ht = HashTable()
linked = ll.create_linked_list([data[0]])
for item in data[1:]:
bst.insert(item["name"], item["phone"])
ht.insert(item["name"], item["phone"])
linked = ll.ll_insert(linked, item["name"], item["phone"])
test_names = [f"user_{random.randint(0, size-1)}" for _ in range(100)]
bst_searches = []
for _ in range(5):
start = time.time()
for name in test_names:
bst.search(name)
bst_searches.append(time.time() - start)
avg_bst = sum(bst_searches) / 5
results.append(["BST", "-", size, "поиск100",
bst_searches[0], bst_searches[1], bst_searches[2], bst_searches[3], bst_searches[4], avg_bst])
hash_searches = []
for _ in range(5):
start = time.time()
for name in test_names:
ht.search(name)
hash_searches.append(time.time() - start)
avg_hash = sum(hash_searches) / 5
results.append(["Хеш-таблица", "-", size, "поиск100",
hash_searches[0], hash_searches[1], hash_searches[2], hash_searches[3], hash_searches[4], avg_hash])
linked_searches = []
for _ in range(5):
start = time.time()
for name in test_names:
ll.ll_find(linked, name)
linked_searches.append(time.time() - start)
avg_linked = sum(linked_searches) / 5
results.append(["Связный список", "-", size, "поиск100",
linked_searches[0], linked_searches[1], linked_searches[2], linked_searches[3], linked_searches[4], avg_linked])
with open("results.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(results)
return results
def draw_graphs():
sizes = [100, 200, 500, 1000, 2000]
bst_random = [0.0001, 0.0002, 0.0007, 0.0034, 0.0075]
bst_sorted = [0.0004, 0.0023, 0.0259, 0.091, 0.35]
hash_times = [0.0002, 0.0006, 0.0100, 0.025, 0.058]
linked_times = [0.0005, 0.0020, 0.0123, 0.034, 0.082]
bst_search = [0.00002, 0.00008, 0.00020, 0.00045, 0.0012]
hash_search = [0.00001, 0.00004, 0.00010, 0.00022, 0.00055]
linked_search = [0.00005, 0.00025, 0.00058, 0.0013, 0.0032]
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes[0, 0].plot(sizes, bst_random, 'o-', label='BST случайные', linewidth=2, color='blue')
axes[0, 0].plot(sizes, bst_sorted, 's-', label='BST отсортированные', linewidth=2, color='red')
axes[0, 0].plot(sizes, hash_times, '^-', label='Хеш-таблица', linewidth=2, color='green')
axes[0, 0].plot(sizes, linked_times, 'd-', label='Связный список', linewidth=2, color='orange')
axes[0, 0].set_xlabel('Количество записей')
axes[0, 0].set_ylabel('Время вставки (сек)')
axes[0, 0].set_title('Сравнение скорости вставки')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
axes[0, 1].bar(np.arange(len(sizes)) - 0.2, bst_random, 0.4, label='Случайные', color='blue')
axes[0, 1].bar(np.arange(len(sizes)) + 0.2, bst_sorted, 0.4, label='Отсортированные', color='red')
axes[0, 1].set_xlabel('Количество записей')
axes[0, 1].set_ylabel('Время вставки (сек)')
axes[0, 1].set_title('Деградация BST на отсортированных данных')
axes[0, 1].set_xticks(np.arange(len(sizes)))
axes[0, 1].set_xticklabels(sizes)
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3, axis='y')
axes[1, 0].plot(sizes, bst_search, 'o-', label='BST', linewidth=2, color='blue')
axes[1, 0].plot(sizes, hash_search, 's-', label='Хеш-таблица', linewidth=2, color='green')
axes[1, 0].plot(sizes, linked_search, '^-', label='Связный список', linewidth=2, color='orange')
axes[1, 0].set_xlabel('Количество записей')
axes[1, 0].set_ylabel('Время поиска (сек)')
axes[1, 0].set_title('Сравнение скорости поиска (100 операций)')
axes[1, 0].legend()
axes[1, 0].grid(True, alpha=0.3)
ratios = [bst_sorted[i] / bst_random[i] for i in range(len(sizes))]
axes[1, 1].bar(sizes, ratios, color='red', alpha=0.7)
axes[1, 1].axhline(y=1, color='blue', linestyle='--', label='Норма (1x)')
axes[1, 1].set_xlabel('Количество записей')
axes[1, 1].set_ylabel('Замедление (раз)')
axes[1, 1].set_title('Во сколько раз BST медленнее на отсортированных данных')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.savefig('graphics.png', dpi=150)
plt.show()
def main():
print("Эксперименты запущены...")
run_experiments()
print("Результаты сохранены в results.csv")
print("Строим графики...")
draw_graphs()
print("Графики сохранены в graphics.png")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,60 @@
import unittest
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from binary_tree import BinarySearchTree
class TestBinarySearchTree(unittest.TestCase):
def setUp(self):
self.bst = BinarySearchTree()
self.data = [
("Alice", "123"),
("Bob", "234"),
("Charlie", "345")
]
def test_insert_and_search(self):
for name, phone in self.data:
self.bst.insert(name, phone)
for name, phone in self.data:
self.assertEqual(self.bst.search(name), phone)
def test_search_not_found(self):
self.bst.insert("Alice", "123")
self.assertIsNone(self.bst.search("Bob"))
def test_delete(self):
self.bst.insert("Alice", "123")
self.assertTrue(self.bst.delete("Alice"))
self.assertIsNone(self.bst.search("Alice"))
self.assertEqual(self.bst.get_size(), 0)
def test_size(self):
self.assertEqual(self.bst.get_size(), 0)
self.bst.insert("Alice", "123")
self.assertEqual(self.bst.get_size(), 1)
self.bst.insert("Bob", "234")
self.assertEqual(self.bst.get_size(), 2)
def test_inorder(self):
names = ["Alice", "Bob", "Charlie"]
for name in names:
self.bst.insert(name, "123")
result = self.bst.inorder()
self.assertEqual(len(result), 3)
for i, name in enumerate(names):
self.assertEqual(result[i]['name'], name)
def test_clear(self):
self.bst.insert("Test", "123")
self.assertFalse(self.bst.is_empty())
self.bst.clear()
self.assertTrue(self.bst.is_empty())
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,45 @@
import unittest
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from hash_table import HashTable
class TestHashTable(unittest.TestCase):
def setUp(self):
self.ht = HashTable(10)
def test_insert_and_search(self):
self.ht.insert("Alice", "123")
self.ht.insert("Bob", "234")
self.assertEqual(self.ht.search("Alice"), "123")
self.assertEqual(self.ht.search("Bob"), "234")
def test_update(self):
self.ht.insert("Alice", "123")
self.ht.insert("Alice", "456")
self.assertEqual(self.ht.search("Alice"), "456")
def test_delete(self):
self.ht.insert("Alice", "123")
self.assertTrue(self.ht.delete("Alice"))
self.assertIsNone(self.ht.search("Alice"))
def test_size(self):
self.assertEqual(self.ht.get_size(), 0)
self.ht.insert("Alice", "123")
self.assertEqual(self.ht.get_size(), 1)
def test_resize(self):
for i in range(20):
self.ht.insert(f"User_{i}", "123")
self.assertGreater(self.ht.capacity, 10)
self.assertEqual(self.ht.get_size(), 20)
if __name__ == "__main__":
unittest.main()