forked from UNN/2026-rff_mp
Merge branch 'lab_1'
This commit is contained in:
commit
a88252fe56
75
skorohodovsa/task_1/README.md
Normal file
75
skorohodovsa/task_1/README.md
Normal 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**. Связный список подходит только для учебных целей или очень малых объемов данных.
|
||||
|
|
@ -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:
|
||||
return {
|
||||
'name': name,
|
||||
'phone': phone,
|
||||
'left': left,
|
||||
'right': right
|
||||
}
|
||||
def insert(self, name: str, phone: str) -> None:
|
||||
if self.root is None:
|
||||
self.root = BSTNode(name, phone)
|
||||
return
|
||||
|
||||
|
||||
def comparison_name(name_main: str, name_second: str) -> str:
|
||||
"""Сравнение аргументов
|
||||
|
||||
:param name_main:
|
||||
:type name_main: str
|
||||
:param name_second: _description_
|
||||
:type name_second: str
|
||||
:return: _description_
|
||||
:rtype: str
|
||||
"""
|
||||
return 'right' if name_main >= name_second else 'left'
|
||||
|
||||
|
||||
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
|
||||
current = self.root
|
||||
while True:
|
||||
if name < current.name:
|
||||
if current.left is None:
|
||||
current.left = BSTNode(name, phone)
|
||||
break
|
||||
current = current.left
|
||||
elif name > current.name:
|
||||
if current.right is None:
|
||||
current.right = BSTNode(name, phone)
|
||||
break
|
||||
current = current.right
|
||||
else:
|
||||
pass
|
||||
current.phone = phone
|
||||
break
|
||||
|
||||
path = comparison_name(root['name'], name)
|
||||
return bst_find(root[path], name)
|
||||
def search(self, name: str):
|
||||
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]:
|
||||
pass
|
||||
while current and current.name != name:
|
||||
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
|
||||
BIN
skorohodovsa/task_1/graphics.png
Normal file
BIN
skorohodovsa/task_1/graphics.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 180 KiB |
84
skorohodovsa/task_1/hash_table.py
Normal file
84
skorohodovsa/task_1/hash_table.py
Normal 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
|
||||
36
skorohodovsa/task_1/results.csv
Normal file
36
skorohodovsa/task_1/results.csv
Normal 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
|
||||
|
173
skorohodovsa/task_1/task.py
Normal file
173
skorohodovsa/task_1/task.py
Normal 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()
|
||||
|
|
@ -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()
|
||||
45
skorohodovsa/task_1/test/test_task_3.py
Normal file
45
skorohodovsa/task_1/test/test_task_3.py
Normal 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()
|
||||
Loading…
Reference in New Issue
Block a user