diff --git a/skorohodovsa/task_1/README.md b/skorohodovsa/task_1/README.md new file mode 100644 index 0000000..b45fdca --- /dev/null +++ b/skorohodovsa/task_1/README.md @@ -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**. Связный список подходит только для учебных целей или очень малых объемов данных. diff --git a/skorohodovsa/task_1/binary_tree.py b/skorohodovsa/task_1/binary_tree.py index ab8f633..8627980 100644 --- a/skorohodovsa/task_1/binary_tree.py +++ b/skorohodovsa/task_1/binary_tree.py @@ -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 - -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 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) +class BinarySearchTree: + def __init__(self): + self.root = None - path = comparison_name(root['name'], name) - root[path] = bst_insert(root[path], name, phone) + def insert(self, name: str, phone: str) -> None: + if self.root is None: + self.root = BSTNode(name, phone) + return + + 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: + current.phone = phone + break - 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: + 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 - 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 + def delete(self, name: str) -> bool: + parent = None + current = self.root + + 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: - pass + 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 - path = comparison_name(root['name'], name) - return bst_find(root[path], name) - - -def bst_list_all(root: dict) -> list[dict]: - pass \ No newline at end of file + 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 \ No newline at end of file diff --git a/skorohodovsa/task_1/graphics.png b/skorohodovsa/task_1/graphics.png new file mode 100644 index 0000000..cbb5af1 Binary files /dev/null and b/skorohodovsa/task_1/graphics.png differ diff --git a/skorohodovsa/task_1/hash_table.py b/skorohodovsa/task_1/hash_table.py new file mode 100644 index 0000000..96c3a99 --- /dev/null +++ b/skorohodovsa/task_1/hash_table.py @@ -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 \ No newline at end of file diff --git a/skorohodovsa/task_1/results.csv b/skorohodovsa/task_1/results.csv new file mode 100644 index 0000000..b5303c4 --- /dev/null +++ b/skorohodovsa/task_1/results.csv @@ -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 diff --git a/skorohodovsa/task_1/task.py b/skorohodovsa/task_1/task.py new file mode 100644 index 0000000..cbaeb5e --- /dev/null +++ b/skorohodovsa/task_1/task.py @@ -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() \ No newline at end of file diff --git a/skorohodovsa/task_1/test/test_task_2.py b/skorohodovsa/task_1/test/test_task_2.py index e69de29..dc18e81 100644 --- a/skorohodovsa/task_1/test/test_task_2.py +++ b/skorohodovsa/task_1/test/test_task_2.py @@ -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() \ No newline at end of file diff --git a/skorohodovsa/task_1/test/test_task_3.py b/skorohodovsa/task_1/test/test_task_3.py new file mode 100644 index 0000000..60f4c77 --- /dev/null +++ b/skorohodovsa/task_1/test/test_task_3.py @@ -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() \ No newline at end of file