[1] лабораторная работа №1 "структуры данных" #272

Closed
petryaninyas wants to merge 2 commits from petryaninyas/2026-rff_mp:task1 into develop
79 changed files with 940 additions and 3 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ __pycache__/
# C extensions
*.so
.DS_Store
# Distribution / packaging
.Python
build/

0
BudakovIS/428.md Normal file
View File

0
DerbenevRY/428.md Normal file
View File

1
KuzminskiyAA/427.md Normal file
View File

@ -0,0 +1 @@

0
KuznetsovAS/427.md Normal file
View File

0
MashinDD/429.txt Normal file
View File

1
MininaVD/427.txt Normal file
View File

@ -0,0 +1 @@
427.txt

1
MininaVD/MininaVD Normal file
View File

@ -0,0 +1 @@
427.txt

0
MusinAA/428b.md Normal file
View File

1
MylnikovAS/427.md Normal file
View File

@ -0,0 +1 @@

BIN
ProninVV/427.md Normal file

Binary file not shown.

BIN
ProninVV/file.txt Normal file

Binary file not shown.

151
README.md
View File

@ -16,7 +16,7 @@
### Крайний срок приема работ 25.05.2026 до 14:00
## Задание 1 -- репозиторий
## Задание 0 -- репозиторий [отдельный срок на создание PR с папкой: 28.02.2026]
0. Создай пользователя (логин — фамилия+инициалы слитно транслитом, как в терминал-классе).
@ -43,12 +43,157 @@
6. Отправь ветку **в свой форк** на Gitea:
```bash
git push origin IvanovII
git push origin
```
если просит, перед этим сделать git push --set-upstream origin
7. **Создай запрос на слияние (Pull Request):** На Gitea перейди в свой форк, выбери ветку `IvanovII`, нажмите **Запрос на слияние**. Убедитесь, что:
- Базовый репозиторий: **учебный** (преподавателя)
- Базовая ветка: **develop**
- Сравниваемая ветка: **свой форк / IvanovII**
8. Отправь PR.
8. Отправь PR.
## Задание 1 -- структуры данных
***Напоминание: под каждое задание вы создаете отдельную ветку***
>Для оформления результатов заведи папку **docs** в своей папке и сохраняй туда отчет (в любом формате от .doc до .md, а то и .jpnb). Вспомогательные файлы клади в подпапку **data** внутри **docs**
**Цель работы**
Реализовать три различные структуры данных «с нуля», применить их для хранения записей телефонного справочника и экспериментально сравнить производительность основных операций. Вы должны собственными руками написать код, чтобы понять внутреннее устройство связного списка, хеш-таблицы и двоичного дерева поиска, а также осознать их сильные и слабые стороны на практике.
**!! Задание выполнять в структурной (процедурной) парадигме, не используя классы. Главное реализовать структуры данных «руками» и сравнить их производительность.**
### Базовые операции (обязательны для всех):
`insert(name, phone)` -- добавить или обновить запись.
`find(name)` -- phone или None.
`delete(name)` -- удалить запись, игнорировать отсутствие.
`list_all()` -- список всех записей, отсортированный по имени (для BST inorder обход; для списка и хеш‑таблицы — собрать и отсортировать явно).
#### 1. Связный список (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)` — собирает все записи в список и сортирует (сортировка вынесена отдельно).
#### 2. Хеш-таблица
Хранится как список buckets фиксированной длины, каждый элемент — голова связного списка (или None).
**Функции:**
`def ht_insert(buckets, name, phone)` — вычисляет индекс, вызывает ll_insert для соответствующего бакета.
Аналогично `ht_find, ht_delete, ht_list_all` (последняя собирает все записи из всех бакетов и сортирует).
#### 3. Двоичное дерево поиска
Узел — словарь: `{'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)` — центрированный обход (рекурсивно собирает записи в отсортированном порядке).
### Экспериментальная часть (подробно об измерении времени)
#### 1. Генерация тестовых данных
Создайте список records из N элементов (например, N = 10000). Каждый элемент — кортеж (name, phone).
Имена генерируйте как `f"User_{i:05d}"` (равномерное распределение) или случайные слова из небольшого набора (чтобы были повторения и коллизии). Для проверки влияния порядка подготовьте два варианта одного и того же набора:
`records_shuffled` — случайный порядок.
`records_sorted` — отсортированный по имени (по алфавиту).
#### 2. Инструменты замера времени
Используйте модуль **time**:
```python
import time
start = time.perf_counter()
# ... операции ...
end = time.perf_counter()
elapsed = end - start # время в секундах
```
Для многократных замеров удобен `timeit`, но в этой задаче достаточно просто обернуть код в цикл и усреднить.
#### 3. Проведение замеров
Для каждой структуры данных и для каждого режима входных данных (случайный / отсортированный) выполните:
- А. Вставка всех записей
Создайте пустую структуру.
Засеките время, выполните insert для каждой записи из входного списка.
Зафиксируйте общее время вставки.
- Б. Поиск 100 случайных записей
Возьмите 100 случайных имён из того же набора (гарантированно существующих) и 10 имён, которых нет (например, "None_{i}").
Засеките время на выполнение всех 110 вызовов find.
- В. Удаление 50 случайных записей
Выберите 50 случайных имён из набора.
Засеките время на выполнение delete для каждого.
**!! Важно: после вставки структура остаётся заполненной, поиск и удаление выполняются на ней же. Если нужно повторить замер для другого порядка данных — создавайте новую структуру и заполняйте заново.**
#### 4. Сохранение результатов
**!! Каждый эксперимент повторить минимум 5 раз и записывать и среднее время, и все замеры.**
Соберите все замеры в словарь или список, затем сохраните в CSV-файл:
```python
import csv
results = [
["Структура", "Режим", "Операция", "Время (сек)"],
["LinkedList", "случайный", "вставка", 0.123],
...
]
with open("results.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerows(results)
```
#### 5. Анализ результатов
Постройте график (столбчатая диаграмма или линейный график) — можно в Excel, Google Sheets или с помощью matplotlib в Python.
Сравните:
- Как порядок входных данных влияет на скорость вставки в BST (деградация до O(n) на отсортированных данных).
- Почему хеш-таблица почти не чувствительна к порядку.
- Почему связный список всегда медленен при поиске.
- Как удаление работает в каждой структуре.
* Вывод должен содержать ответ на вопрос: какую структуру и для каких задач (частые вставки, частый поиск, необходимость получать данные в порядке) стоит выбирать в реальной жизни.*

