diff --git a/volkovim/__init__.py b/volkovim/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/volkovim/docs/data/Figure_1.png b/volkovim/docs/data/Figure_1.png new file mode 100644 index 0000000..9ad574f Binary files /dev/null and b/volkovim/docs/data/Figure_1.png differ diff --git a/volkovim/docs/data/Figure_2.png b/volkovim/docs/data/Figure_2.png new file mode 100644 index 0000000..a1d9f65 Binary files /dev/null and b/volkovim/docs/data/Figure_2.png differ diff --git a/volkovim/docs/data/Figure_3.png b/volkovim/docs/data/Figure_3.png new file mode 100644 index 0000000..db5b0df Binary files /dev/null and b/volkovim/docs/data/Figure_3.png differ diff --git a/volkovim/docs/data/results.csv b/volkovim/docs/data/results.csv new file mode 100644 index 0000000..c909858 --- /dev/null +++ b/volkovim/docs/data/results.csv @@ -0,0 +1,91 @@ +Structure,Order,Operation,Time +LinkedList,random,insert,0.02272110000012617 +LinkedList,random,find,0.00020389999917824753 +LinkedList,random,delete,0.00012740000056510326 +LinkedList,random,insert,0.022962700000789482 +LinkedList,random,find,0.00019210000027669594 +LinkedList,random,delete,0.00013299999955052044 +LinkedList,random,insert,0.023047099999530474 +LinkedList,random,find,0.000189200000022538 +LinkedList,random,delete,0.00013699999908567406 +LinkedList,random,insert,0.0228056000014476 +LinkedList,random,find,0.00019530000099621248 +LinkedList,random,delete,0.0001320000010309741 +LinkedList,random,insert,0.022504299999127397 +LinkedList,random,find,0.0001827000014600344 +LinkedList,random,delete,0.00012650000098801684 +HashTable,random,insert,0.006552200000442099 +HashTable,random,find,6.84000006003771e-05 +HashTable,random,delete,4.3999998524668626e-05 +HashTable,random,insert,0.006576800000402727 +HashTable,random,find,6.790000043110922e-05 +HashTable,random,delete,4.459999945538584e-05 +HashTable,random,insert,0.006557500000781147 +HashTable,random,find,6.779999966965988e-05 +HashTable,random,delete,4.2499999835854396e-05 +HashTable,random,insert,0.006657900001300732 +HashTable,random,find,6.579999899258837e-05 +HashTable,random,delete,3.990000004705507e-05 +HashTable,random,insert,0.0066283999985898845 +HashTable,random,find,6.589999975403771e-05 +HashTable,random,delete,4.270000135875307e-05 +BST,random,insert,0.005961099999694852 +BST,random,find,5.790000068373047e-05 +BST,random,delete,5.5900000006658956e-05 +BST,random,insert,0.005897299999560346 +BST,random,find,5.229999987932388e-05 +BST,random,delete,5.080000119050965e-05 +BST,random,insert,0.005889399999432499 +BST,random,find,5.32000012753997e-05 +BST,random,delete,4.749999970954377e-05 +BST,random,insert,0.006325000000288128 +BST,random,find,5.310000051395036e-05 +BST,random,delete,5.1900000471505336e-05 +BST,random,insert,0.00589380000019446 +BST,random,find,5.149999924469739e-05 +BST,random,delete,5.140000030223746e-05 +LinkedList,sorted,insert,0.021485899998879177 +LinkedList,sorted,find,0.0001861000000644708 +LinkedList,sorted,delete,0.00012830000014218967 +LinkedList,sorted,insert,0.020360300000902498 +LinkedList,sorted,find,0.00017280000065511558 +LinkedList,sorted,delete,0.00010759999895526562 +LinkedList,sorted,insert,0.02137589999983902 +LinkedList,sorted,find,0.00017079999997804407 +LinkedList,sorted,delete,8.949999937613029e-05 +LinkedList,sorted,insert,0.019899599999916973 +LinkedList,sorted,find,0.0001748000013321871 +LinkedList,sorted,delete,0.00011620000077527948 +LinkedList,sorted,insert,0.019986600000265753 +LinkedList,sorted,find,0.0001812999998946907 +LinkedList,sorted,delete,0.00011749999976018444 +HashTable,sorted,insert,0.005906399999730638 +HashTable,sorted,find,6.240000038815197e-05 +HashTable,sorted,delete,3.930000093532726e-05 +HashTable,sorted,insert,0.005912500000704313 +HashTable,sorted,find,6.050000047252979e-05 +HashTable,sorted,delete,3.8800000766059384e-05 +HashTable,sorted,insert,0.005913900000450667 +HashTable,sorted,find,6.050000047252979e-05 +HashTable,sorted,delete,3.96999985241564e-05 +HashTable,sorted,insert,0.005919999999605352 +HashTable,sorted,find,6.190000021888409e-05 +HashTable,sorted,delete,3.749999996216502e-05 +HashTable,sorted,insert,0.005881000000954373 +HashTable,sorted,find,6.089999988034833e-05 +HashTable,sorted,delete,3.7900001188972965e-05 +BST,sorted,insert,0.033791699999710545 +BST,sorted,find,0.000340900000082911 +BST,sorted,delete,0.00026059999981953297 +BST,sorted,insert,0.03474140000071202 +BST,sorted,find,0.0003206999990652548 +BST,sorted,delete,0.0002024000004894333 +BST,sorted,insert,0.03431230000023788 +BST,sorted,find,0.0003130000004603062 +BST,sorted,delete,0.00025209999876096845 +BST,sorted,insert,0.03444429999944987 +BST,sorted,find,0.0003271999994467478 +BST,sorted,delete,0.00017320000006293412 +BST,sorted,insert,0.03425440000137314 +BST,sorted,find,0.0003316999991511693 +BST,sorted,delete,0.00022639999951934442 diff --git a/volkovim/docs/report_1.docx b/volkovim/docs/report_1.docx new file mode 100644 index 0000000..08a385e Binary files /dev/null and b/volkovim/docs/report_1.docx differ diff --git a/volkovim/task1/__init__.py b/volkovim/task1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/volkovim/task1/histograms.py b/volkovim/task1/histograms.py new file mode 100644 index 0000000..7ae1594 --- /dev/null +++ b/volkovim/task1/histograms.py @@ -0,0 +1,45 @@ +import csv +import matplotlib.pyplot as plt +from collections import defaultdict + + +data = defaultdict(list) + +with open("results.csv", "r") as f: + reader = csv.DictReader(f) + + for row in reader: + key = (row["Structure"], row["Order"], row["Operation"]) + data[key].append(float(row["Time"])) + + +def avg(key): + return sum(data[key]) / len(data[key]) + + +structures = ["LinkedList", "HashTable", "BST"] +orders = ["random", "sorted"] +operations = ["insert", "find", "delete"] + + +for op in operations: + plt.figure() + + labels = [] + values = [] + + for struct in structures: + for order in orders: + key = (struct, order, op) + labels.append(f"{struct}\n{order}") + values.append(avg(key)) + + plt.bar(labels, values) + + plt.title(f"{op} (Histogram)") + plt.ylabel("Time (sec)") + plt.xticks(rotation=30) + plt.grid(axis="y") + + plt.tight_layout() + plt.show() \ No newline at end of file diff --git a/volkovim/task1/main.py b/volkovim/task1/main.py new file mode 100644 index 0000000..163dbe5 --- /dev/null +++ b/volkovim/task1/main.py @@ -0,0 +1,66 @@ +import csv + +from structures.LinkedList import ll_insert, ll_find, ll_delete +from structures.HashTable import ht_insert, ht_find, ht_delete +from structures.BinaryTree import bst_insert, bst_find, bst_delete + +from util.randomNames import generate_test_data +from util.timeTester import run_test + + +def main(): + structures = [ + ("LinkedList", ll_insert, ll_find, ll_delete), + ("HashTable", ht_insert, ht_find, ht_delete), + ("BST", bst_insert, bst_find, bst_delete) + ] + + modes = [ + ("random", False), + ("sorted", True) + ] + + results = [] + + N = 10000 + REPEATS = 5 + + for mode_name, is_sorted in modes: + base_records = generate_test_data(N, is_sorted) + + for struct_name, ins, fnd, dele in structures: + for i in range(REPEATS): + + stats = run_test(base_records, ins, fnd, dele) + + results.append([ + struct_name, + mode_name, + "insert", + stats["insert"] + ]) + + results.append([ + struct_name, + mode_name, + "find", + stats["find"] + ]) + + results.append([ + struct_name, + mode_name, + "delete", + stats["delete"] + ]) + + with open("results.csv", "w", newline="") as f: + writer = csv.writer(f) + writer.writerow(["Structure", "Order", "Operation", "Time"]) + writer.writerows(results) + + print("Готово: записано", len(results), "строк") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/volkovim/task1/structures/BinaryTree.py b/volkovim/task1/structures/BinaryTree.py new file mode 100644 index 0000000..b98af00 --- /dev/null +++ b/volkovim/task1/structures/BinaryTree.py @@ -0,0 +1,83 @@ +def bst_insert(root: dict | None, name: str, phone: str) -> dict: + new_node = {'name': name, 'phone': phone, 'left': None, 'right': None} + + if root is None: + return new_node + + current = root + + while True: + if name == current['name']: + current['phone'] = phone + return root + + if name < current['name']: + if current['left'] is None: + current['left'] = new_node + return root + current = current['left'] + else: + if current['right'] is None: + current['right'] = new_node + return root + current = current['right'] + + +def bst_find(root: dict | None, name: str) -> str | None: + current = root + + while current is not None: + if name == current['name']: + return current['phone'] + + if name < current['name']: + current = current['left'] + else: + current = current['right'] + + return None + + +def bst_min(node: dict) -> dict: + while node['left'] is not None: + node = node['left'] + return node + + +def bst_delete(root: dict | None, name: str) -> dict | None: + 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'] + + if root['right'] is None: + return root['left'] + + successor = bst_min(root['right']) + root['name'] = successor['name'] + root['phone'] = successor['phone'] + root['right'] = bst_delete(root['right'], successor['name']) + + return root + + +def bst_list_all(root: dict | None) -> list: + result = [] + + def inorder(node): + if node is None: + return + inorder(node['left']) + result.append((node['name'], node['phone'])) + inorder(node['right']) + + inorder(root) + return result \ No newline at end of file diff --git a/volkovim/task1/structures/HashTable.py b/volkovim/task1/structures/HashTable.py new file mode 100644 index 0000000..dd22790 --- /dev/null +++ b/volkovim/task1/structures/HashTable.py @@ -0,0 +1,51 @@ +from structures.LinkedList import * + + +def hash_func(name: str, size: int) -> int: + total = 0 + + for i, ch in enumerate(name): + total += ord(ch) * (i + 1) + + return total % size + + +def ht_insert(buckets: list | None, name: str, phone: str, size: int = 50) -> list: + if buckets is None: + buckets = [None] * size + + index = hash_func(name, len(buckets)) + buckets[index] = ll_insert(buckets[index], name, phone) + + return buckets + + +def ht_find(buckets: list | None, name: str) -> str | None: + if not buckets: + return None + + index = hash_func(name, len(buckets)) + return ll_find(buckets[index], name) + + +def ht_delete(buckets: list | None, name: str) -> list | None: + if not buckets: + return buckets + + index = hash_func(name, len(buckets)) + buckets[index] = ll_delete(buckets[index], name) + + return buckets + + +def ht_list_all(buckets: list | None) -> list: + if not buckets: + return [] + + result = [] + + for bucket in buckets: + if bucket is not None: + result.extend(ll_list_all(bucket)) + + return sorted(result, key=lambda x: x[0]) diff --git a/volkovim/task1/structures/LinkedList.py b/volkovim/task1/structures/LinkedList.py new file mode 100644 index 0000000..091bae4 --- /dev/null +++ b/volkovim/task1/structures/LinkedList.py @@ -0,0 +1,60 @@ +def ll_insert(head: dict | None, name: str, phone: str) -> dict: + if head is None: + return {'name': name, 'phone': phone, 'next': None} + + current = head + + while current is not None: + if current['name'] == name: + current['phone'] = phone + return head + + if current['next'] is None: + break + + current = current['next'] + + current['next'] = {'name': name, 'phone': phone, 'next': None} + return head + + +def ll_find(head: dict | None, name: str) -> str | None: + current = head + + while current is not None: + if current['name'] == name: + return current['phone'] + current = current['next'] + + return None + + +def ll_delete(head: dict | None, name: str) -> dict | None: + 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: dict | None) -> list: + records = [] + current = head + + while current is not None: + records.append((current['name'], current['phone'])) + current = current['next'] + + records.sort(key=lambda item: item[0]) + return records diff --git a/volkovim/task1/structures/__init__.py b/volkovim/task1/structures/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/volkovim/task1/util/__init__.py b/volkovim/task1/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/volkovim/task1/util/randomNames.py b/volkovim/task1/util/randomNames.py new file mode 100644 index 0000000..79ff6d3 --- /dev/null +++ b/volkovim/task1/util/randomNames.py @@ -0,0 +1,44 @@ +import random + + +names_pool = ( + "Иван", "Александр", "Михаил", "Дмитрий", "Сергей", "Андрей", "Алексей", "Николай", "Владимир", "Евгений", +"Павел", "Илья", "Роман", "Артём", "Константин", "Виктор", "Георгий", "Максим", "Василий", "Олег", +"Юрий", "Валерий", "Антон", "Кирилл", "Степан", "Денис", "Тимур", "Григорий", "Леонид", "Фёдор", +"Никита", "Ярослав", "Руслан", "Богдан", "Станислав", "Вячеслав", "Арсений", "Егор", "Захар", "Даниил", +"Матвей", "Тимофей", "Пётр", "Лев", "Семён", "Платон", "Давид", "Глеб", "Родион", "Святослав", +"Владислав", "Елисей", "Анатолий", "Ростислав", "Всеволод", "Мирослав", "Игнат", "Клим", "Евстафий", "Аркадий", +"Игорь", "Лука", "Филипп", "Альберт", "Эдуард", "Роберт", "Артур", "Карл", "Борис", "Вадим", +"Эмиль", "Оскар", "Геннадий", "Марк", "Виталий", "Назар", "Мирон", "Савелий", "Фома", "Еремей", +"Нестор", "Прохор", "Авраам", "Севастьян", "Евдоким", "Трофим", "Кузьма", "Фадей", "Наум", "Аким", +"Лаврентий", "Ипполит", "Панкрат", "Афанасий", "Евдокия", "Прасковья", "Марфа", "Агафья", "Ульяна", "Пелагея", +"Дарья", "Анастасия", "Екатерина", "Ольга", "Татьяна", "Светлана", "Наталья", "Ирина", "Вера", "Людмила", +"Галина", "Любовь", "Надежда", "Анна", "Мария", "Елена", "Юлия", "Ксения", "Полина", "Виктория", +"Алина", "Дарина", "Валерия", "Софья", "Вероника", "Арина", "Кира", "Милана", "Алиса", "Ева", +"Агата", "Злата", "Яна", "Василиса", "Стефания", "Диана", "Карина", "Лидия", "Алла", "Раиса" +) + +non_existent_names = ( + "Ноль", "Целковый", "Полушка", "Четвертушка", "Осьмушка" +) + + +def generate_phone(): + return str(random.randint(10000000000, 99999999999)) + + +def generate_test_data(n=10000, sorted_data=False): + records = [(random.choice(names_pool), generate_phone()) for _ in range(n)] + + if sorted_data: + records.sort(key=lambda x: x[0]) + + return records + + +def generate_find_set(): + return random.sample(names_pool, 100) + list(non_existent_names) + + +def generate_delete_set(): + return random.sample(names_pool, 50) \ No newline at end of file diff --git a/volkovim/task1/util/timeTester.py b/volkovim/task1/util/timeTester.py new file mode 100644 index 0000000..3a321b0 --- /dev/null +++ b/volkovim/task1/util/timeTester.py @@ -0,0 +1,30 @@ +import time +import random +from util.randomNames import names_pool, generate_find_set + + +def run_test(records, insert_func, find_func, delete_func): + structure = None + + start = time.perf_counter() + for name, phone in records: + structure = insert_func(structure, name, phone) + insert_time = time.perf_counter() - start + + find_set = generate_find_set() + + start = time.perf_counter() + for name in find_set: + find_func(structure, name) + find_time = time.perf_counter() - start + + start = time.perf_counter() + for name in random.sample(names_pool, 50): + structure = delete_func(structure, name) + delete_time = time.perf_counter() - start + + return { + "insert": insert_time, + "find": find_time, + "delete": delete_time + } \ No newline at end of file