From 8124c755f8f6d4e65aa4be95e60e0aec9f7bc738 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Fri, 20 Mar 2026 20:06:29 +0300 Subject: [PATCH 01/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=D1=8B?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8=20=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82?= =?UTF-8?q?=D1=83=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/task-1/BinaryTree.py | 20 ++++++++++++++++++++ MusinAA/task-1/HashTable.py | 18 ++++++++++++++++++ MusinAA/task-1/LinkedList.py | 25 +++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 MusinAA/task-1/BinaryTree.py create mode 100644 MusinAA/task-1/HashTable.py create mode 100644 MusinAA/task-1/LinkedList.py diff --git a/MusinAA/task-1/BinaryTree.py b/MusinAA/task-1/BinaryTree.py new file mode 100644 index 0000000..aa39c0e --- /dev/null +++ b/MusinAA/task-1/BinaryTree.py @@ -0,0 +1,20 @@ +""" +Двоичное дерево поиска + +Узел — словарь: +{'name': 'Имя', 'phone': '123', 'left': None, 'right': None}. +""" + +def bst_insert(root, name, phone): + """Рекурсивно или итеративно вставляет, + возвращает новый корень (если корень меняется).""" + +def bst_find(root, name): + ... + +def bst_delete(root, name): + """Удаление, возвращает новый корень.""" + +def bst_list_all(root): + """Центрированный обход. + Рекурсивно собирает записи в отсортированном порядке.""" \ No newline at end of file diff --git a/MusinAA/task-1/HashTable.py b/MusinAA/task-1/HashTable.py new file mode 100644 index 0000000..8fb6288 --- /dev/null +++ b/MusinAA/task-1/HashTable.py @@ -0,0 +1,18 @@ +""" +Хеш-таблица + +Хранится как список buckets фиксированной длины, +каждый элемент — голова связного списка (или None). +""" + +def ht_insert(buckets, name, phone): + """вычисляет индекс, вызывает ll_insert для соответствующего бакета.""" + +def ht_find(buckets, name): + ... + +def ht_delete(buckets, name): + ... + +def ht_list_all(buckets): + """Собирает все записи из всех бакетов и сортирует""" \ No newline at end of file diff --git a/MusinAA/task-1/LinkedList.py b/MusinAA/task-1/LinkedList.py new file mode 100644 index 0000000..c9dd29f --- /dev/null +++ b/MusinAA/task-1/LinkedList.py @@ -0,0 +1,25 @@ +""" +Связный список (LinkedListPhoneBook) + +Узел представляется словарём: +{'name': 'Имя', 'phone': '123', 'next': None}. +""" + + + +def ll_insert(head, name, phone): + """ + Проходит до конца (или сразу добавляет в конец) и возвращает новую + голову (если вставка в начало) или изменяет список по ссылке. + Удобнее возвращать новую голову, если вставка может быть в начало. + """ + +def ll_find(head, name): + """Ищет узел, возвращает телефон или None.""" + +def ll_delete(head, name): + """Удаляет узел, возвращает новую голову.""" + +def ll_list_all(head): + """Cобирает все записи в список и сортирует. + сортировка вынесена отдельно).""" \ No newline at end of file -- 2.43.0 From 9c1cd94e872e58d3902c34c4a4941d6671d06471 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Fri, 20 Mar 2026 22:01:33 +0300 Subject: [PATCH 02/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20.gitignore=20=D0=B4=D0=BB=D1=8F=20vscode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 MusinAA/.gitignore diff --git a/MusinAA/.gitignore b/MusinAA/.gitignore new file mode 100644 index 0000000..1d74e21 --- /dev/null +++ b/MusinAA/.gitignore @@ -0,0 +1 @@ +.vscode/ -- 2.43.0 From b984ec3569ecac0072c123e045274545aa903d82 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Fri, 20 Mar 2026 22:04:02 +0300 Subject: [PATCH 03/12] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D1=89=D0=B5=D0=BD=D1=8B=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20?= =?UTF-8?q?=D0=B8=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0?= =?UTF-8?q?=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F?= =?UTF-8?q?=20LinkedList?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/task-1/LinkedList.py | 25 -------- MusinAA/task1/__init__.py | 0 .../structures}/BinaryTree.py | 0 .../{task-1 => task1/structures}/HashTable.py | 0 MusinAA/task1/structures/LinkedList.py | 60 +++++++++++++++++++ MusinAA/task1/structures/__init__.py | 0 6 files changed, 60 insertions(+), 25 deletions(-) delete mode 100644 MusinAA/task-1/LinkedList.py create mode 100644 MusinAA/task1/__init__.py rename MusinAA/{task-1 => task1/structures}/BinaryTree.py (100%) rename MusinAA/{task-1 => task1/structures}/HashTable.py (100%) create mode 100644 MusinAA/task1/structures/LinkedList.py create mode 100644 MusinAA/task1/structures/__init__.py diff --git a/MusinAA/task-1/LinkedList.py b/MusinAA/task-1/LinkedList.py deleted file mode 100644 index c9dd29f..0000000 --- a/MusinAA/task-1/LinkedList.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -Связный список (LinkedListPhoneBook) - -Узел представляется словарём: -{'name': 'Имя', 'phone': '123', 'next': None}. -""" - - - -def ll_insert(head, name, phone): - """ - Проходит до конца (или сразу добавляет в конец) и возвращает новую - голову (если вставка в начало) или изменяет список по ссылке. - Удобнее возвращать новую голову, если вставка может быть в начало. - """ - -def ll_find(head, name): - """Ищет узел, возвращает телефон или None.""" - -def ll_delete(head, name): - """Удаляет узел, возвращает новую голову.""" - -def ll_list_all(head): - """Cобирает все записи в список и сортирует. - сортировка вынесена отдельно).""" \ No newline at end of file diff --git a/MusinAA/task1/__init__.py b/MusinAA/task1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/MusinAA/task-1/BinaryTree.py b/MusinAA/task1/structures/BinaryTree.py similarity index 100% rename from MusinAA/task-1/BinaryTree.py rename to MusinAA/task1/structures/BinaryTree.py diff --git a/MusinAA/task-1/HashTable.py b/MusinAA/task1/structures/HashTable.py similarity index 100% rename from MusinAA/task-1/HashTable.py rename to MusinAA/task1/structures/HashTable.py diff --git a/MusinAA/task1/structures/LinkedList.py b/MusinAA/task1/structures/LinkedList.py new file mode 100644 index 0000000..54850ad --- /dev/null +++ b/MusinAA/task1/structures/LinkedList.py @@ -0,0 +1,60 @@ +""" +Связный список (LinkedListPhoneBook) + +Узел представляется словарём: +{'name': 'Имя', 'phone': '123', 'next': None}. +""" + + +def ll_insert(head : dict|None, name: str, phone: str) -> dict: + """ + Проходит до конца (или сразу добавляет в конец) и возвращает новую + голову (если вставка в начало) или изменяет список по ссылке. + Удобнее возвращать новую голову, если вставка может быть в начало. + """ + + newNode = {'name': name, 'phone': phone, 'next': None} + if head == None: + return newNode + + currentNode = head + while currentNode['next'] != None: + currentNode = currentNode['next'] + currentNode['next'] = newNode + return head + +def ll_find(head : dict|None, name: str) -> str|None: + """Ищет узел, возвращает телефон или None.""" + currentNode = head + while currentNode != None: + if currentNode['name'] == name: + return currentNode['phone'] + currentNode = currentNode['next'] + return None + +def ll_delete(head : dict|None, name: str) -> dict: + """Удаляет узел, возвращает новую голову.""" + if head == None: + return None + + if head['name'] == name: + return head['next'] + + currentNode = head + while currentNode['next'] != None: + if currentNode['next']['name'] == name: + currentNode['next'] = currentNode['next']['next'] + return head + currentNode = currentNode['next'] + return head + +def ll_list_all(head: dict|None) -> list: + """Cобирает все записи в список и сортирует. + сортировка вынесена отдельно).""" + records = [] + currentNode = head + while currentNode != None: + records.append((currentNode['name'], currentNode['phone'])) + currentNode = currentNode['next'] + records.sort(key=lambda item: item[0]) + return records \ No newline at end of file diff --git a/MusinAA/task1/structures/__init__.py b/MusinAA/task1/structures/__init__.py new file mode 100644 index 0000000..e69de29 -- 2.43.0 From 0b092e8d26c4014d7df17dff378f219aa49ddcd1 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Fri, 20 Mar 2026 22:05:07 +0300 Subject: [PATCH 04/12] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D1=91=D0=BD=20.gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/MusinAA/.gitignore b/MusinAA/.gitignore index 1d74e21..cb48c0c 100644 --- a/MusinAA/.gitignore +++ b/MusinAA/.gitignore @@ -1 +1,2 @@ .vscode/ +*/tests/ \ No newline at end of file -- 2.43.0 From 9bdefcc922868f1ffa1ddbb55ed718c8b086d1a9 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Sat, 21 Mar 2026 23:41:46 +0300 Subject: [PATCH 05/12] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=20HashTable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/task1/structures/HashTable.py | 54 +++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/MusinAA/task1/structures/HashTable.py b/MusinAA/task1/structures/HashTable.py index 8fb6288..81b4d90 100644 --- a/MusinAA/task1/structures/HashTable.py +++ b/MusinAA/task1/structures/HashTable.py @@ -5,14 +5,54 @@ каждый элемент — голова связного списка (или None). """ -def ht_insert(buckets, name, phone): - """вычисляет индекс, вызывает ll_insert для соответствующего бакета.""" +from task1.structures.LinkedList import * -def ht_find(buckets, name): - ... +def hash_fun(name: str, size: int) -> int: + """Принимает имя и возвращает индекс бакета для него.""" + if size <= 0: + raise ValueError("size должен быть больше 0") + + hashSum = 0 + n = size+1 + base = 1103 # ord('я') + for letter in name: + hashSum += ord(letter) * pow(base, n) + n -= 1 + return int(hashSum) % size -def ht_delete(buckets, name): - ... +def ht_insert(buckets: list, name: str, phone: str) -> list: + """Возвращает новый массив бакетов + Вычисляет индекс, вызывает ll_insert для соответствующего бакета. + Функция не меняет размер массива бакетов автоматически!""" + if buckets == []: + raise ValueError("Длинна buckets должна быть больше 0") + + size = len(buckets) + index = hash_fun(name, size) + buckets[index] = ll_insert(buckets[index], name, phone) + return buckets + +def ht_delete(buckets: list, name: str) -> list: + """Возвращает новый массив бакетов без элемента с именем name""" + if buckets == []: + raise ValueError("Длинна buckets должна быть больше 0") + + size = len(buckets) + index = hash_fun(name, size) + buckets[index] = ll_delete(buckets[index], name) + return buckets + +def ht_find(buckets: list, name: str) -> str: + if buckets == []: + raise ValueError("Длинна buckets должна быть больше 0") + + size = len(buckets) + index = hash_fun(name, size) + return ll_find(buckets[index], name) def ht_list_all(buckets): - """Собирает все записи из всех бакетов и сортирует""" \ No newline at end of file + """Собирает все записи из всех бакетов и сортирует""" + allRecords = [] + for bucket in buckets: + allRecords.extend(ll_list_all(bucket)) + return sorted(allRecords, key=lambda x: x[0]) \ No newline at end of file -- 2.43.0 From b383ed1cdc1e8b777a49e6d7121ddc26d3044235 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Sun, 22 Mar 2026 00:39:01 +0300 Subject: [PATCH 06/12] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=20bst=5Finsert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/task1/structures/BinaryTree.py | 35 ++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/MusinAA/task1/structures/BinaryTree.py b/MusinAA/task1/structures/BinaryTree.py index aa39c0e..f2e4aad 100644 --- a/MusinAA/task1/structures/BinaryTree.py +++ b/MusinAA/task1/structures/BinaryTree.py @@ -5,16 +5,37 @@ {'name': 'Имя', 'phone': '123', 'left': None, 'right': None}. """ -def bst_insert(root, name, phone): - """Рекурсивно или итеративно вставляет, - возвращает новый корень (если корень меняется).""" +def bst_insert(root: dict|None, name: str, phone: str) -> dict: + """Итеративно вставляет, возвращает новый корень (если корень меняется).""" + if root == None: + return {'name': name, 'phone': phone, 'left': None, 'right': None} + + # '674' < '722' == True, lol + current = root + while True: + if current['name'] == name: + current['phone'] == phone + elif current['name'] < name: + if current['left'] == None: + current['left'] = bst_insert(None, name, phone) + return root + else: + current = current['left'] + else: + if current['right'] == None: + current['right'] = bst_insert(None, name, phone) + return root + else: + current = current['right'] + # Увы, это самый лаконичный вариант, который я придумал. -def bst_find(root, name): - ... -def bst_delete(root, name): +def bst_find(root: dict|None, name: str) -> str|None: + """Поиск в ширину.""" + +def bst_delete(root: dict, name: str) -> dict: """Удаление, возвращает новый корень.""" -def bst_list_all(root): +def bst_list_all(root: dict) -> list: """Центрированный обход. Рекурсивно собирает записи в отсортированном порядке.""" \ No newline at end of file -- 2.43.0 From dd4eca84077590089079cf82a52c1fd103ed6cb8 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Mon, 23 Mar 2026 00:07:17 +0300 Subject: [PATCH 07/12] =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=D1=8E=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=20BinaryTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/task1/structures/BinaryTree.py | 57 +++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/MusinAA/task1/structures/BinaryTree.py b/MusinAA/task1/structures/BinaryTree.py index f2e4aad..93493f5 100644 --- a/MusinAA/task1/structures/BinaryTree.py +++ b/MusinAA/task1/structures/BinaryTree.py @@ -14,8 +14,9 @@ def bst_insert(root: dict|None, name: str, phone: str) -> dict: current = root while True: if current['name'] == name: - current['phone'] == phone - elif current['name'] < name: + current['phone'] = phone + return root + elif name < current['name']: if current['left'] == None: current['left'] = bst_insert(None, name, phone) return root @@ -32,10 +33,56 @@ def bst_insert(root: dict|None, name: str, phone: str) -> dict: def bst_find(root: dict|None, name: str) -> str|None: """Поиск в ширину.""" + node = find_node_to_delete(root, name) + if node != None: + return node['phone'] + +def find_node_to_delete(root: dict, name: str) -> dict|None: + """Поиск в ширину.""" + while root != None: + if root['name'] == name: + return root + elif name < root['name']: + root = root['left'] + else: + root = root['right'] + return None + +def find_minimal_child(root: dict) -> dict|None: + while root['left']: + root = root['left'] + return root + +def bst_delete(root: dict, name: str) -> 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: + # Случай 1: нет детей или один ребенок + if root['left'] is None: + return root['right'] + elif root['right'] is None: + return root['left'] + + # Случай 2: два ребенка + min_node = find_minimal_child(root['right']) + root['name'] = min_node['name'] + root['phone'] = min_node['phone'] + root['right'] = bst_delete(root['right'], min_node['name']) + + return root -def bst_delete(root: dict, name: str) -> dict: - """Удаление, возвращает новый корень.""" def bst_list_all(root: dict) -> list: """Центрированный обход. - Рекурсивно собирает записи в отсортированном порядке.""" \ No newline at end of file + Рекурсивно собирает записи в отсортированном порядке.""" + + if root is None: + return [] + node_values = {"name": root['name'], "phone": root['phone']} + return bst_list_all(root['left']) + [node_values] + bst_list_all(root['right']) \ No newline at end of file -- 2.43.0 From 7026ad395d157f2917698dd00ea7bc186019be60 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Mon, 30 Mar 2026 17:47:24 +0300 Subject: [PATCH 08/12] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D1=82=20=D0=BE?= =?UTF-8?q?=D1=82=D1=87=D1=91=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/docs/Report 1.ipynb | 126 ++++++++++++++++++++++++++ MusinAA/task1/structures/HashTable.py | 7 +- MusinAA/task1/util/__init__.py | 0 MusinAA/task1/util/randomNames.py | 47 ++++++++++ MusinAA/task1/util/timeTester.py | 24 +++++ 5 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 MusinAA/docs/Report 1.ipynb create mode 100644 MusinAA/task1/util/__init__.py create mode 100644 MusinAA/task1/util/randomNames.py create mode 100644 MusinAA/task1/util/timeTester.py diff --git a/MusinAA/docs/Report 1.ipynb b/MusinAA/docs/Report 1.ipynb new file mode 100644 index 0000000..cd21dda --- /dev/null +++ b/MusinAA/docs/Report 1.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2acfa743", + "metadata": {}, + "source": [ + "# 0. Подготовим окружение" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4689b73e", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import os\n", + "sys.path.insert(0, os.path.abspath( '../task1'))\n", + "sys.path.insert(0, os.path.abspath( '../'))" + ] + }, + { + "cell_type": "markdown", + "id": "37cc11a5", + "metadata": {}, + "source": [ + "# 1. Генерация тестовых данных\n", + "\n", + "Создадим список records из N=10000 элементов. Каждый элемент — кортеж (name, phone). \n", + "Имена возъмём случайные из небольшого набора (чтобы были повторения и коллизии). \n", + "Для проверки влияния порядка подготовим два варианта: \n", + "\n", + "_records_shuffled_ — случайный порядок. \n", + "_records_sorted_ — отсортированный по имени (по алфавиту)." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "7d073d06", + "metadata": {}, + "outputs": [], + "source": [ + "from util.randomNames import generate_test_data\n", + "records_shuffled = generate_test_data(N=10000)\n", + "records_sorted = generate_test_data(N=10000, _sorted=True)\n", + "\n", + "from util.timeTester import insert_tester" + ] + }, + { + "cell_type": "markdown", + "id": "c2f4989c", + "metadata": {}, + "source": [ + "# 2. Проведение замеров\n", + "### A. Время вставки" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eba5888c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Function': 'll_insert', 'shuffled': 4.4217493799999374, 'sorted': 5.294112365000046}\n", + "{'Function': 'ht_insert', 'shuffled': 0.338659952999933, 'sorted': 0.20052070199994887}\n", + "{'Function': 'bst_insert', 'shuffled': 0.01834327899996424, 'sorted': 0.18432242999983828}\n" + ] + } + ], + "source": [ + "from structures.LinkedList import *\n", + "from structures.HashTable import *\n", + "from structures.BinaryTree import *\n", + "\n", + "print(insert_tester(ll_insert, records_shuffled, records_sorted))\n", + "print(insert_tester(ht_insert, records_shuffled, records_sorted))\n", + "print(insert_tester(bst_insert, records_shuffled, records_sorted))" + ] + }, + { + "cell_type": "markdown", + "id": "383c4b1b", + "metadata": {}, + "source": [ + "### Б. Поиск 100 случайных записей и 10 несуществующих" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1acfa50", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/MusinAA/task1/structures/HashTable.py b/MusinAA/task1/structures/HashTable.py index 81b4d90..08b93fd 100644 --- a/MusinAA/task1/structures/HashTable.py +++ b/MusinAA/task1/structures/HashTable.py @@ -20,12 +20,13 @@ def hash_fun(name: str, size: int) -> int: n -= 1 return int(hashSum) % size -def ht_insert(buckets: list, name: str, phone: str) -> list: +def ht_insert(buckets: list, name: str, phone: str, blen:int = 50) -> list: """Возвращает новый массив бакетов Вычисляет индекс, вызывает ll_insert для соответствующего бакета. Функция не меняет размер массива бакетов автоматически!""" - if buckets == []: - raise ValueError("Длинна buckets должна быть больше 0") + if buckets == [] or buckets == None: + buckets = [None] * blen + # raise ValueError("Длинна buckets должна быть больше 0") size = len(buckets) index = hash_fun(name, size) diff --git a/MusinAA/task1/util/__init__.py b/MusinAA/task1/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/MusinAA/task1/util/randomNames.py b/MusinAA/task1/util/randomNames.py new file mode 100644 index 0000000..3fffb67 --- /dev/null +++ b/MusinAA/task1/util/randomNames.py @@ -0,0 +1,47 @@ +import random + +names_pool = ( + "Иван", "Мария", "Петр", "Анна", "Сергей", "Елена", "Алексей", "Ольга", + "Дмитрий", "Татьяна", "Михаил", "Наталья", "Андрей", "Ирина", "Николай", + "Светлана", "Владимир", "Екатерина", "Александр", "Юлия", "Павел", "Ксения", + "Виктор", "Анастасия", "Артем", "Виктория", "Максим", "Полина", "Даниил", + "София", "Евгений", "Алиса", "Станислав", "Дарья", "Георгий", "Вероника", + "Кирилл", "Маргарита", "Тимофей", "Арина", "Руфина", "Илларион", "Стелла", + "Роман", "Валерия", "Игорь", "Алина", "Олег", "Диана", "Юрий", "Милана", + "Василий", "Ева", "Никита", "Алиса", "Константин", "Кира", "Денис", "Ангелина", + "Вячеслав", "Мирослава", "Григорий", "Эмилия", "Леонид", "Василиса", "Руслан", + "Стефания", "Арсений", "Есения", "Антон", "Яна", "Матвей", "Любовь", "Семен", + "Надежда", "Федор", "Софья", "Лев", "Варвара", "Егор", "Амелия", "Борис", + "Агата", "Захар", "Камилла", "Давид", "Олеся", "Ярослав", "Людмила", "Данила", + "Регина", "Марк", "Каролина", "Артур", "Нелли", "Глеб", "Инна", "Платон", + "Нина", "Святослав", "Римма", "Родион", "Лидия", "Эдуард", "Жанна", "Вадим", + "Рената", "Савелий", "Алла", "Назар", "Снежана", "Демид", "Лариса", "Филипп", + "Злата", "Тимур", "Майя", "Клим", "Эльвира", "Дамир", "Таисия", "Илья", + "Роза", "Виталий", "Азалия", "Степан", "Лиана", "Богдан", "Инесса", "Эрик", + "Ариана", "Алан", "Юлиана", "Лука", "Антонина", "Мирон", "Клавдия", "Гордей", + "Руслана", "Макар", "Елизавета", "Северин", "Александра", "Моисей", "Агафья", + "Наум", "Серафима", "Влад", "Фаина", "Кузьма", "Пелагея", "Ермак", "Ульяна", + "Тарас", "Марианна", "Остап", "Бронислава", "Архип", "Владислава", "Фома", + "Станислава", "Еремей", "Зинаида", "Прохор", "Раиса", "Мстислав", "Галина", + "Ростислав", "Валентина", "Серафим", "Евдокия", "Лаврентий", "Кристина", + "Никон", "Анфиса", "Феликс", "Лия", "Иннокентий", "Роксана", "Всеволод", + "Эвелина", "Модест", "Юнона", "Трофим", "Изабелла", "Аполлон", "Глория", + "Касьян", "Аврора", "Любомир", "Адель", "Бронислав", "Доминика", "Афанасий", + "Фрида", "Евстафий", "Ассоль", "Венедикт", "Цветана", "Епифан", "Мелисса", + "Добрыня" +) + +def generate_phone(phone_len=11) -> str: + # 88005553535 + return str(random.randint(10**phone_len, 10**(phone_len+1)-1)) + +def generate_test_data(N=10000, _sorted=False): + records = [] + for i in range(N): + name = random.choice(names_pool) + phone = generate_phone() + records.append((name, phone)) + + if _sorted: + return sorted(records) + return records \ No newline at end of file diff --git a/MusinAA/task1/util/timeTester.py b/MusinAA/task1/util/timeTester.py new file mode 100644 index 0000000..a0a5007 --- /dev/null +++ b/MusinAA/task1/util/timeTester.py @@ -0,0 +1,24 @@ +import time +from typing import Callable, Any + +def _concrete_insert_tester(func: Callable[[Any, str, str], Any], records: list) -> float: + """Исследует время работы функции вставки""" + aboba = None + + start = time.perf_counter() + for item in records: + aboba = func(aboba, name=item[0], phone=item[1]) + end = time.perf_counter() + + elapsed = end - start + return elapsed + +def insert_tester(func_to_test: Callable[[Any, str, str], Any], records_shuffled, records_sorted) -> dict: + """Возвращает словарь с временем сортировки в обоих режимах""" + shuffled = _concrete_insert_tester(func_to_test, records_shuffled) + sorted = _concrete_insert_tester(func_to_test, records_sorted) + + return {"Function": func_to_test.__name__, + "shuffled": shuffled, + "sorted": sorted + } \ No newline at end of file -- 2.43.0 From 94bc3b8524a5b813fb1ec44501a5293278bdbf67 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Fri, 3 Apr 2026 01:30:35 +0300 Subject: [PATCH 09/12] Pylance fixes --- MusinAA/task1/structures/BinaryTree.py | 2 +- MusinAA/task1/structures/HashTable.py | 6 ++-- MusinAA/task1/structures/LinkedList.py | 2 +- MusinAA/task1/util/randomNames.py | 8 +++++ MusinAA/task1/util/timeTester.py | 44 ++++++++++++++++---------- 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/MusinAA/task1/structures/BinaryTree.py b/MusinAA/task1/structures/BinaryTree.py index 93493f5..e98c31a 100644 --- a/MusinAA/task1/structures/BinaryTree.py +++ b/MusinAA/task1/structures/BinaryTree.py @@ -37,7 +37,7 @@ def bst_find(root: dict|None, name: str) -> str|None: if node != None: return node['phone'] -def find_node_to_delete(root: dict, name: str) -> dict|None: +def find_node_to_delete(root: dict|None, name: str) -> dict|None: """Поиск в ширину.""" while root != None: if root['name'] == name: diff --git a/MusinAA/task1/structures/HashTable.py b/MusinAA/task1/structures/HashTable.py index 08b93fd..dd16599 100644 --- a/MusinAA/task1/structures/HashTable.py +++ b/MusinAA/task1/structures/HashTable.py @@ -20,7 +20,7 @@ def hash_fun(name: str, size: int) -> int: n -= 1 return int(hashSum) % size -def ht_insert(buckets: list, name: str, phone: str, blen:int = 50) -> list: +def ht_insert(buckets: list|None, name: str, phone: str, blen:int = 50) -> list: """Возвращает новый массив бакетов Вычисляет индекс, вызывает ll_insert для соответствующего бакета. Функция не меняет размер массива бакетов автоматически!""" @@ -43,8 +43,8 @@ def ht_delete(buckets: list, name: str) -> list: buckets[index] = ll_delete(buckets[index], name) return buckets -def ht_find(buckets: list, name: str) -> str: - if buckets == []: +def ht_find(buckets: list|None, name: str) -> str|None: + if buckets == [] or buckets == None: raise ValueError("Длинна buckets должна быть больше 0") size = len(buckets) diff --git a/MusinAA/task1/structures/LinkedList.py b/MusinAA/task1/structures/LinkedList.py index 54850ad..ed0d1ba 100644 --- a/MusinAA/task1/structures/LinkedList.py +++ b/MusinAA/task1/structures/LinkedList.py @@ -32,7 +32,7 @@ def ll_find(head : dict|None, name: str) -> str|None: currentNode = currentNode['next'] return None -def ll_delete(head : dict|None, name: str) -> dict: +def ll_delete(head : dict|None, name: str) -> dict|None: """Удаляет узел, возвращает новую голову.""" if head == None: return None diff --git a/MusinAA/task1/util/randomNames.py b/MusinAA/task1/util/randomNames.py index 3fffb67..2e08f82 100644 --- a/MusinAA/task1/util/randomNames.py +++ b/MusinAA/task1/util/randomNames.py @@ -31,6 +31,14 @@ names_pool = ( "Добрыня" ) +_non_existent_names = [ + "Ноль", "Целковый", "Полушка", "Четвертушка", "Осьмушка", + "Пудовичок", "Медячок", "Серебрячок", "Золотничок", "Девятичок" +] +assert set(names_pool).isdisjoint(set(_non_existent_names)), \ +"В списке несуществующих имён существуют существующие имена сущностей" +names_pool_to_find = random.choices(names_pool, k=100) + _non_existent_names + def generate_phone(phone_len=11) -> str: # 88005553535 return str(random.randint(10**phone_len, 10**(phone_len+1)-1)) diff --git a/MusinAA/task1/util/timeTester.py b/MusinAA/task1/util/timeTester.py index a0a5007..763b25d 100644 --- a/MusinAA/task1/util/timeTester.py +++ b/MusinAA/task1/util/timeTester.py @@ -1,24 +1,36 @@ import time from typing import Callable, Any +from task1.util.randomNames import names_pool_to_find -def _concrete_insert_tester(func: Callable[[Any, str, str], Any], records: list) -> float: - """Исследует время работы функции вставки""" - aboba = None - +def test(records: list, + insert_func: Callable[[Any, str, str], Any], + find_func: Callable[[Any, str], Any], + delete_func: Callable[[Any, str], Any]) -> dict: + data = None + + # Вставка всех записей start = time.perf_counter() for item in records: - aboba = func(aboba, name=item[0], phone=item[1]) + data = insert_func(data, item[0], item[1]) end = time.perf_counter() + insert_time = end - start - elapsed = end - start - return elapsed + # Поиск 110 случайных записей + start = time.perf_counter() + for name in names_pool_to_find: + find_func(data, name) + end = time.perf_counter() + find_time = end - start -def insert_tester(func_to_test: Callable[[Any, str, str], Any], records_shuffled, records_sorted) -> dict: - """Возвращает словарь с временем сортировки в обоих режимах""" - shuffled = _concrete_insert_tester(func_to_test, records_shuffled) - sorted = _concrete_insert_tester(func_to_test, records_sorted) - - return {"Function": func_to_test.__name__, - "shuffled": shuffled, - "sorted": sorted - } \ No newline at end of file + # Удаление 50 случайных записей + start = time.perf_counter() + for name in names_pool_to_find: + data = delete_func(data, name) + end = time.perf_counter() + delete_time = end - start + + return { + "insert_time" : insert_time , + "find_time" : find_time , + "delete_time": delete_time + } -- 2.43.0 From cb02fb20feb303c32bdf70b9b7cc94179c5d7623 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Fri, 3 Apr 2026 01:31:26 +0300 Subject: [PATCH 10/12] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D0=B0=D0=BD=20=D0=B8=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=20=D0=BF=D0=BE=D0=B4=D1=81=D1=87?= =?UTF-8?q?=D1=91=D1=82=20=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=B8=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=B0=D0=B6=D0=B4=D0=BE=D0=B9=20?= =?UTF-8?q?=D0=A1=D0=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/docs/Report 1.ipynb | 84 ++++++++++++++++++++--------------- MusinAA/docs/data/results.csv | 31 +++++++++++++ 2 files changed, 79 insertions(+), 36 deletions(-) create mode 100644 MusinAA/docs/data/results.csv diff --git a/MusinAA/docs/Report 1.ipynb b/MusinAA/docs/Report 1.ipynb index cd21dda..3e19ef8 100644 --- a/MusinAA/docs/Report 1.ipynb +++ b/MusinAA/docs/Report 1.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 16, "id": "4689b73e", "metadata": {}, "outputs": [], @@ -38,16 +38,16 @@ }, { "cell_type": "code", - "execution_count": 2, - "id": "7d073d06", + "execution_count": 17, + "id": "a3b5c31b", "metadata": {}, "outputs": [], "source": [ "from util.randomNames import generate_test_data\n", - "records_shuffled = generate_test_data(N=10000)\n", - "records_sorted = generate_test_data(N=10000, _sorted=True)\n", + "from util.timeTester import test\n", "\n", - "from util.timeTester import insert_tester" + "records_shuffled = generate_test_data(N=10000)\n", + "records_sorted = generate_test_data(N=10000, _sorted=True)" ] }, { @@ -55,51 +55,63 @@ "id": "c2f4989c", "metadata": {}, "source": [ - "# 2. Проведение замеров\n", - "### A. Время вставки" + "# 2. Проведение замеров" ] }, { "cell_type": "code", - "execution_count": null, - "id": "eba5888c", + "execution_count": 18, + "id": "df12d41d", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'Function': 'll_insert', 'shuffled': 4.4217493799999374, 'sorted': 5.294112365000046}\n", - "{'Function': 'ht_insert', 'shuffled': 0.338659952999933, 'sorted': 0.20052070199994887}\n", - "{'Function': 'bst_insert', 'shuffled': 0.01834327899996424, 'sorted': 0.18432242999983828}\n" - ] - } - ], + "outputs": [], "source": [ + "# Подготовим функции СД, которые будем тестировать\n", "from structures.LinkedList import *\n", "from structures.HashTable import *\n", "from structures.BinaryTree import *\n", "\n", - "print(insert_tester(ll_insert, records_shuffled, records_sorted))\n", - "print(insert_tester(ht_insert, records_shuffled, records_sorted))\n", - "print(insert_tester(bst_insert, records_shuffled, records_sorted))" - ] - }, - { - "cell_type": "markdown", - "id": "383c4b1b", - "metadata": {}, - "source": [ - "### Б. Поиск 100 случайных записей и 10 несуществующих" + "func_list = {\"Связанный список\" : (ll_insert, ll_find, ll_delete),\n", + " \"Хэш-таблица\" : (ht_insert, ht_find, ht_delete),\n", + " \"Бинарное дерево\" : (bst_insert, bst_find, bst_delete)}" ] }, { "cell_type": "code", - "execution_count": null, - "id": "d1acfa50", + "execution_count": 24, + "id": "cc8d0436", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "# Проведём замеры\n", + "report = [[\"Структура\", \"Режим\", \"Вставка\", \"Поиск\", \"Удаление\"]]\n", + "records = {\"Cлучайный\" : records_shuffled, \"Отсортированный\" : records_sorted}\n", + "\n", + "TEST_ITERATIONS_NUM = 5\n", + "\n", + "for _ in range(TEST_ITERATIONS_NUM):\n", + " for mode, data in records.items():\n", + " for struct_name, fns in func_list.items():\n", + " result = test(data, *fns)\n", + " row = [struct_name, mode,\n", + " result[\"insert_time\"],\n", + " result[\"find_time\"],\n", + " result[\"delete_time\"]]\n", + " report.append(row)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "2eedf056", + "metadata": {}, + "outputs": [], + "source": [ + "# Сохраним данные в csv\n", + "import csv\n", + "with open(\"data/results.csv\", \"w\", newline=\"\") as f:\n", + " writer = csv.writer(f)\n", + " writer.writerows(report)" + ] } ], "metadata": { @@ -118,7 +130,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.2" + "version": "3.14.3" } }, "nbformat": 4, diff --git a/MusinAA/docs/data/results.csv b/MusinAA/docs/data/results.csv new file mode 100644 index 0000000..f8fd074 --- /dev/null +++ b/MusinAA/docs/data/results.csv @@ -0,0 +1,31 @@ +Структура,Режим,Вставка,Поиск,Удаление +Связанный список,Cлучайный,6.184219556999778,0.01564759699977003,0.020917029999509396 +Хэш-таблица,Cлучайный,0.20728507099920535,0.0011867590001202188,0.0012845039991589147 +Бинарное дерево,Cлучайный,0.01599855899985414,0.00017333699997834628,0.0001880449999589473 +Связанный список,Отсортированный,6.1492630290003945,0.08403158500004793,0.11902903299960599 +Хэш-таблица,Отсортированный,0.1831843130003108,0.003145785999549844,0.0030832479997116025 +Бинарное дерево,Отсортированный,0.17353334099971107,0.0018611919995237258,0.001973905000340892 +Связанный список,Cлучайный,5.064191275000667,0.015435045000231185,0.021122407000802923 +Хэш-таблица,Cлучайный,0.21584205599992856,0.001062764999915089,0.0010387600004833075 +Бинарное дерево,Cлучайный,0.01586526800019783,0.0001650120002523181,0.0002011500000662636 +Связанный список,Отсортированный,5.008700298999429,0.08874143100001675,0.11785725200024899 +Хэш-таблица,Отсортированный,0.16122512399942934,0.0027618209996944643,0.0031808120002096985 +Бинарное дерево,Отсортированный,0.16625836200000776,0.0017326589995718678,0.0018288709998159902 +Связанный список,Cлучайный,4.973175217000062,0.016034526000112237,0.029878299000301922 +Хэш-таблица,Cлучайный,0.19947776500066539,0.0008432810000158497,0.0009618849999242229 +Бинарное дерево,Cлучайный,0.015627648000190675,0.00015909000012470642,0.00018263399942952674 +Связанный список,Отсортированный,4.7649637760005135,0.07843009399948642,0.11216894700010016 +Хэш-таблица,Отсортированный,0.16914973799975996,0.0028197709998494247,0.003400436000447371 +Бинарное дерево,Отсортированный,0.16913629200007563,0.00174245800008066,0.00184838800032594 +Связанный список,Cлучайный,5.070599788999971,0.023625830999662867,0.024334026999895286 +Хэш-таблица,Cлучайный,0.2566551750005601,0.001680571000179043,0.0019877810000252794 +Бинарное дерево,Cлучайный,0.02019279199976154,0.00019776400040427689,0.0002360259995839442 +Связанный список,Отсортированный,5.0148616579999725,0.08842415099934442,0.13560766399950808 +Хэш-таблица,Отсортированный,0.18670927000039228,0.0038891280000825645,0.0034846049993575434 +Бинарное дерево,Отсортированный,0.1774570309999035,0.0019291399994472158,0.0021798640000270098 +Связанный список,Cлучайный,5.373787051000363,0.021812238000165962,0.025861819999590807 +Хэш-таблица,Cлучайный,0.19457704500018735,0.00110557600055472,0.0010436189995743916 +Бинарное дерево,Cлучайный,0.015349283000432479,0.00016242600031546317,0.00017538100019010017 +Связанный список,Отсортированный,5.167020247999972,0.08513789999960863,0.12899004599967157 +Хэш-таблица,Отсортированный,0.18223923400000785,0.0032350740002584644,0.0037601450003421633 +Бинарное дерево,Отсортированный,0.1719607389995872,0.0017423979998056893,0.0018891839999923832 -- 2.43.0 From 94a9cba182e11561f22180a4b77c0f3d001a7fc9 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Sun, 5 Apr 2026 10:06:28 +0300 Subject: [PATCH 11/12] =?UTF-8?q?=D0=9F=D0=B0=D1=80=D0=B0=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/docs/Report 1.ipynb | 20 ++++++++--- MusinAA/docs/data/results.csv | 60 ++++++++++++++++---------------- MusinAA/task1/util/timeTester.py | 5 +-- 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/MusinAA/docs/Report 1.ipynb b/MusinAA/docs/Report 1.ipynb index 3e19ef8..3af91fe 100644 --- a/MusinAA/docs/Report 1.ipynb +++ b/MusinAA/docs/Report 1.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 26, "id": "4689b73e", "metadata": {}, "outputs": [], @@ -38,7 +38,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 27, "id": "a3b5c31b", "metadata": {}, "outputs": [], @@ -60,7 +60,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 28, "id": "df12d41d", "metadata": {}, "outputs": [], @@ -77,7 +77,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 29, "id": "cc8d0436", "metadata": {}, "outputs": [], @@ -101,7 +101,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 30, "id": "2eedf056", "metadata": {}, "outputs": [], @@ -112,6 +112,16 @@ " writer = csv.writer(f)\n", " writer.writerows(report)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8523ae48", + "metadata": {}, + "outputs": [], + "source": [ + "TODO проверить работает ли оно вообще" + ] } ], "metadata": { diff --git a/MusinAA/docs/data/results.csv b/MusinAA/docs/data/results.csv index f8fd074..8f5e275 100644 --- a/MusinAA/docs/data/results.csv +++ b/MusinAA/docs/data/results.csv @@ -1,31 +1,31 @@ Структура,Режим,Вставка,Поиск,Удаление -Связанный список,Cлучайный,6.184219556999778,0.01564759699977003,0.020917029999509396 -Хэш-таблица,Cлучайный,0.20728507099920535,0.0011867590001202188,0.0012845039991589147 -Бинарное дерево,Cлучайный,0.01599855899985414,0.00017333699997834628,0.0001880449999589473 -Связанный список,Отсортированный,6.1492630290003945,0.08403158500004793,0.11902903299960599 -Хэш-таблица,Отсортированный,0.1831843130003108,0.003145785999549844,0.0030832479997116025 -Бинарное дерево,Отсортированный,0.17353334099971107,0.0018611919995237258,0.001973905000340892 -Связанный список,Cлучайный,5.064191275000667,0.015435045000231185,0.021122407000802923 -Хэш-таблица,Cлучайный,0.21584205599992856,0.001062764999915089,0.0010387600004833075 -Бинарное дерево,Cлучайный,0.01586526800019783,0.0001650120002523181,0.0002011500000662636 -Связанный список,Отсортированный,5.008700298999429,0.08874143100001675,0.11785725200024899 -Хэш-таблица,Отсортированный,0.16122512399942934,0.0027618209996944643,0.0031808120002096985 -Бинарное дерево,Отсортированный,0.16625836200000776,0.0017326589995718678,0.0018288709998159902 -Связанный список,Cлучайный,4.973175217000062,0.016034526000112237,0.029878299000301922 -Хэш-таблица,Cлучайный,0.19947776500066539,0.0008432810000158497,0.0009618849999242229 -Бинарное дерево,Cлучайный,0.015627648000190675,0.00015909000012470642,0.00018263399942952674 -Связанный список,Отсортированный,4.7649637760005135,0.07843009399948642,0.11216894700010016 -Хэш-таблица,Отсортированный,0.16914973799975996,0.0028197709998494247,0.003400436000447371 -Бинарное дерево,Отсортированный,0.16913629200007563,0.00174245800008066,0.00184838800032594 -Связанный список,Cлучайный,5.070599788999971,0.023625830999662867,0.024334026999895286 -Хэш-таблица,Cлучайный,0.2566551750005601,0.001680571000179043,0.0019877810000252794 -Бинарное дерево,Cлучайный,0.02019279199976154,0.00019776400040427689,0.0002360259995839442 -Связанный список,Отсортированный,5.0148616579999725,0.08842415099934442,0.13560766399950808 -Хэш-таблица,Отсортированный,0.18670927000039228,0.0038891280000825645,0.0034846049993575434 -Бинарное дерево,Отсортированный,0.1774570309999035,0.0019291399994472158,0.0021798640000270098 -Связанный список,Cлучайный,5.373787051000363,0.021812238000165962,0.025861819999590807 -Хэш-таблица,Cлучайный,0.19457704500018735,0.00110557600055472,0.0010436189995743916 -Бинарное дерево,Cлучайный,0.015349283000432479,0.00016242600031546317,0.00017538100019010017 -Связанный список,Отсортированный,5.167020247999972,0.08513789999960863,0.12899004599967157 -Хэш-таблица,Отсортированный,0.18223923400000785,0.0032350740002584644,0.0037601450003421633 -Бинарное дерево,Отсортированный,0.1719607389995872,0.0017423979998056893,0.0018891839999923832 +Связанный список,Cлучайный,4.661078881000321,0.012941928999680385,0.020117076999667916 +Хэш-таблица,Cлучайный,0.18879180299973086,0.0014481220005109208,0.0012560499999381136 +Бинарное дерево,Cлучайный,0.01616830700004357,0.00016560199946979992,0.00016564300040045055 +Связанный список,Отсортированный,5.038275819999399,0.07141196100019442,0.1353478549999636 +Хэш-таблица,Отсортированный,0.1631836659998953,0.003129734999674838,0.003202291999514273 +Бинарное дерево,Отсортированный,0.16634428900033527,0.0017354540004816954,0.001874036000117485 +Связанный список,Cлучайный,4.664316974999565,0.014653709000413073,0.02280332600003021 +Хэш-таблица,Cлучайный,0.186777711999639,0.0010283499996148748,0.0009878339997158037 +Бинарное дерево,Cлучайный,0.016256722999969497,0.00015175599946815055,0.0001649409996389295 +Связанный список,Отсортированный,5.907060995999927,0.08458327099924645,0.12409427100010362 +Хэш-таблица,Отсортированный,0.18781050100005814,0.003518858999996155,0.0038270310005827923 +Бинарное дерево,Отсортированный,0.17500397699950554,0.0019018089997189236,0.001833940000324219 +Связанный список,Cлучайный,5.755159846999959,0.016742109000006167,0.026386416000605095 +Хэш-таблица,Cлучайный,0.22951744300007704,0.0009921219998432207,0.0011742059996322496 +Бинарное дерево,Cлучайный,0.01580532200023299,0.00017768500038073398,0.00019722199976968113 +Связанный список,Отсортированный,6.30150953500015,0.11176149099992472,0.1474957850005012 +Хэш-таблица,Отсортированный,0.18557919999966543,0.003155624000100943,0.002713390000280924 +Бинарное дерево,Отсортированный,0.19082545899982506,0.001985636999961571,0.002389950000178942 +Связанный список,Cлучайный,6.395210606000546,0.014804241999627266,0.02304338900012226 +Хэш-таблица,Cлучайный,0.1902105980007036,0.000852088000101503,0.0009626670007492066 +Бинарное дерево,Cлучайный,0.01663886400001502,0.00016400000004068715,0.000184548000106588 +Связанный список,Отсортированный,4.850914527999521,0.0771323629996914,0.1152741280002374 +Хэш-таблица,Отсортированный,0.17607759100064868,0.002924628000073426,0.0033850670006358996 +Бинарное дерево,Отсортированный,0.19345043999965128,0.0018585970001367969,0.0019752460002564476 +Связанный список,Cлучайный,4.803303787999539,0.015972447000422108,0.0223228390004806 +Хэш-таблица,Cлучайный,0.19020581800032232,0.0011616620004133438,0.0009839170006671338 +Бинарное дерево,Cлучайный,0.016469425000650517,0.000160212000082538,0.00017693399968266021 +Связанный список,Отсортированный,4.741838529000233,0.075463203000254,0.10462550600004761 +Хэш-таблица,Отсортированный,0.16722737300005974,0.004002030999799899,0.005207103999964602 +Бинарное дерево,Отсортированный,0.16575109800032806,0.0020921670002280734,0.002277146999404067 diff --git a/MusinAA/task1/util/timeTester.py b/MusinAA/task1/util/timeTester.py index 763b25d..3e3204e 100644 --- a/MusinAA/task1/util/timeTester.py +++ b/MusinAA/task1/util/timeTester.py @@ -1,6 +1,7 @@ import time +import random from typing import Callable, Any -from task1.util.randomNames import names_pool_to_find +from task1.util.randomNames import names_pool_to_find, names_pool def test(records: list, insert_func: Callable[[Any, str, str], Any], @@ -24,7 +25,7 @@ def test(records: list, # Удаление 50 случайных записей start = time.perf_counter() - for name in names_pool_to_find: + for name in random.choices(names_pool, k = 50): data = delete_func(data, name) end = time.perf_counter() delete_time = end - start -- 2.43.0 From cd62d229a507992fa3a9b4558e40aa90f1ffdd78 Mon Sep 17 00:00:00 2001 From: oSTEVEo Date: Sat, 11 Apr 2026 14:23:15 +0300 Subject: [PATCH 12/12] =?UTF-8?q?=D0=97=D0=B0=D0=BA=D0=BE=D0=BD=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BE=D1=82=D1=87=D1=91=D1=82=20=D0=BF=D0=BE=20?= =?UTF-8?q?1=20=D0=BB=D0=B0=D0=B1=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MusinAA/docs/Report 1.ipynb | 225 ++++++++++++++++++- MusinAA/docs/data/results.csv | 31 --- MusinAA/docs/data/task1/performance_plot.png | Bin 0 -> 72782 bytes MusinAA/docs/data/task1/results.csv | 31 +++ MusinAA/task1/structures/LinkedList.py | 3 + 5 files changed, 247 insertions(+), 43 deletions(-) delete mode 100644 MusinAA/docs/data/results.csv create mode 100644 MusinAA/docs/data/task1/performance_plot.png create mode 100644 MusinAA/docs/data/task1/results.csv diff --git a/MusinAA/docs/Report 1.ipynb b/MusinAA/docs/Report 1.ipynb index 3af91fe..9ac1fa0 100644 --- a/MusinAA/docs/Report 1.ipynb +++ b/MusinAA/docs/Report 1.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 8, "id": "4689b73e", "metadata": {}, "outputs": [], @@ -38,7 +38,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 9, "id": "a3b5c31b", "metadata": {}, "outputs": [], @@ -60,7 +60,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 10, "id": "df12d41d", "metadata": {}, "outputs": [], @@ -77,7 +77,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 11, "id": "cc8d0436", "metadata": {}, "outputs": [], @@ -101,26 +101,227 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 12, "id": "2eedf056", "metadata": {}, "outputs": [], "source": [ "# Сохраним данные в csv\n", "import csv\n", - "with open(\"data/results.csv\", \"w\", newline=\"\") as f:\n", + "with open(\"data/task1/results.csv\", \"w\", newline=\"\") as f:\n", " writer = csv.writer(f)\n", " writer.writerows(report)" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "8523ae48", + "cell_type": "markdown", + "id": "94335af1", "metadata": {}, - "outputs": [], "source": [ - "TODO проверить работает ли оно вообще" + "# 3. Построение графиков и их анализ" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "cad64d2f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABdEAAAHqCAYAAADrpwd3AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/P9b71AAAACXBIWXMAAA9hAAAPYQGoP6dpAACcZElEQVR4nOzde1xVZfr///eWo2migoEUIFqjkKUF5YDiYUwMyzx+pCysPBSDpUJpovLJLCPLbOcokqUxTqXMZ0jtwCQ4o6RJNiDYNFGaoZjBGFqSppx/f/hl/9zuvREU3IKv5+OxHtO+17Xu+157kGvti3uvZaitra0VAAAAAAAAAACw0MbeEwAAAAAAAAAA4EpFER0AAAAAAAAAABsoogMAAAAAAAAAYANFdAAAAAAAAAAAbKCIDgAAAAAAAACADRTRAQAAAAAAAACwgSI6AAAAAAAAAAA2UEQHAAAAAAAAAMAGiugAAAAAAAAAANhAER1owVJSUmQwGMy2Ll26aPDgwfroo4/sPT0AANCErOX987du3brZe5oAAABAq0MRHWgF3n77bWVnZ2vXrl1avXq1HBwcNHLkSH344Yf2nhoAAGhidXn//K1///72nhoAAK3eyy+/LIPBoA8++MBiX0lJiZydnTV69OjLPzEAzcrR3hMAcOl69+6t4OBg0+u7775bnTp10vr16zVy5Eg7zgwAADS18/N+nY4dO+qHH36ww4wAALh6TJ06VQsXLtSf/vQn3XfffWb7Vq1apcrKSj355JN2mh2A5sJKdKAVcnV1lbOzs5ycnExt5eXlWrRokQICAuTq6ip3d3cNGTJEu3btkqQLfj188ODBkqQzZ87oqaeeUt++feXm5qbOnTsrJCREmzdvtpjHucc7ODjI29tbDz/8sP773/+aYg4ePCiDwaCUlBRTW2lpqW699VYFBASopKTE1L5y5UoNHDhQ1113ndq1a6dbbrlFL7/8siorK5v4HQQAoOU7c+aM4uPj5e/vL2dnZ11//fWaPn26fvnlF7O4bt266ZFHHjFr+8tf/mL19jAXup6Qzub/hQsXml6fPn1aQ4cOVdeuXfXNN9808VkCAHB5de7cWQ8++KC2bt2qgoICU3tFRYXeeOMN3XzzzRo6dKgdZwigOVBEB1qB6upqVVVVqbKyUj/88INmzZqlU6dOaeLEiZKkqqoqRURE6Pnnn9e9996rjRs3KiUlRaGhoSoqKpIks6+DL1iwQJL0/vvvm9qSkpIknf3wfPz4cT399NPatGmT1q9frwEDBmjs2LFat26dxdymTJmi7OxsZWVlafbs2UpNTdWjjz5q81xKS0v1hz/8QZWVldq2bZu8vLxM+w4cOKCJEyfqL3/5iz766CNNmTJFr7zyih5//PEmey8BAGgNamtrNXr0aC1dulRRUVH6+OOPFRcXpz//+c/6wx/+oPLycpvHlpWVac6cOXJwcDBrb8j1xPlOnz6te++9V19//bW2bdumXr16Nel5AgBgD3Urzf/0pz+Z2lJTU/Xf//7XYhX6I488YnWh2vl/wE5NTVV4eLi6du2qtm3bKiAgQHPnztWpU6eszsHWAriDBw+aYmpra5WUlKS+ffuqbdu26tSpk8aPH6/vv//erK/Bgwerd+/eFmMsXbrUos/G/PG9oqJCL7zwgnr16iUXFxd16dJFjz76qH766Ser5wRcybidC9AK/P73vzd77eLiohUrVmj48OGSpPXr12vbtm168803NXXqVFPcubd6ObePulVit912m0USdHNz09tvv216XV1draFDh+rnn3+W0WjUpEmTzOJvuOEGU98DBgzQp59+arZa7VylpaUaOnSo1QK6JC1btsz03zU1NQoLC5O7u7seffRRvfrqq+rUqZP1NwgAgKtMRkaGtmzZopdfflmzZ8+WJA0bNkw+Pj6KjIzUunXrNG3aNKvHPvvss3JwcNDo0aOVk5Njam/I9cS5Tp8+rZEjR1JABwC0OrfeeqsGDhyodevWKTExUW5ubvrTn/6kTp06KSoqyiK+bdu2+uc//2l6/Yc//MEiZv/+/RoxYoRmzZqldu3a6ZtvvtGSJUv0xRdfmB17rilTpphy8scff6wXXnjBbP/jjz+ulJQUzZgxQ0uWLNHx48e1aNEihYaGau/evfL09LyUt0GS7T++19TUaNSoUdqxY4fmzJmj0NBQHTp0SM8++6wGDx6snJwctW3b9pLHBy4XiuhAK7Bu3ToFBARIOluI3rhxo6ZPn67q6mo98cQT+vvf/y5XV1dNnjy5Scb7v//7PxmNRu3du9fsr+Kurq4WsTU1NaqqqlJ1dbW++OIL7dy5U8OGDbOIO3bsmIYOHaovv/xS//nPfywK6JKUl5enZ599Vp999pmOHz9utm/fvn3q169fE5wdAAAtX92H7fNXiv3P//yPJk+erH/84x9Wi+hfffWVVqxYoXfeeUd///vfzfY15nri9OnTuu+++/SPf/xDH3/8MQV0AECr8+STT+p//ud/9Pbbb6tfv37617/+paefflrXXHONWVx5ebmcnJzMFq61aWN5Y4i6b4RLZ1eQ9+/fXwEBARo0aJC+/PJL3Xrrrab9FRUVks6uCq/r9/xbpn3++ed688039eqrryouLs7UHhYWpt/97ndatmyZlixZcgnvwFm2/vj+17/+VZ988onS0tI0duxYU3ufPn10xx13KCUlRX/84x8veXzgcuF2LkArEBAQoODgYAUHB+vuu+/WG2+8ofDwcM2ZM0e//PKLfvrpJ3l7e1tN1I31/vvva8KECbr++uv1zjvvKDs7W//61780efJknTlzxiL++eefl5OTk1xdXTVw4EDdeOONMhqNFnHz5s1TRUWFvLy8lJCQYLG/qKhIYWFhOnLkiF5//XXt2LFD//rXv7Ry5UpJZz+sAwCAs44dOyZHR0d16dLFrN1gMMjLy0vHjh2zetz06dMVFhamyMhIi32NuZ4wGo366quv1KtXLy1atEhVVVUXdyIAAFyhRo8eLR8fH61YsUJGo1EODg6aPn26RdzJkyctCuvWfP/995o4caK8vLzk4OAgJycnDRo0SJLM7r0u/f+ff60tZKvz0UcfyWAw6KGHHlJVVZVp8/LyUp8+fbR9+3aLY86Nq6qqUk1NTb1zrvvj+6uvvqr27dtbjN+xY0eNHDnSrM++ffvKy8vL6vjAlYyV6EArdeutt2rLli3at2+funTpop07d6qmpuaSC+nvvPOO/P39lZqaKoPBYGq3dW/VadOm6bHHHlNtba1+/PFHvfjiiwoJCVF+fr6uvfZaU1z37t21bds27d27VxEREVqzZo2mTJli2r9p0yadOnVK77//vvz8/Ezt+fn5l3Q+AAC0Ru7u7qqqqtJPP/1kVkivra1VSUmJ7rjjDotj3n33XWVnZ9vMrY25nujcubO2bdumiooK3XnnnXruuef0/PPPX9I5AQBwJXF0dNQf//hHzZs3TwcOHNDo0aMtbocqSUeOHJG3t3e9fZ08eVJhYWFydXXVCy+8oN/97ne65pprdPjwYY0dO9Zi0VhpaakkycPDw2af//3vf1VbW2vzli3du3c3e/2f//xHTk5O9c7zfOf+8f38b7D997//1S+//CJnZ2erx9adA9BSUEQHWqm6D8BdunRRRESE1q9fr5SUlEu+pYvBYJCzs7NZAb2kpESbN2+2Gu/t7a3g4GDT69raWo0ZM0bZ2dkKDw83tT/zzDPy8vKSl5eXnnzySc2cOdP0NbO6caWz93s/t68333zzks4HAIDWaOjQoXr55Zf1zjvvKDY21tSelpamU6dOaejQoWbxv/76q2bPnq2ZM2cqMDDQap+NuZ54/PHHTbdwSUxM1NNPP63w8HCFhYVd4pkBAHDlmDZtmhYtWqQzZ85oxowZFvsrKytVUFBg9Rte5/rnP/+pH3/8Udu3bzetPpekX375xWr8/v37JUk33nijzT49PDxkMBi0Y8cOs8/Rdc5v69GjhzZs2GDW9s477+j111+32v+F/vju4eEhd3d3ffLJJ1b3n7uoDmgJKKIDrcBXX31l+pr0sWPH9P777yszM1NjxoyRv7+/fHx89Pbbbys6OlrffvuthgwZopqaGu3evVsBAQG6//77GzzWvffeq/fff18xMTEaP368Dh8+rOeff15du3Y1JfJz/fDDD/r8889NK9ETExPl4uJiuoe7NUuWLNE///lPPfjgg9q1a5ecnJw0bNgwOTs764EHHtCcOXN05swZrVq1Sj///HPj3zAAAFq5YcOGafjw4XrmmWdUVlam/v3768svv9Szzz6r2267zeKhZ5s3b5anp6eeffZZm30+8MADF3U9MWvWLP3973/XQw89pL1796pjx45NeaoAANhNhw4d1L59e910000aMmSIxf6MjAydOXPG5kO461hbNCZJb7zxhtX4TZs2qV27dgoKCrLZ57333quXXnpJR44c0YQJEy50KnJ1dTVbACfJ5i1XGvLH93vvvVcbNmxQdXU1zy9Dq0ARHWgFHn30UdN/u7m5yd/fX8uWLVNMTIyks18zS09PV2JiotavXy+j0ahrr71Wffr00d13393osY4ePark5GStXbtW3bt319y5c/XDDz/oueees4hfs2aN1qxZI4PBoM6dO6tPnz76+9//Lh8fH5tjuLq66t1339Wdd96phIQEvfTSS+rVq5fS0tK0YMECjR07Vu7u7po4caLi4uIUERHRqHMAAKC1MxgM2rRpkxYuXKi3335bixcvloeHh6KiovTiiy9afEivrq62ej/Tc13s9YTBYFBK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1Pb222/rf/7nf0z/4F1dXXX69Gmb/ffp00ePP/64brnlFt1000164YUX1L17d33wwQdW4//85z/rzJkzGjVqVENP95Lt27dPa9euVWxs7GUbEwAAAJcP18eNw/UxAOBKRU5vHHL6xaGIfpWora2VdPZrJxdSVlZm9S93daZOnaq3335bknT06FF9/PHHmjx5smn/zTffrL/97W+qrKy0evypU6c0Z84cBQYGqmPHjmrfvr2++eYbq3+V++2337RgwQK98sorcnS0vIV/UlKS2rdvb9pefPFFi5iPPvpI7du3V8eOHXXLLbdo5cqVF3wP5syZo8cff1zdu3e/YCwAAABaHq6PuT4GALQO5HRy+uVAEf0qcdNNN8lgMKigoOCCsT/++KO8vb1t7p80aZK+//57ZWdn65133lG3bt0UFhZm2v/aa6/p008/Vbt27dS+fXtFR0ebHT979mylpaVp8eLF2rFjh/Lz83XLLbeooqLCYqxXXnlFPXv21MiRI63O5cEHH1R+fr5pO38sSRoyZIjy8/P1+eefKzo6WjNmzNA//vEPm+eXlZWlHTt2aMGCBTZjAAAA0LJxfcz1MQCgdSCnk9MvB8s/c6BV6ty5s4YPH66VK1dqxowZFn91++WXX9SxY0edOnVKBQUFio+Pt9mXu7u7Ro8erbffflvZ2dl69NFHzfaHhYWppKRERUVFqq6u1vvvv2/217IdO3bokUce0ZgxYySdvV/UwYMHLcYpLi7WqlWrtH37dptzcXNz04033mh2nudr166dKaZXr1567bXXlJeXZ/WvfLW1tXrqqaeUkJCgTp062RwX51noZu8ZXJqFJ+w9AwAArgwXk9Pb+0j9X5WOnpYcL7wCrNn8mCd539bgcK6PuT4GgFatsTn9SsnnEjn9/yGnX1nsvhI9KSlJ/v7+cnV1VVBQkHbs2GEztri4WBMnTlTPnj3Vpk0bi6fU1vnll180ffp0de3aVa6urgoICFB6enoznUHLkZSUpOrqat15551KS0vT/v37VVBQoOXLlyskJETffPONHnjgAXXs2FERERH19jV16lT9+c9/VkFBgR5++GGL/Q4ODvL399eNN96o6667zmzfjTfeqPfff1/5+fnau3evJk6cqJqaGos+Vq5cqTFjxuj222+/pPOuqanRmTNndPLkSX3wwQc6dOiQbrnlFqux//jHP3TixAnFxMRc0pgAAAC48nF9zPUxAKB1IKeT05ubXVeip6amatasWUpKSlL//v31xhtvKCIiQl9//bV8fX0t4svLy9WlSxfNnz9fr732mtU+KyoqNGzYMF133XX629/+phtuuEGHDx/Wtdde29ync8Xz9/fXnj17tHjxYj311FMqLi5Wly5dFBQUpFWrVmnhwoWqqqrS1q1bL/hU4Lvuuktdu3bVzTffXO/XYKx57bXXNHnyZIWGhsrDw0PPPPOMysrKLOJqamq0ePHiRvVtzYcffqi2bdvK0dFRvr6+SkxM1PDhw61+zefUqVN66aWXzB4sAQAAgNaJ62OujwEArQM5nZze3Ay1dXfft4N+/frp9ttv16pVq0xtAQEBGj16tBITE+s9dvDgwerbt6+MRqNZe3Jysl555RV98803cnJyuqh5lZWVyc3NTSdOnFCHDh3M9p05c0aFhYWm1fNXq99++03e3t5au3atxo4da+/poIlc9M83t3MBGqS+/ILmwXsONNJF5PQz7X1U2P9V+V/fRa72/vp3I7763dS4Pm596rs2Jr9cfrznQCM1MqdfUflcIqejSTVFTrfb7VwqKiqUm5ur8PBws/bw8HDt2rXrovv94IMPFBISounTp8vT01O9e/fWiy++qOrq6kudMnT2L2U//vijEhIS5Obmpvvuu8/eUwIAAADshutjAABaB3I66mO327mUlpaqurpanp6eZu2enp4qKSm56H6///57/fOf/9SDDz6o9PR07d+/X9OnT1dVVZX+93//1+ox5eXlKi8vN7229jULnFVUVCR/f3/dcMMNSklJsfqgAgAAAOBqwfUxAACtAzkd9bH7T4PBYP4VkdraWou2xqipqdF1112n1atXy8HBQUFBQfrxxx/1yiuv2CyiJyYm6rnnnrvoMa8m3bp1kx3vAAQAAABcUbg+BgCgdSCnoz52u52Lh4eHHBwcLFadHz161GJ1emN07dpVv/vd7+Tg4GBqCwgIUElJiSoqKqweEx8frxMnTpi2w4cPX/T4AAAAAAAAAIDWw25FdGdnZwUFBSkzM9OsPTMzU6GhoRfdb//+/fXdd9+ppqbG1LZv3z517drV5tNnXVxc1KFDB7MNAAAAAAAAAAC7FdElKS4uTm+99ZbWrl2rgoICxcbGqqioSNHR0ZLOrhCfNGmS2TH5+fnKz8/XyZMn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lzWtS5cuOnv2rH744QcdPHhQeXl5uv/+++2W88477+jbb78td3udPn1aDRo0cDl/9+7d2rJli91y27RpI0l2y77rrrvs2hcbG6sjR46oqKhI6enpMsaoVatWdsvZunWr3TJKtoO/v7/uuusujRw50tp2GRkZuvXWW+3OVHfp0kXFxcX6+uuvnbbd/P9HCZRuV3lKvu+GDRvqzJkzdr8giI6OVkpKik6cOOHy89u2bVNAQICCg4N14cIFTZ8+3Zq3ZcsW3X///WratKkCAwOVkJCg06dP69y5cw7r76oflGjWrJldOWc6d+6sgIAANWvWTD169FBmZma5617RvlDi5MmT+vHHH3XvvfeWW85d58+f1/jx4/X666+rbt261vSMjAzl5+e7rMfd/pCZmanu3bsrLy9P3bp1q5I2V8aiRYtUr149ZWZm6ocffrCbd9NNN1nfYa9evZSfn293XKiMyZMn2/WJsscgV9zpl126dJG3979j6He/+50uXryob775xpqWm5vr9FckZRlj9MILL2jSpEkKCgqqxBr+27x589SpUyddf/31CggI0IIFC9xeX9Q+ZDqZXoJMJ9PJ9PKR6ajpyHQyvQSZTqaT6eUj0y8Pg+iVUL9+fd1444268cYbdccdd2jRokXy8/PTBx984FD2hRde0IgRIxQWFuZ0WTNmzLCCfu/everUqZM179y5c4qPj1dAQID+53/+R2lpaVq9erWkS5ePVaR0YAQGBtrVs27dOruyxhiHgCkdPMXFxZKktWvX2i3n4MGD+sc//lFuO7777jtFRUW5nF9cXKyHH37Ybrl79+7VkSNHdPfdd1e4niXLqFOnjnbv3m23jIyMDL311lsO22H//v366KOPtGTJEi1ZssTlNijhanrLli3l5eXl9gGv5PvetWuXoqOj9cc//tGaN3HiREVFRVnB6Cw4O3XqpD179mjDhg06ffq0FixYIEn6/vvv9dBDD6l9+/ZKTk7W7t27NXv2bEmyu1ywon5QYtu2bXblnFmxYoX27t2r999/X1lZWUpISCh33SvaF0r8lsspy/P666+rdevWevjhhytVj7v9Yf/+/Ro4cKAef/xxPfnkk9a+ciWkpqZqxowZ+vDDDxUbG6uBAwda+60krVu3zvoOS45Pv3X7Dho0yK5PhIeHV/gZd/plw4YN3drOP/74o1t1vvPOOzp3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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "df = pd.read_csv('data/task1/results.csv')\n", + "mean_times = df.groupby(['Структура', 'Режим'])[['Вставка', 'Поиск', 'Удаление']].mean().reset_index()\n", + "structures = mean_times['Структура'].unique()\n", + "modes = mean_times['Режим'].unique()\n", + "\n", + "fig, axes = plt.subplots(1, 3, figsize=(15, 5))\n", + "operations = ['Вставка', 'Поиск', 'Удаление']\n", + "\n", + "for ax, op in zip(axes, operations):\n", + " # a\n", + " x = np.arange(len(structures))\n", + " width = 0.35\n", + " \n", + " random_vals = []\n", + " sorted_vals = []\n", + " for s in structures:\n", + " random_row = mean_times[(mean_times['Структура']==s) & (mean_times['Режим']=='Cлучайный')]\n", + " sorted_row = mean_times[(mean_times['Структура']==s) & (mean_times['Режим']=='Отсортированный')]\n", + " random_vals.append(random_row[op].values[0] if not random_row.empty else 0)\n", + " sorted_vals.append(sorted_row[op].values[0] if not sorted_row.empty else 0)\n", + " \n", + " ax.bar(x - width/2, random_vals, width, label='Случайный')\n", + " ax.bar(x + width/2, sorted_vals, width, label='Отсортированный')\n", + " ax.set_xticks(x)\n", + " ax.set_xticklabels(structures)\n", + " ax.set_ylabel('Время (сек)')\n", + " ax.set_title(op)\n", + " ax.legend()\n", + "\n", + "plt.tight_layout()\n", + "plt.savefig('data/task1/performance_plot.png', dpi=150)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "1d86131d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
СтруктураРежимВставкаПоискУдаление
0Бинарное деревоCлучайный0.0119210.0001500.000137
1Бинарное деревоОтсортированный0.1221710.0016270.000873
2Связанный списокCлучайный0.0900390.0008930.000605
3Связанный списокОтсортированный0.1624470.0017070.000915
4Хэш-таблицаCлучайный0.0448310.0006180.000324
5Хэш-таблицаОтсортированный0.0493690.0005270.000272
\n", + "
" + ], + "text/plain": [ + " Структура Режим Вставка Поиск Удаление\n", + "0 Бинарное дерево Cлучайный 0.011921 0.000150 0.000137\n", + "1 Бинарное дерево Отсортированный 0.122171 0.001627 0.000873\n", + "2 Связанный список Cлучайный 0.090039 0.000893 0.000605\n", + "3 Связанный список Отсортированный 0.162447 0.001707 0.000915\n", + "4 Хэш-таблица Cлучайный 0.044831 0.000618 0.000324\n", + "5 Хэш-таблица Отсортированный 0.049369 0.000527 0.000272" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv('data/task1/results.csv')\n", + "df.groupby(['Структура', 'Режим'])[['Вставка', 'Поиск', 'Удаление']].mean().reset_index()" + ] + }, + { + "cell_type": "markdown", + "id": "c9a486a5", + "metadata": {}, + "source": [ + "# 4. Анализ результатов\n", + "---\n", + "### 4.1 Влияние порядка данных на вставку в BST\n", + "При вставке элементов в отсортированном порядке в бинарное дерево оно превращается в связный список - это связанно с тем, что все элементы вставляются в одну ветвь дерева. Сложность всех операций приблтижается к **O(n)**. Вставка в BST на отсортированных данных заняла 0.122171c вместо 0.011921с, разница более чем в 10 раз. Причём, время вставки даже хуже, чем у чистого связнного списка - это связанно с дополнительными расходами бинарного дерева. Поиск так же ухудшился, примерно в 10 раз, а с ним ухудшилось и удаление.\n", + "\n", + "### 4.2 Почему хэш-таблица почти не чувствительна к порядку\n", + "По графикам видно, что для хэш-таблицы время операций почти не изменяется. Исключение составляет лишь поиск, его время больше на отсортированных данных. Это связано с особенностями теста - поиск 10 несуществующих записей ухудшают результат для отсортированных данных. Все эти наблюдения связаны с механизмом работы хэш-таблицы - она распределяет данные по корзинам независимо от порядка поступления. Получается, что сложность всех операций **O(1)**\n", + "\n", + "### 4.3 Почему связный список всегда медленен при поиске\n", + "Для поиска в связном списке нужно просматривать все элементы по порядку, так что сложность всех операций **O(n)**\n", + "\n", + "### 4.4 Сравнение удаления\n", + "\n", + "- **Связаный список** удаление требует сначала найти элемент за O(n), затем переставить ссылки за O(1). Время удаления (0.000605 с) близко ко времени поиска, что логично.\n", + "- **Хеш-таблица:** при удалении, поиск корзины за O(1) и поиск в коротком связаном списке за O(n) удаляется элемент. Время удаления (0.000324) меньше, чем в списке.\n", + "- **BST:** на случайных данных удаление очень быстрое (0.000137 с) благодаря логарифмической высоте. На отсортированных данных время возрастает до 0.000873, что отражает деградацию до O(n)." + ] + }, + { + "cell_type": "markdown", + "id": "a7ed5470", + "metadata": {}, + "source": [ + "# 5. Вывод\n", + "На основе полученных результатов можно сформулировать следующие рекомендации:\n", + "\n", + "- Хеш-таблица – хороший выбор, если приоритетом является максимальная скорость вставки, поиска и удаления по ключу, а порядок элементов не имеет значения. Время операций близко к **O(1)** и практически не зависит от упорядоченности входных данных. Идеальна для кэшей, словарей и частых запросов по идентификатору.\n", + "\n", + "- Двоичное дерево поиска – следует применять, когда необходимо получать данные в отсортированном порядке. На случайных данных демонстрирует хорошую производительность **O(log n)**, однако при поступлении заранее отсортированных элементов вырождается в связный список с падением скорости до **O(n)**.\n", + "\n", + "- Связный список – демонстрирует линейную сложность поиска и удаления **O(n)** что делает его непригодным для задач с частым доступом к произвольным элементам. Может быть оправдан только в узких случаях, где вставки и удаления происходят исключительно в начале или конце коллекции (очереди, стеки) и не требуется поиск.\n", + "\n", + "Таким образом, для реальных задач чаще всего выбирают хеш-таблицы или сбалансированные деревья в зависимости от требований к упорядоченности данных.\n" ] } ], @@ -140,7 +341,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.14.3" + "version": "3.11.2" } }, "nbformat": 4, diff --git a/MusinAA/docs/data/results.csv b/MusinAA/docs/data/results.csv deleted file mode 100644 index 8f5e275..0000000 --- a/MusinAA/docs/data/results.csv +++ /dev/null @@ -1,31 +0,0 @@ -Структура,Режим,Вставка,Поиск,Удаление -Связанный список,Cлучайный,4.661078881000321,0.012941928999680385,0.020117076999667916 -Хэш-таблица,Cлучайный,0.18879180299973086,0.0014481220005109208,0.0012560499999381136 -Бинарное дерево,Cлучайный,0.01616830700004357,0.00016560199946979992,0.00016564300040045055 -Связанный список,Отсортированный,5.038275819999399,0.07141196100019442,0.1353478549999636 -Хэш-таблица,Отсортированный,0.1631836659998953,0.003129734999674838,0.003202291999514273 -Бинарное дерево,Отсортированный,0.16634428900033527,0.0017354540004816954,0.001874036000117485 -Связанный список,Cлучайный,4.664316974999565,0.014653709000413073,0.02280332600003021 -Хэш-таблица,Cлучайный,0.186777711999639,0.0010283499996148748,0.0009878339997158037 -Бинарное дерево,Cлучайный,0.016256722999969497,0.00015175599946815055,0.0001649409996389295 -Связанный список,Отсортированный,5.907060995999927,0.08458327099924645,0.12409427100010362 -Хэш-таблица,Отсортированный,0.18781050100005814,0.003518858999996155,0.0038270310005827923 -Бинарное дерево,Отсортированный,0.17500397699950554,0.0019018089997189236,0.001833940000324219 -Связанный список,Cлучайный,5.755159846999959,0.016742109000006167,0.026386416000605095 -Хэш-таблица,Cлучайный,0.22951744300007704,0.0009921219998432207,0.0011742059996322496 -Бинарное дерево,Cлучайный,0.01580532200023299,0.00017768500038073398,0.00019722199976968113 -Связанный список,Отсортированный,6.30150953500015,0.11176149099992472,0.1474957850005012 -Хэш-таблица,Отсортированный,0.18557919999966543,0.003155624000100943,0.002713390000280924 -Бинарное дерево,Отсортированный,0.19082545899982506,0.001985636999961571,0.002389950000178942 -Связанный список,Cлучайный,6.395210606000546,0.014804241999627266,0.02304338900012226 -Хэш-таблица,Cлучайный,0.1902105980007036,0.000852088000101503,0.0009626670007492066 -Бинарное дерево,Cлучайный,0.01663886400001502,0.00016400000004068715,0.000184548000106588 -Связанный список,Отсортированный,4.850914527999521,0.0771323629996914,0.1152741280002374 -Хэш-таблица,Отсортированный,0.17607759100064868,0.002924628000073426,0.0033850670006358996 -Бинарное дерево,Отсортированный,0.19345043999965128,0.0018585970001367969,0.0019752460002564476 -Связанный список,Cлучайный,4.803303787999539,0.015972447000422108,0.0223228390004806 -Хэш-таблица,Cлучайный,0.19020581800032232,0.0011616620004133438,0.0009839170006671338 -Бинарное дерево,Cлучайный,0.016469425000650517,0.000160212000082538,0.00017693399968266021 -Связанный список,Отсортированный,4.741838529000233,0.075463203000254,0.10462550600004761 -Хэш-таблица,Отсортированный,0.16722737300005974,0.004002030999799899,0.005207103999964602 -Бинарное дерево,Отсортированный,0.16575109800032806,0.0020921670002280734,0.002277146999404067 diff --git a/MusinAA/docs/data/task1/performance_plot.png b/MusinAA/docs/data/task1/performance_plot.png new file mode 100644 index 0000000000000000000000000000000000000000..f4080211dd4ee427dcfee91e89880fee38ddc44a GIT binary patch literal 72782 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 TJ6_yAU$a dict: currentNode = head while currentNode['next'] != None: + if currentNode['name'] == name: + currentNode['phone'] = phone + return head currentNode = currentNode['next'] currentNode['next'] = newNode return head -- 2.43.0