0
SimonovaMS/428.md Normal file
View File

0
SimonovaMS/428.txt Normal file
View File

0
SolovevDS/428b.md Normal file
View File

1
VaravinVV/428b Normal file
View File

@ -0,0 +1 @@
428b

0
VolkovVA/428b.md Normal file
View File

0
YanyaevAA/428b.md Normal file
View File

1
YaroslavtsevAS/428.md Normal file
View File

@ -0,0 +1 @@
428

0
ZelentsovAV/428b.md Normal file
View File

0
anikinvd/428.md Normal file
View File

0
chizhikovaSM/428.md Normal file
View File

0
duznb/429.md.txt Normal file
View File

1
filippovavm/427 Normal file
View File

@ -0,0 +1 @@
427

0
fomichevks/426.md.txt Normal file
View File

1
ivanchenkoam/427.txt Normal file
View File

@ -0,0 +1 @@
856

0
ivantsovma/428.txt Normal file
View File

0
kolesovve/427.md Normal file
View File

BIN
komissarovgo/427.md Normal file

Binary file not shown.

1
konnovaea/429 Normal file
View File

@ -0,0 +1 @@
429

0
kornevma/426.md Normal file
View File

0
krasnovia/429.txt Normal file
View File

0
lomakinae/426 Normal file
View File

0
meosyam/428.md.txt Normal file
View File

2
morozovns/1.py Normal file
View File

@ -0,0 +1,2 @@
print("Zadanie adin!!11!adin!11!")
print("patch")

1
morozovns/429 Normal file
View File

@ -0,0 +1 @@
429

1
nehoroshevaa/428b.md Normal file
View File

@ -0,0 +1 @@
428b

BIN
nikolaevda/427.md Normal file

Binary file not shown.

0
novikovsd/428 Normal file
View File

0
osininyai/427.md Normal file
View File

0
petryaninyas/426.md Normal file
View File

18
petryaninyas/README.md Normal file
View File

