diff --git a/nehoroshevaa/Task 1/code/BinaryTree.py b/nehoroshevaa/Task 1/code/BinaryTree.py new file mode 100644 index 0000000..520db72 --- /dev/null +++ b/nehoroshevaa/Task 1/code/BinaryTree.py @@ -0,0 +1,71 @@ +#Узел — словарь: {'name': 'Имя', 'phone': '123', 'left': None, 'right': None}. +def bst_insert(root, name, phone): + #рекурсивно или итеративно вставляет, возвращает новый корень (если корень меняется). + if root is None: + return {'name': name,'phone': phone,'left': None,'right': None} + + if name < root['name']: + root['left'] = bst_insert(root['left'], name, phone) + + elif name > root['name']: + root['right'] = bst_insert(root['right'], name, phone) + + else: + root['phone'] = phone + + return root + + +def bst_find(root, name): + if root is None: + return None + + if name == root['name']: + return root['phone'] + + if name < root['name']: + return bst_find(root['left'], name) + + return bst_find(root['right'], name) + + +def bst_delete(root, name): + #удаление, возвращает новый корень. + if root is None: + return None + + if name < root['name']: + root['left'] = bst_delete(root['left'], name) + + elif name > root['name']: + root['right'] = bst_delete(root['right'], name) + + else: + if root['left'] is None: + return root['right'] + + if root['right'] is None: + return root['left'] + + min_node = root['right'] + while min_node['left'] is not None: + min_node = min_node['left'] + + root['name'] = min_node['name'] + root['phone'] = min_node['phone'] + + root['right'] = bst_delete(root['right'], min_node['name']) + + return root + + +def bst_list_all(root): + # центрированный обход (рекурсивно собирает записи в отсортированном порядке). + if root is None: + return [] + + return ( + bst_list_all(root['left']) + + [(root['name'], root['phone'])] + + bst_list_all(root['right']) + ) \ No newline at end of file diff --git a/nehoroshevaa/Task 1/code/HashTable.py b/nehoroshevaa/Task 1/code/HashTable.py new file mode 100644 index 0000000..13b1988 --- /dev/null +++ b/nehoroshevaa/Task 1/code/HashTable.py @@ -0,0 +1,56 @@ +#Аналогично ht_find, ht_delete, ht_list_all (последняя собирает все записи из всех бакетов и сортирует). +from code.LinkedList import * + +def create_buckets(size=1000): + return [None] * size + +def hash_function(name, bucket_size): + hash_value = 0 + + for char in name: + hash_value = (hash_value * 31 + ord(char)) % bucket_size + + return hash_value + +def ht_insert(buckets, name, phone): + #вычисляет индекс, вызывает ll_insert для соответствующего бакета. + if buckets is None: + buckets = create_buckets() + + index = hash_function(name, len(buckets)) + buckets[index] = ll_insert(buckets[index], name, phone) + + return buckets + +def ht_find(buckets, name): + if not buckets: + return None + + index = hash_function(name, len(buckets)) + return ll_find(buckets[index], name) + +def ht_delete(buckets, name): + if not buckets: + return buckets + + index = hash_function(name, len(buckets)) + buckets[index] = ll_delete(buckets[index], name) + + return buckets + +def ht_list_all(buckets): + if not buckets: + return [] + + records = [] + + for bucket in buckets: + current = bucket + + while current is not None: + records.append((current['name'], current['phone'])) + current = current['next'] + + records.sort(key=lambda x: x[0]) + + return records \ No newline at end of file diff --git a/nehoroshevaa/Task 1/code/LinkedList.py b/nehoroshevaa/Task 1/code/LinkedList.py new file mode 100644 index 0000000..03d36b9 --- /dev/null +++ b/nehoroshevaa/Task 1/code/LinkedList.py @@ -0,0 +1,62 @@ +def ll_insert(head, name, phone): + #проходит до конца (или сразу добавляет в конец) и возвращает новую голову (если вставка в начало) или изменяет список по ссылке. Удобнее возвращать новую голову, если вставка может быть в начало. + 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: + current['next'] = {'name': name, 'phone': phone, 'next': None} + return head + + current = current['next'] + + +def ll_find(head, name): + # ищет узел, возвращает телефон или None. + current = head + + while current is not None: + if current['name'] == name: + return current['phone'] + current = current['next'] + + return None + + +def ll_delete(head, name): + # удаляет узел, возвращает новую голову. + if head is None: + return None + + if head['name'] == name: + return head['next'] + + current = head + + while current['next'] is not None: + if current['next']['name'] == name: + current['next'] = current['next']['next'] + return head + current = current['next'] + + return head + + +def ll_list_all(head): + #собирает все записи в список и сортирует (сортировка вынесена отдельно). + result = [] + current = head + + while current is not None: + result.append((current['name'], current['phone'])) + current = current['next'] + + result.sort(key=lambda x: x[0]) + + return result \ No newline at end of file diff --git a/nehoroshevaa/Task 1/code/__init__.py b/nehoroshevaa/Task 1/code/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nehoroshevaa/Task 1/exp.py b/nehoroshevaa/Task 1/exp.py new file mode 100644 index 0000000..4949ef2 --- /dev/null +++ b/nehoroshevaa/Task 1/exp.py @@ -0,0 +1,138 @@ +import sys +sys.setrecursionlimit(20000) +import time +import random +import csv + +from code.LinkedList import * +from code.HashTable import * +from code.BinaryTree import * + + + +def generate_data(n=10000): + return [(f"User_{i:05d}", f"+7-900-{i:05d}") for i in range(n)] + + +def prepare_data(n=10000): + data = generate_data(n) + + shuffled = data[:] + random.shuffle(shuffled) + + sorted_data = sorted(data, key=lambda x: x[0]) + + return shuffled, sorted_data + + + +def measure_find(find_func, obj, data): + exist = random.sample([x[0] for x in data], 100) + fake = [f"None_{i}" for i in range(10)] + names = exist + fake + + start = time.perf_counter() + + for name in names: + find_func(obj, name) + + return time.perf_counter() - start + + + +def measure_delete(delete_func, obj, data): + names = random.sample([x[0] for x in data], 50) + + start = time.perf_counter() + + for name in names: + obj = delete_func(obj, name) + + return time.perf_counter() - start + + + +def test_linked_list(data): + head = None + + start = time.perf_counter() + for name, phone in data: + head = ll_insert(head, name, phone) + insert_time = time.perf_counter() - start + + find_time = measure_find(ll_find, head, data) + delete_time = measure_delete(ll_delete, head, data) + + return insert_time, find_time, delete_time + + + +def test_hash_table(data): + buckets = create_buckets(1000) + + start = time.perf_counter() + for name, phone in data: + ht_insert(buckets, name, phone) + insert_time = time.perf_counter() - start + + find_time = measure_find(ht_find, buckets, data) + delete_time = measure_delete(ht_delete, buckets, data) + + return insert_time, find_time, delete_time + + +def test_bst(data): + root = None + + start = time.perf_counter() + for name, phone in data: + root = bst_insert(root, name, phone) + insert_time = time.perf_counter() - start + + find_time = measure_find(bst_find, root, data) + delete_time = measure_delete(bst_delete, root, data) + + return insert_time, find_time, delete_time + + +def run(): + + results = [] + results.append(["Structure", "Order", "Insert", "Find", "Delete"]) + + for i in range(5): + + shuffled, sorted_data = prepare_data() + + # -------- LinkedList -------- + i1, f1, d1 = test_linked_list(shuffled) + results.append(["LinkedList", "shuffled", i1, f1, d1]) + + i1, f1, d1 = test_linked_list(sorted_data) + results.append(["LinkedList", "sorted", i1, f1, d1]) + + # -------- HashTable -------- + i2, f2, d2 = test_hash_table(shuffled) + results.append(["HashTable", "shuffled", i2, f2, d2]) + + i2, f2, d2 = test_hash_table(sorted_data) + results.append(["HashTable", "sorted", i2, f2, d2]) + + # -------- BST -------- + i3, f3, d3 = test_bst(shuffled) + results.append(["BST", "shuffled", i3, f3, d3]) + + i3, f3, d3 = test_bst(sorted_data) + results.append(["BST", "sorted", i3, f3, d3]) + + + + with open("results.csv", "w", newline="") as f: + writer = csv.writer(f) + writer.writerows(results) + + print("Готово! results.csv создан") + + +if __name__ == "__main__": + run() \ No newline at end of file diff --git a/nehoroshevaa/docs/data_task1/delete.png b/nehoroshevaa/docs/data_task1/delete.png new file mode 100644 index 0000000..86e8a8d Binary files /dev/null and b/nehoroshevaa/docs/data_task1/delete.png differ diff --git a/nehoroshevaa/docs/data_task1/find.png b/nehoroshevaa/docs/data_task1/find.png new file mode 100644 index 0000000..6e066f6 Binary files /dev/null and b/nehoroshevaa/docs/data_task1/find.png differ diff --git a/nehoroshevaa/docs/data_task1/insert.png b/nehoroshevaa/docs/data_task1/insert.png new file mode 100644 index 0000000..c875e0c Binary files /dev/null and b/nehoroshevaa/docs/data_task1/insert.png differ diff --git a/nehoroshevaa/docs/data_task1/plot.py b/nehoroshevaa/docs/data_task1/plot.py new file mode 100644 index 0000000..2fe1096 --- /dev/null +++ b/nehoroshevaa/docs/data_task1/plot.py @@ -0,0 +1,51 @@ + +import csv +import matplotlib.pyplot as plt +from collections import defaultdict + + +data = [] + +with open("results.csv", "r") as f: + reader = csv.reader(f) + next(reader) # header + for row in reader: + structure, order, insert, find, delete = row + data.append((structure, order, float(insert), float(find), float(delete))) + + +def group(metric_index): + result = defaultdict(list) + for s, o, ins, f, d in data: + key = (s, o) + result[key].append([ins, f, d][metric_index]) + return result + + +def save_plot(metric_name, index, filename): + + grouped = group(index) + + plt.figure() + + labels = [] + + for (structure, order), values in grouped.items(): + label = f"{structure}-{order}" + labels.append(label) + plt.plot(values, label=label) + + plt.title(metric_name) + plt.xlabel("Run") + plt.ylabel("Time (sec)") + plt.legend() + + plt.savefig(filename, dpi=300, bbox_inches="tight") + plt.close() + + +save_plot("INSERT TIME", 0, "insert.png") +save_plot("FIND TIME", 1, "find.png") +save_plot("DELETE TIME", 2, "delete.png") + +print("Графики сохранены: insert.png, find.png, delete.png") \ No newline at end of file diff --git a/nehoroshevaa/docs/data_task1/results.csv b/nehoroshevaa/docs/data_task1/results.csv new file mode 100644 index 0000000..a80753b --- /dev/null +++ b/nehoroshevaa/docs/data_task1/results.csv @@ -0,0 +1,31 @@ +Structure,Order,Insert,Find,Delete +LinkedList,shuffled,3.1266312,0.0240491,0.0153019 +LinkedList,sorted,2.1736874,0.0176649,0.0123909 +HashTable,shuffled,0.0102941,0.000103,5.22E-05 +HashTable,sorted,0.0093038,0.0001008,5.37E-05 +BST,shuffled,0.0154676,0.000154,9.03E-05 +BST,sorted,8.3014441,0.0768616,0.0345065 +LinkedList,shuffled,3.2182401,0.0256622,0.0177542 +LinkedList,sorted,2.2604362,0.0199027,0.0131383 +HashTable,shuffled,0.0110818,0.0001227,5.32E-05 +HashTable,sorted,0.0098066,0.0001021,5.52E-05 +BST,shuffled,0.0184675,0.0001531,9.83E-05 +BST,sorted,8.6233891,0.0829446,0.0509548 +LinkedList,shuffled,3.2111766,0.0260377,0.0221557 +LinkedList,sorted,2.6125727,0.0275846,0.0190955 +HashTable,shuffled,0.014219,0.0001666,0.0003187 +HashTable,sorted,0.0138165,0.0001425,7.94E-05 +BST,shuffled,0.0234246,0.0002257,0.0001382 +BST,sorted,8.9193103,0.0615153,0.0415436 +LinkedList,shuffled,3.4287802,0.0276346,0.0178373 +LinkedList,sorted,2.4205873,0.0211635,0.0157121 +HashTable,shuffled,0.0113899,0.0001118,5.63E-05 +HashTable,sorted,0.0116161,0.0001284,6.88E-05 +BST,shuffled,0.0221165,0.0001773,0.0001002 +BST,sorted,9.0077053,0.1054247,0.0477643 +LinkedList,shuffled,3.2640041,0.0345332,0.0232472 +LinkedList,sorted,2.827502,0.0201937,0.0141592 +HashTable,shuffled,0.0105407,0.0001501,8.18E-05 +HashTable,sorted,0.0102284,0.0001005,5.58E-05 +BST,shuffled,0.0166355,0.0001603,9.34E-05 +BST,sorted,8.2043019,0.0622669,0.0375809 diff --git a/nehoroshevaa/docs/report_1.docx b/nehoroshevaa/docs/report_1.docx new file mode 100644 index 0000000..25fcb2f Binary files /dev/null and b/nehoroshevaa/docs/report_1.docx differ