@ -0,0 +1,18 @@
# Задание 1 — структуры данных
Процедурная реализация:
- linked_list.py
- hash_table.py
- bst.py
Эксперименты и отчёты:
- experiments.py
- plot_results.py
- results.csv
- docs/report.md
- docs/data/*.png
Запуск:
```bash
python main.py
```

118
petryaninyas/bst.py Normal file
View File

@ -0,0 +1,118 @@
from typing import Any, Dict, List, Optional
Node = Dict[str, Any]
def _make_node(name: str, phone: str) -> Node:
return {"name": name, "phone": phone, "left": None, "right": None}
def bst_insert(root: Optional[Node], name: str, phone: str) -> Node:
new_node = _make_node(name, phone)
if root is None:
return new_node
current = root
parent = None
while current is not None:
parent = current
if name < current["name"]:
current = current["left"]
elif name > current["name"]:
current = current["right"]
else:
current["phone"] = phone
return root
if name < parent["name"]:
parent["left"] = new_node
else:
parent["right"] = new_node
return root
def bst_find(root: Optional[Node], name: str) -> Optional[str]:
current = root
while current is not None:
if name < current["name"]:
current = current["left"]
elif name > current["name"]:
current = current["right"]
else:
return current["phone"]
return None
def _find_min_node(node: Node) -> Node:
current = node
while current["left"] is not None:
current = current["left"]
return current
def bst_delete(root: Optional[Node], name: str) -> Optional[Node]:
if root is None:
return None
parent = None
current = root
while current is not None and current["name"] != name:
parent = current
if name < current["name"]:
current = current["left"]
else:
current = current["right"]
if current is None:
return root
if current["left"] is None or current["right"] is None:
child = current["left"] if current["left"] is not None else current["right"]
if parent is None:
return child
if parent["left"] is current:
parent["left"] = child
else:
parent["right"] = child
return root
succ_parent = current
successor = current["right"]
while successor["left"] is not None:
succ_parent = successor
successor = successor["left"]
current["name"] = successor["name"]
current["phone"] = successor["phone"]
successor_child = successor["right"]
if succ_parent["left"] is successor:
succ_parent["left"] = successor_child
else:
succ_parent["right"] = successor_child
return root
def bst_list_all(root: Optional[Node]) -> List[Dict[str, str]]:
result: List[Dict[str, str]] = []
stack: List[Node] = []
current = root
while current is not None or stack:
while current is not None:
stack.append(current)
current = current["left"]
current = stack.pop()
result.append({"name": current["name"], "phone": current["phone"]})
current = current["right"]
return result

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

@ -0,0 +1,109 @@
Структура,Режим,Операция,Замер,Время (сек)
LinkedList,случайный,insert,1,4.2622492010
LinkedList,случайный,find,1,0.0314994130
LinkedList,случайный,delete,1,0.0149069000
LinkedList,случайный,insert,2,4.0154580330
LinkedList,случайный,find,2,0.0393284500
LinkedList,случайный,delete,2,0.0210732100
LinkedList,случайный,insert,3,4.0436019780
LinkedList,случайный,find,3,0.0344933660
LinkedList,случайный,delete,3,0.0152639850
LinkedList,случайный,insert,4,3.7182993220
LinkedList,случайный,find,4,0.0327698850
LinkedList,случайный,delete,4,0.0149959540
LinkedList,случайный,insert,5,3.7082228200
LinkedList,случайный,find,5,0.0303762490
LinkedList,случайный,delete,5,0.0141406560
LinkedList,случайный,insert,среднее,3.9495662708
LinkedList,случайный,find,среднее,0.0336934726
LinkedList,случайный,delete,среднее,0.0160761410
HashTable,случайный,insert,1,0.2059865770
HashTable,случайный,find,1,0.0014966100
HashTable,случайный,delete,1,0.0006891700
HashTable,случайный,insert,2,0.2024331460
HashTable,случайный,find,2,0.0015934880
HashTable,случайный,delete,2,0.0007212620
HashTable,случайный,insert,3,0.2126128040
HashTable,случайный,find,3,0.0016566220
HashTable,случайный,delete,3,0.0008358420
HashTable,случайный,insert,4,0.2157934910
HashTable,случайный,find,4,0.0015542810
HashTable,случайный,delete,4,0.0007269120
HashTable,случайный,insert,5,0.2079924580
HashTable,случайный,find,5,0.0013696990
HashTable,случайный,delete,5,0.0006616050
HashTable,случайный,insert,среднее,0.2089636952
HashTable,случайный,find,среднее,0.0015341400
HashTable,случайный,delete,среднее,0.0007269582
BST,случайный,insert,1,0.0166981280
BST,случайный,find,1,0.0001569360
BST,случайный,delete,1,0.0000917280
BST,случайный,insert,2,0.0184119040
BST,случайный,find,2,0.0001517110
BST,случайный,delete,2,0.0001163770
BST,случайный,insert,3,0.0174662270
BST,случайный,find,3,0.0001582930
BST,случайный,delete,3,0.0000892660
BST,случайный,insert,4,0.0191369100
BST,случайный,find,4,0.0002087170
BST,случайный,delete,4,0.0001067050
BST,случайный,insert,5,0.0184276900
BST,случайный,find,5,0.0002767720
BST,случайный,delete,5,0.0001067660
BST,случайный,insert,среднее,0.0180281718
BST,случайный,find,среднее,0.0001904858
BST,случайный,delete,среднее,0.0001021684
LinkedList,отсортированный,insert,1,2.9875078340
LinkedList,отсортированный,find,1,0.0237300610
LinkedList,отсортированный,delete,1,0.0111698260
LinkedList,отсортированный,insert,2,3.0573987940
LinkedList,отсортированный,find,2,0.0243270360
LinkedList,отсортированный,delete,2,0.0115366030
LinkedList,отсортированный,insert,3,2.9641987260
LinkedList,отсортированный,find,3,0.0236313330
LinkedList,отсортированный,delete,3,0.0112848510
LinkedList,отсортированный,insert,4,3.0345914950
LinkedList,отсортированный,find,4,0.0240271220
LinkedList,отсортированный,delete,4,0.0112117310
LinkedList,отсортированный,insert,5,2.9481954700
LinkedList,отсортированный,find,5,0.0239006100
LinkedList,отсортированный,delete,5,0.0110857710
LinkedList,отсортированный,insert,среднее,2.9983784638
LinkedList,отсортированный,find,среднее,0.0239232324
LinkedList,отсортированный,delete,среднее,0.0112577564
HashTable,отсортированный,insert,1,0.1997087560
HashTable,отсортированный,find,1,0.0017550400
HashTable,отсортированный,delete,1,0.0008407980
HashTable,отсортированный,insert,2,0.1968675190
HashTable,отсортированный,find,2,0.0019886760
HashTable,отсортированный,delete,2,0.0008920910
HashTable,отсортированный,insert,3,0.1907563580
HashTable,отсортированный,find,3,0.0018447440
HashTable,отсортированный,delete,3,0.0008684640
HashTable,отсортированный,insert,4,0.2625327630
HashTable,отсортированный,find,4,0.0016053140
HashTable,отсортированный,delete,4,0.0008098670
HashTable,отсортированный,insert,5,0.1936840590
HashTable,отсортированный,find,5,0.0019015160
HashTable,отсортированный,delete,5,0.0009053780
HashTable,отсортированный,insert,среднее,0.2087098910
HashTable,отсортированный,find,среднее,0.0018190580
HashTable,отсортированный,delete,среднее,0.0008633196
BST,отсортированный,insert,1,4.2195800190
BST,отсортированный,find,1,0.0389314570
BST,отсортированный,delete,1,0.0190308920
BST,отсортированный,insert,2,4.1356184250
BST,отсортированный,find,2,0.0383339310
BST,отсортированный,delete,2,0.0194247740
BST,отсортированный,insert,3,4.1204731890
BST,отсортированный,find,3,0.0388593320
BST,отсортированный,delete,3,0.0215428460
BST,отсортированный,insert,4,4.2120902370
BST,отсортированный,find,4,0.0378190250
BST,отсортированный,delete,4,0.0188528460
BST,отсортированный,insert,5,4.1304951260
BST,отсортированный,find,5,0.0359927840
BST,отсортированный,delete,5,0.0179617110
BST,отсортированный,insert,среднее,4.1636513992
BST,отсортированный,find,среднее,0.0379873058
BST,отсортированный,delete,среднее,0.0193626138
1 Структура Режим Операция Замер Время (сек)
2 LinkedList случайный insert 1 4.2622492010
3 LinkedList случайный find 1 0.0314994130
4 LinkedList случайный delete 1 0.0149069000
5 LinkedList случайный insert 2 4.0154580330
6 LinkedList случайный find 2 0.0393284500
7 LinkedList случайный delete 2 0.0210732100
8 LinkedList случайный insert 3 4.0436019780
9 LinkedList случайный find 3 0.0344933660
10 LinkedList случайный delete 3 0.0152639850
11 LinkedList случайный insert 4 3.7182993220
12 LinkedList случайный find 4 0.0327698850
13 LinkedList случайный delete 4 0.0149959540
14 LinkedList случайный insert 5 3.7082228200
15 LinkedList случайный find 5 0.0303762490
16 LinkedList случайный delete 5 0.0141406560
17 LinkedList случайный insert среднее 3.9495662708
18 LinkedList случайный find среднее 0.0336934726
19 LinkedList случайный delete среднее 0.0160761410
20 HashTable случайный insert 1 0.2059865770
21 HashTable случайный find 1 0.0014966100
22 HashTable случайный delete 1 0.0006891700
23 HashTable случайный insert 2 0.2024331460
24 HashTable случайный find 2 0.0015934880
25 HashTable случайный delete 2 0.0007212620
26 HashTable случайный insert 3 0.2126128040
27 HashTable случайный find 3 0.0016566220
28 HashTable случайный delete 3 0.0008358420
29 HashTable случайный insert 4 0.2157934910
30 HashTable случайный find 4 0.0015542810
31 HashTable случайный delete 4 0.0007269120
32 HashTable случайный insert 5 0.2079924580
33 HashTable случайный find 5 0.0013696990
34 HashTable случайный delete 5 0.0006616050
35 HashTable случайный insert среднее 0.2089636952
36 HashTable случайный find среднее 0.0015341400
37 HashTable случайный delete среднее 0.0007269582
38 BST случайный insert 1 0.0166981280
39 BST случайный find 1 0.0001569360
40 BST случайный delete 1 0.0000917280
41 BST случайный insert 2 0.0184119040
42 BST случайный find 2 0.0001517110
43 BST случайный delete 2 0.0001163770
44 BST случайный insert 3 0.0174662270
45 BST случайный find 3 0.0001582930
46 BST случайный delete 3 0.0000892660
47 BST случайный insert 4 0.0191369100
48 BST случайный find 4 0.0002087170
49 BST случайный delete 4 0.0001067050
50 BST случайный insert 5 0.0184276900
51 BST случайный find 5 0.0002767720
52 BST случайный delete 5 0.0001067660
53 BST случайный insert среднее 0.0180281718
54 BST случайный find среднее 0.0001904858
55 BST случайный delete среднее 0.0001021684
56 LinkedList отсортированный insert 1 2.9875078340
57 LinkedList отсортированный find 1 0.0237300610
58 LinkedList отсортированный delete 1 0.0111698260
59 LinkedList отсортированный insert 2 3.0573987940
60 LinkedList отсортированный find 2 0.0243270360
61 LinkedList отсортированный delete 2 0.0115366030
62 LinkedList отсортированный insert 3 2.9641987260
63 LinkedList отсортированный find 3 0.0236313330
64 LinkedList отсортированный delete 3 0.0112848510
65 LinkedList отсортированный insert 4 3.0345914950
66 LinkedList отсортированный find 4 0.0240271220
67 LinkedList отсортированный delete 4 0.0112117310
68 LinkedList отсортированный insert 5 2.9481954700
69 LinkedList отсортированный find 5 0.0239006100
70 LinkedList отсортированный delete 5 0.0110857710
71 LinkedList отсортированный insert среднее 2.9983784638
72 LinkedList отсортированный find среднее 0.0239232324
73 LinkedList отсортированный delete среднее 0.0112577564
74 HashTable отсортированный insert 1 0.1997087560
75 HashTable отсортированный find 1 0.0017550400
76 HashTable отсортированный delete 1 0.0008407980
77 HashTable отсортированный insert 2 0.1968675190
78 HashTable отсортированный find 2 0.0019886760
79 HashTable отсортированный delete 2 0.0008920910
80 HashTable отсортированный insert 3 0.1907563580
81 HashTable отсортированный find 3 0.0018447440
82 HashTable отсортированный delete 3 0.0008684640
83 HashTable отсортированный insert 4 0.2625327630
84 HashTable отсортированный find 4 0.0016053140
85 HashTable отсортированный delete 4 0.0008098670
86 HashTable отсортированный insert 5 0.1936840590
87 HashTable отсортированный find 5 0.0019015160
88 HashTable отсортированный delete 5 0.0009053780
89 HashTable отсортированный insert среднее 0.2087098910
90 HashTable отсортированный find среднее 0.0018190580
91 HashTable отсортированный delete среднее 0.0008633196
92 BST отсортированный insert 1 4.2195800190
93 BST отсортированный find 1 0.0389314570
94 BST отсортированный delete 1 0.0190308920
95 BST отсортированный insert 2 4.1356184250
96 BST отсортированный find 2 0.0383339310
97 BST отсортированный delete 2 0.0194247740
98 BST отсортированный insert 3 4.1204731890
99 BST отсортированный find 3 0.0388593320
100 BST отсортированный delete 3 0.0215428460
101 BST отсортированный insert 4 4.2120902370
102 BST отсортированный find 4 0.0378190250
103 BST отсортированный delete 4 0.0188528460
104 BST отсортированный insert 5 4.1304951260
105 BST отсортированный find 5 0.0359927840
106 BST отсортированный delete 5 0.0179617110
107 BST отсортированный insert среднее 4.1636513992
108 BST отсортированный find среднее 0.0379873058
109 BST отсортированный delete среднее 0.0193626138

Binary file not shown.

172
petryaninyas/experiments.py Normal file
View File

@ -0,0 +1,172 @@
from __future__ import annotations
import csv
import random
import time
from pathlib import Path
from typing import Dict, List, Tuple
from linked_list import ll_insert, ll_find, ll_delete
from hash_table import ht_insert, ht_find, ht_delete
from bst import bst_insert, bst_find, bst_delete
from utils import generate_records, prepare_records_variants
Record = Tuple[str, str]
def make_missing_names(count: int = 10) -> List[str]:
return [f"None_{i}" for i in range(count)]
def pick_existing_names(records: List[Record], count: int, seed: int = 42) -> List[str]:
rng = random.Random(seed)
unique_names = list(dict.fromkeys(name for name, _ in records))
if len(unique_names) < count:
raise ValueError(f"Not enough unique names: need {count}, got {len(unique_names)}")
return rng.sample(unique_names, count)
def pick_delete_names(records: List[Record], count: int = 50, seed: int = 43) -> List[str]:
rng = random.Random(seed)
unique_names = list(dict.fromkeys(name for name, _ in records))
if len(unique_names) < count:
raise ValueError(f"Not enough unique names: need {count}, got {len(unique_names)}")
return rng.sample(unique_names, count)
def build_structure(structure_name: str, records: List[Record], buckets_count: int = 2048):
if structure_name == "linked_list":
structure = None
for name, phone in records:
structure = ll_insert(structure, name, phone)
return structure
if structure_name == "hash_table":
buckets = [None] * buckets_count
for name, phone in records:
buckets = ht_insert(buckets, name, phone)
return buckets
if structure_name == "bst":
root = None
for name, phone in records:
root = bst_insert(root, name, phone)
return root
raise ValueError(f"Unknown structure: {structure_name}")
def do_find(structure_name: str, structure: object, existing_names: List[str], missing_names: List[str]) -> None:
if structure_name == "linked_list":
for name in existing_names:
ll_find(structure, name)
for name in missing_names:
ll_find(structure, name)
return
if structure_name == "hash_table":
for name in existing_names:
ht_find(structure, name)
for name in missing_names:
ht_find(structure, name)
return
if structure_name == "bst":
for name in existing_names:
bst_find(structure, name)
for name in missing_names:
bst_find(structure, name)
return
raise ValueError(f"Unknown structure: {structure_name}")
def do_delete(structure_name: str, structure: object, delete_names: List[str]):
if structure_name == "linked_list":
for name in delete_names:
structure = ll_delete(structure, name)
return structure
if structure_name == "hash_table":
for name in delete_names:
structure = ht_delete(structure, name)
return structure
if structure_name == "bst":
for name in delete_names:
structure = bst_delete(structure, name)
return structure
raise ValueError(f"Unknown structure: {structure_name}")
def measure_once(structure_name: str, records: List[Record], buckets_count: int = 2048) -> Dict[str, float]:
existing_names = pick_existing_names(records, 100, seed=42)
missing_names = make_missing_names(10)
delete_names = pick_delete_names(records, 50, seed=43)
start = time.perf_counter()
structure = build_structure(structure_name, records, buckets_count=buckets_count)
insert_time = time.perf_counter() - start
start = time.perf_counter()
do_find(structure_name, structure, existing_names, missing_names)
find_time = time.perf_counter() - start
start = time.perf_counter()
structure = do_delete(structure_name, structure, delete_names)
delete_time = time.perf_counter() - start
return {"insert": insert_time, "find": find_time, "delete": delete_time}
def run_experiments(n: int = 10000, buckets_count: int = 2048, repeats: int = 5):
records = generate_records(n, repeat_names=False)
records_shuffled, records_sorted = prepare_records_variants(records)
datasets = [
("случайный", records_shuffled),
("отсортированный", records_sorted),
]
structures = [
("LinkedList", "linked_list"),
("HashTable", "hash_table"),
("BST", "bst"),
]
operations = ("insert", "find", "delete")
rows = [["Структура", "Режим", "Операция", "Замер", "Время (сек)"]]
for mode_name, dataset_records in datasets:
for human_name, structure_name in structures:
times_by_op = {op: [] for op in operations}
for attempt in range(1, repeats + 1):
result = measure_once(structure_name, dataset_records, buckets_count=buckets_count)
for op_name in operations:
elapsed = result[op_name]
times_by_op[op_name].append(elapsed)
rows.append([human_name, mode_name, op_name, attempt, f"{elapsed:.10f}"])
for op_name in operations:
avg_time = sum(times_by_op[op_name]) / len(times_by_op[op_name])
rows.append([human_name, mode_name, op_name, "среднее", f"{avg_time:.10f}"])
return rows
def save_results_csv(rows, filename: str = "results.csv"):
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(rows)
def main():
rows = run_experiments(n=10000, buckets_count=2048, repeats=5)
save_results_csv(rows, "results.csv")
print("Saved results.csv")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,44 @@
from typing import Any, Dict, List, Optional
from linked_list import ll_insert, ll_find, ll_delete, ll_list_all
Bucket = Optional[Dict[str, Any]]
def _hash_name(name: str, buckets_count: int) -> int:
if buckets_count <= 0:
return 0
return sum(ord(ch) for ch in name) % buckets_count
def ht_insert(buckets: List[Bucket], name: str, phone: str) -> List[Bucket]:
if not buckets:
return buckets
index = _hash_name(name, len(buckets))
buckets[index] = ll_insert(buckets[index], name, phone)
return buckets
def ht_find(buckets: List[Bucket], name: str) -> Optional[str]:
if not buckets:
return None
index = _hash_name(name, len(buckets))
return ll_find(buckets[index], name)
def ht_delete(buckets: List[Bucket], name: str) -> List[Bucket]:
if not buckets:
return buckets
index = _hash_name(name, len(buckets))
buckets[index] = ll_delete(buckets[index], name)
return buckets
def ht_list_all(buckets: List[Bucket]) -> List[Dict[str, str]]:
records: List[Dict[str, str]] = []
for head in buckets:
records.extend(ll_list_all(head))
return sorted(records, key=lambda x: x["name"])

View File

@ -0,0 +1,73 @@
from typing import Any, Dict, List, Optional
Node = Dict[str, Any]
def _make_node(name: str, phone: str) -> Node:
return {"name": name, "phone": phone, "next": None}
def sort_records(records: List[Dict[str, str]]) -> List[Dict[str, str]]:
return sorted(records, key=lambda x: x["name"])
def ll_insert(head: Optional[Node], name: str, phone: str) -> Node:
new_node = _make_node(name, phone)
if head is None:
return new_node
current = head
while current is not None:
if current["name"] == name:
current["phone"] = phone
return head
if current["next"] is None:
current["next"] = new_node
return head
current = current["next"]
return head
def ll_find(head: Optional[Node], name: str) -> Optional[str]:
current = head
while current is not None:
if current["name"] == name:
return current["phone"]
current = current["next"]
return None
def ll_delete(head: Optional[Node], name: str) -> Optional[Node]:
if head is None:
return None
if head["name"] == name:
return head["next"]
prev = head
current = head["next"]
while current is not None:
if current["name"] == name:
prev["next"] = current["next"]
return head
prev = current
current = current["next"]
return head
def ll_list_all(head: Optional[Node]) -> List[Dict[str, str]]:
records: List[Dict[str, str]] = []
current = head
while current is not None:
records.append({"name": current["name"], "phone": current["phone"]})
current = current["next"]
return sort_records(records)

21
petryaninyas/main.py Normal file
View File

@ -0,0 +1,21 @@
from __future__ import annotations
import csv
from pathlib import Path
from experiments import run_experiments, save_results_csv
from plot_results import build_graphs, load_average_results
def main():
rows = run_experiments(n=10000, buckets_count=2048, repeats=5)
save_results_csv(rows, "results.csv")
averaged = load_average_results("results.csv")
build_graphs(averaged, output_dir="docs/data")
print("Done.")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,66 @@
from __future__ import annotations
import csv
from collections import defaultdict
from pathlib import Path
import matplotlib.pyplot as plt
from typing import List, Dict, Any
# Карта соответствия заголовков CSV для удобства поддержки
_CSV_KEYS = {
"STRUCTURE": "Структура",
"MODE": "Режим",
"OP": "Операция",
"MEASURE": "Замер",
"TIME": "Время (сек)"
}
def load_average_results(csv_file: str) -> List[Dict[str, Any]]:
"""Загружает только строки со средними значениями из CSV."""
with open(csv_file, "r", encoding="utf-8") as fh:
return [
{
"structure": row[_CSV_KEYS["STRUCTURE"]],
"mode": row[_CSV_KEYS["MODE"]],
"operation": row[_CSV_KEYS["OP"]],
"time": float(row[_CSV_KEYS["TIME"]])
}
for row in csv.DictReader(fh)
if row[_CSV_KEYS["MEASURE"]] == "среднее"
]
def _render_chart(operation: str, data: List[Dict[str, Any]], save_path: Path) -> None:
"""Вспомогательная функция для отрисовки одного столбчатого графика."""
fig, ax = plt.subplots(figsize=(10, 5))
labels = [f"{rec['structure']}\n{rec['mode']}" for rec in data]
values = [rec["time"] for rec in data]
ax.bar(labels, values, color="cornflowerblue", edgecolor="navy")
ax.set_title(f"{operation.capitalize()} Performance Comparison")
ax.set_xlabel("Data Structure & Input Order")
ax.set_ylabel("Execution Time (seconds)")
ax.tick_params(axis="x", rotation=15)
fig.tight_layout()
fig.savefig(save_path, dpi=150)
plt.close(fig)
print(f"Saved chart: {save_path}")
def build_graphs(results: List[Dict[str, Any]], output_dir: str = "docs/data") -> None:
"""Группирует результаты по операциям и сохраняет графики."""
out_path = Path(output_dir)
out_path.mkdir(parents=True, exist_ok=True)
grouped = defaultdict(list)
for record in results:
grouped[record["operation"]].append(record)
for op_name in ("insert", "find", "delete"):
if op_name in grouped:
target_file = out_path / f"{op_name}.png"
_render_chart(op_name, grouped[op_name], target_file)
def main():
avg_data = load_average_results("results.csv")
build_graphs(avg_data)
if __name__ == "__main__":
main()

View File

@ -0,0 +1 @@
matplotlib>=3.8

109
petryaninyas/results.csv Normal file
View File

@ -0,0 +1,109 @@
Структура,Режим,Операция,Замер,Время (сек)
LinkedList,случайный,insert,1,6.8132659000
LinkedList,случайный,find,1,0.0553455000
LinkedList,случайный,delete,1,0.0304272000
LinkedList,случайный,insert,2,6.8263299000
LinkedList,случайный,find,2,0.0562645000
LinkedList,случайный,delete,2,0.0303858000
LinkedList,случайный,insert,3,6.8117682000
LinkedList,случайный,find,3,0.0567219000
LinkedList,случайный,delete,3,0.0302671000
LinkedList,случайный,insert,4,7.0393228000
LinkedList,случайный,find,4,0.0544359000
LinkedList,случайный,delete,4,0.0313359000
LinkedList,случайный,insert,5,7.0633509000
LinkedList,случайный,find,5,0.0552176000
LinkedList,случайный,delete,5,0.0318664000
LinkedList,случайный,insert,среднее,6.9108075400
LinkedList,случайный,find,среднее,0.0555970800
LinkedList,случайный,delete,среднее,0.0308564800
HashTable,случайный,insert,1,0.3898307000
HashTable,случайный,find,1,0.0022226000
HashTable,случайный,delete,1,0.0012723000
HashTable,случайный,insert,2,0.3844561000
HashTable,случайный,find,2,0.0024825000
HashTable,случайный,delete,2,0.0013425000
HashTable,случайный,insert,3,0.3740853000
HashTable,случайный,find,3,0.0026141000
HashTable,случайный,delete,3,0.0013710000
HashTable,случайный,insert,4,0.3870099000
HashTable,случайный,find,4,0.0022063000
HashTable,случайный,delete,4,0.0015940000
HashTable,случайный,insert,5,0.3869087000
HashTable,случайный,find,5,0.0022110000
HashTable,случайный,delete,5,0.0012524000
HashTable,случайный,insert,среднее,0.3844581400
HashTable,случайный,find,среднее,0.0023473000
HashTable,случайный,delete,среднее,0.0013664400
BST,случайный,insert,1,0.0375842000
BST,случайный,find,1,0.0003637000
BST,случайный,delete,1,0.0001893000
BST,случайный,insert,2,0.0364385000
BST,случайный,find,2,0.0003284000
BST,случайный,delete,2,0.0002408000
BST,случайный,insert,3,0.0359604000
BST,случайный,find,3,0.0003705000
BST,случайный,delete,3,0.0001883000
BST,случайный,insert,4,0.0371920000
BST,случайный,find,4,0.0003347000
BST,случайный,delete,4,0.0001711000
BST,случайный,insert,5,0.0385580000
BST,случайный,find,5,0.0003628000
BST,случайный,delete,5,0.0001828000
BST,случайный,insert,среднее,0.0371466200
BST,случайный,find,среднее,0.0003520200
BST,случайный,delete,среднее,0.0001944600
LinkedList,отсортированный,insert,1,6.7166487000
LinkedList,отсортированный,find,1,0.0614362000
LinkedList,отсортированный,delete,1,0.0324487000
LinkedList,отсортированный,insert,2,6.8582294000
LinkedList,отсортированный,find,2,0.0588546000
LinkedList,отсортированный,delete,2,0.0332572000
LinkedList,отсортированный,insert,3,6.6991410000
LinkedList,отсортированный,find,3,0.0521304000
LinkedList,отсортированный,delete,3,0.0296734000
LinkedList,отсортированный,insert,4,6.7166336000
LinkedList,отсортированный,find,4,0.0521848000
LinkedList,отсортированный,delete,4,0.0286064000
LinkedList,отсортированный,insert,5,6.6510829000
LinkedList,отсортированный,find,5,0.0547075000
LinkedList,отсортированный,delete,5,0.0285625000
LinkedList,отсортированный,insert,среднее,6.7283471200
LinkedList,отсортированный,find,среднее,0.0558627000
LinkedList,отсортированный,delete,среднее,0.0305096400
HashTable,отсортированный,insert,1,0.3645209000
HashTable,отсортированный,find,1,0.0032770000
HashTable,отсортированный,delete,1,0.0018631000
HashTable,отсортированный,insert,2,0.3579217000
HashTable,отсортированный,find,2,0.0032143000
HashTable,отсортированный,delete,2,0.0016427000
HashTable,отсортированный,insert,3,0.3684879000
HashTable,отсортированный,find,3,0.0026412000
HashTable,отсортированный,delete,3,0.0014870000
HashTable,отсортированный,insert,4,0.3873619000
HashTable,отсортированный,find,4,0.0028024000
HashTable,отсортированный,delete,4,0.0015786000
HashTable,отсортированный,insert,5,0.3642992000
HashTable,отсортированный,find,5,0.0031264000
HashTable,отсортированный,delete,5,0.0015886000
HashTable,отсортированный,insert,среднее,0.3685183200
HashTable,отсортированный,find,среднее,0.0030122600
HashTable,отсортированный,delete,среднее,0.0016320000
BST,отсортированный,insert,1,10.5552378000
BST,отсортированный,find,1,0.1016856000
BST,отсортированный,delete,1,0.0422728000
BST,отсортированный,insert,2,10.3035871000
BST,отсортированный,find,2,0.1008642000
BST,отсортированный,delete,2,0.0450330000
BST,отсортированный,insert,3,10.6304005000
BST,отсортированный,find,3,0.1073470000
BST,отсортированный,delete,3,0.0816121000
BST,отсортированный,insert,4,10.3183078000
BST,отсортированный,find,4,0.1005074000
BST,отсортированный,delete,4,0.0422195000
BST,отсортированный,insert,5,10.3131368000
BST,отсортированный,find,5,0.1001096000
BST,отсортированный,delete,5,0.0416660000
BST,отсортированный,insert,среднее,10.4241340000
BST,отсортированный,find,среднее,0.1021027600
BST,отсортированный,delete,среднее,0.0505606800
1 Структура Режим Операция Замер Время (сек)
2 LinkedList случайный insert 1 6.8132659000
3 LinkedList случайный find 1 0.0553455000
4 LinkedList случайный delete 1 0.0304272000
5 LinkedList случайный insert 2 6.8263299000
6 LinkedList случайный find 2 0.0562645000
7 LinkedList случайный delete 2 0.0303858000
8 LinkedList случайный insert 3 6.8117682000
9 LinkedList случайный find 3 0.0567219000
10 LinkedList случайный delete 3 0.0302671000
11 LinkedList случайный insert 4 7.0393228000
12 LinkedList случайный find 4 0.0544359000
13 LinkedList случайный delete 4 0.0313359000
14 LinkedList случайный insert 5 7.0633509000
15 LinkedList случайный find 5 0.0552176000
16 LinkedList случайный delete 5 0.0318664000
17 LinkedList случайный insert среднее 6.9108075400
18 LinkedList случайный find среднее 0.0555970800
19 LinkedList случайный delete среднее 0.0308564800
20 HashTable случайный insert 1 0.3898307000
21 HashTable случайный find 1 0.0022226000
22 HashTable случайный delete 1 0.0012723000
23 HashTable случайный insert 2 0.3844561000
24 HashTable случайный find 2 0.0024825000
25 HashTable случайный delete 2 0.0013425000
26 HashTable случайный insert 3 0.3740853000
27 HashTable случайный find 3 0.0026141000
28 HashTable случайный delete 3 0.0013710000
29 HashTable случайный insert 4 0.3870099000
30 HashTable случайный find 4 0.0022063000
31 HashTable случайный delete 4 0.0015940000
32 HashTable случайный insert 5 0.3869087000
33 HashTable случайный find 5 0.0022110000
34 HashTable случайный delete 5 0.0012524000
35 HashTable случайный insert среднее 0.3844581400
36 HashTable случайный find среднее 0.0023473000
37 HashTable случайный delete среднее 0.0013664400
38 BST случайный insert 1 0.0375842000
39 BST случайный find 1 0.0003637000
40 BST случайный delete 1 0.0001893000
41 BST случайный insert 2 0.0364385000
42 BST случайный find 2 0.0003284000
43 BST случайный delete 2 0.0002408000
44 BST случайный insert 3 0.0359604000
45 BST случайный find 3 0.0003705000
46 BST случайный delete 3 0.0001883000
47 BST случайный insert 4 0.0371920000
48 BST случайный find 4 0.0003347000
49 BST случайный delete 4 0.0001711000
50 BST случайный insert 5 0.0385580000
51 BST случайный find 5 0.0003628000
52 BST случайный delete 5 0.0001828000
53 BST случайный insert среднее 0.0371466200
54 BST случайный find среднее 0.0003520200
55 BST случайный delete среднее 0.0001944600
56 LinkedList отсортированный insert 1 6.7166487000
57 LinkedList отсортированный find 1 0.0614362000
58 LinkedList отсортированный delete 1 0.0324487000
59 LinkedList отсортированный insert 2 6.8582294000
60 LinkedList отсортированный find 2 0.0588546000
61 LinkedList отсортированный delete 2 0.0332572000
62 LinkedList отсортированный insert 3 6.6991410000
63 LinkedList отсортированный find 3 0.0521304000
64 LinkedList отсортированный delete 3 0.0296734000
65 LinkedList отсортированный insert 4 6.7166336000
66 LinkedList отсортированный find 4 0.0521848000
67 LinkedList отсортированный delete 4 0.0286064000
68 LinkedList отсортированный insert 5 6.6510829000
69 LinkedList отсортированный find 5 0.0547075000
70 LinkedList отсортированный delete 5 0.0285625000
71 LinkedList отсортированный insert среднее 6.7283471200
72 LinkedList отсортированный find среднее 0.0558627000
73 LinkedList отсортированный delete среднее 0.0305096400
74 HashTable отсортированный insert 1 0.3645209000
75 HashTable отсортированный find 1 0.0032770000
76 HashTable отсортированный delete 1 0.0018631000
77 HashTable отсортированный insert 2 0.3579217000
78 HashTable отсортированный find 2 0.0032143000
79 HashTable отсортированный delete 2 0.0016427000
80 HashTable отсортированный insert 3 0.3684879000
81 HashTable отсортированный find 3 0.0026412000
82 HashTable отсортированный delete 3 0.0014870000
83 HashTable отсортированный insert 4 0.3873619000
84 HashTable отсортированный find 4 0.0028024000
85 HashTable отсортированный delete 4 0.0015786000
86 HashTable отсортированный insert 5 0.3642992000
87 HashTable отсортированный find 5 0.0031264000
88 HashTable отсортированный delete 5 0.0015886000
89 HashTable отсортированный insert среднее 0.3685183200
90 HashTable отсортированный find среднее 0.0030122600
91 HashTable отсортированный delete среднее 0.0016320000
92 BST отсортированный insert 1 10.5552378000
93 BST отсортированный find 1 0.1016856000
94 BST отсортированный delete 1 0.0422728000
95 BST отсортированный insert 2 10.3035871000
96 BST отсортированный find 2 0.1008642000
97 BST отсортированный delete 2 0.0450330000
98 BST отсортированный insert 3 10.6304005000
99 BST отсортированный find 3 0.1073470000
100 BST отсортированный delete 3 0.0816121000
101 BST отсортированный insert 4 10.3183078000
102 BST отсортированный find 4 0.1005074000
103 BST отсортированный delete 4 0.0422195000
104 BST отсортированный insert 5 10.3131368000
105 BST отсортированный find 5 0.1001096000
106 BST отсортированный delete 5 0.0416660000
107 BST отсортированный insert среднее 10.4241340000
108 BST отсортированный find среднее 0.1021027600
109 BST отсортированный delete среднее 0.0505606800

29
petryaninyas/utils.py Normal file
View File

@ -0,0 +1,29 @@
import random
from typing import List, Tuple
Record = Tuple[str, str]
NAME_POOL = (
"User_Alex", "User_Bob", "User_Cat", "User_Dan", "User_Eva",
"User_Fox", "User_Geo", "User_Hen", "User_Ira", "User_Leo"
)
def generate_records(n: int, repeat_names: bool = False, seed: int = 42) -> List[Record]:
"""Генерирует n кортежей (имя, телефон)."""
rng = random.Random(seed)
if repeat_names:
return [
(rng.choice(NAME_POOL), str(rng.randint(10**9, 10**10 - 1)))
for _ in range(n)
]
return [
(f"User_{i:05d}", str(10**9 + i))
for i in range(n)
]
def prepare_records_variants(records: List[Record], seed: int = 42) -> Tuple[List[Record], List[Record]]:
"""Возвращает пару: (перемешанный список, отсортированный по имени список)."""
shuffled = records.copy()
random.Random(seed).shuffle(shuffled)
sorted_records = sorted(records, key=lambda rec: rec[0])
return shuffled, sorted_records

0
pogodinda/427.md.txt Normal file
View File

1
pomelovsd/427 Normal file
View File

@ -0,0 +1 @@
427

BIN
raskatovia/429.md Normal file

Binary file not shown.

0
romanovpv/427.md Normal file
View File

0
semyanovra/426.md Normal file
View File

0
shahovaa/429.md Normal file
View File

0
shalovsa/429.txt Normal file
View File

0
shekurovaa/429.md Normal file
View File

1
skorohodovsa/427 Normal file
View File

@ -0,0 +1 @@
427

4
skorohodovsa/main.py Normal file
View File

@ -0,0 +1,4 @@
from math import sin
for i in range(10000):
print(" " * round(50 * (1 + sin(i/100))), "Hello World!")

0
smirnovad/429.md Normal file
View File

6
sobininaas/429.rtf Normal file
View File

@ -0,0 +1,6 @@
{\rtf1\ansi\ansicpg1251\cocoartf2761
\cocoatextscaling0\cocoaplatform0{\fonttbl}
{\colortbl;\red255\green255\blue255;}
{\*\expandedcolortbl;;}
\paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0
}

1
soldatkinao/428б.md Normal file
View File

@ -0,0 +1 @@
<EFBFBD>¥¦¨¬ ¢כ¢®₪  ×®¬ ­₪ ­  ם×א ­ (ECHO) ¢×«מח¥­.

0
sorokinfi/427.md Normal file
View File

0
stepinim/428.md Normal file
View File

1
stepushovgs/427 Normal file
View File

@ -0,0 +1 @@
427

0
svetlakovkyu/426 Normal file
View File

1
talantsevgi/427.txt Normal file
View File

@ -0,0 +1 @@
732489234

1
tseremonnikovaaa/427 Normal file
View File

@ -0,0 +1 @@
427

1
volkovim/428b.md Normal file
View File

@ -0,0 +1 @@
428b

1
zaharoves/429.md Normal file
View File

@ -0,0 +1 @@

0
zverevem/429.txt Normal file
View File