This commit is contained in:
sawa2caxap 2026-05-23 18:45:47 +03:00
parent 1a041a4dac
commit 155b75f45d
23 changed files with 978 additions and 0 deletions

3
BolonkinNM/Task 1/.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (ds_project_archive)" project-jdk-type="Python SDK" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/ds_project_archive.iml" filepath="$PROJECT_DIR$/.idea/ds_project_archive.iml" />
</modules>
</component>
</project>

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
```

View File

@ -0,0 +1,82 @@
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
col_names = ['T(C)', 'Td(C)', 'HR%', 'ff(kmh)', 'Gust(kmh)', 'P_0(HPa)', 'P_sea(HPa)']
data = pd.read_csv(
"data_meteo.txt",
sep=r'\s+',
skiprows=1,
usecols=[2, 3, 4, 5, 6, 7, 8],
names=col_names,
engine='python'
)
print("загружено записей (строк):", len(data))
data = data.apply(pd.to_numeric, errors='coerce')
n_before = len(data)
data = data.dropna(subset=col_names)
n_after = len(data)
print(f"после приведения к числам и dropna: {n_after} строк (удалено {n_before - n_after})")
def correlation(vec1, vec2, center=False):
v1 = np.asarray(vec1, dtype=float)
v2 = np.asarray(vec2, dtype=float)
if center:
v1 = v1 - np.mean(v1)
v2 = v2 - np.mean(v2)
dot_product = np.sum(v1 * v2)
norm1 = np.sqrt(np.sum(v1 ** 2))
norm2 = np.sqrt(np.sum(v2 ** 2))
if norm1 == 0 or norm2 == 0:
return np.nan
return dot_product / (norm1 * norm2)
n = len(col_names)
raw_matrix = np.zeros((n, n))
center_matrix = np.zeros((n, n))
for i in range(n):
for j in range(n):
r_raw = correlation(data.iloc[:, i], data.iloc[:, j], center=False)
r_center = correlation(data.iloc[:, i], data.iloc[:, j], center=True)
raw_matrix[i, j] = np.round(r_raw, 3) if not np.isnan(r_raw) else np.nan
center_matrix[i, j] = np.round(r_center, 3) if not np.isnan(r_center) else np.nan
df_raw = pd.DataFrame(raw_matrix, index=col_names, columns=col_names)
df_center = pd.DataFrame(center_matrix, index=col_names, columns=col_names)
print("\nкорреляция (raw):")
print(df_raw.to_string())
print("\nкорреляция (centered):")
print(df_center.to_string())
print("\nразница (centered - raw):")
print((df_center - df_raw).round(3).to_string())
plt.figure(figsize=(14, 8))
for col in col_names:
centered_values = data[col] - data[col].mean()
plt.plot(centered_values.values, label=col, marker='.', linewidth=1, markersize=4)
plt.axhline(0, linestyle='--')
plt.title("центрированные метеоданные")
plt.xlabel("номер измерения")
plt.ylabel("отклонение от среднего")
plt.legend()
plt.grid()
plt.tight_layout()
plt.savefig("meteo_analysis.png", dpi=150)
plt.show()

118
BolonkinNM/Task 1/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: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 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

View File

@ -0,0 +1,101 @@
# Отчёт по заданию 1 — структуры данных
## Цель работы
Реализовать три структуры данных с нуля в процедурном стиле:
- связный список;
- хеш-таблицу;
- двоичное дерево поиска.
Также были выполнены измерения времени для операций `insert`, `find`, `delete` и построены графики по результатам эксперимента.
## Реализованные структуры
### Связный список
Узел хранится как словарь:
```python
{"name": "Имя", "phone": "123", "next": None}
```
### Хеш-таблица
Хранится как список бакетов фиксированной длины, где каждый бакет — голова связного списка или `None`.
### Двоичное дерево поиска
Узел хранится как словарь:
```python
{"name": "Имя", "phone": "123", "left": None, "right": None}
```
Для BST использованы итеративные операции, чтобы корректно работать и на отсортированных данных.
## Методика эксперимента
- Количество записей: `N = 10000`
- Режимы данных:
- случайный порядок;
- отсортированный порядок.
- Каждое измерение повторялось **5 раз**.
- В CSV сохранены:
- все отдельные замеры;
- среднее время для каждой операции, структуры и режима.
Операции:
- вставка всех записей;
- поиск 100 существующих и 10 отсутствующих имён;
- удаление 50 случайных имён.
## Графики
![insert](data/insert.png)
![find](data/find.png)
![delete](data/delete.png)
## Средние результаты
| Режим | Операция | LinkedList | HashTable | BST | Лучший результат |
|---|---:|---:|---:|---:|---|
| случайный | insert | 3.949566 | 0.208964 | 0.018028 | BST |
| случайный | find | 0.033693 | 0.001534 | 0.000190 | BST |
| случайный | delete | 0.016076 | 0.000727 | 0.000102 | BST |
| отсортированный | insert | 2.998378 | 0.208710 | 4.163651 | HashTable |
| отсортированный | find | 0.023923 | 0.001819 | 0.037987 | HashTable |
| отсортированный | delete | 0.011258 | 0.000863 | 0.019363 | HashTable |
## Анализ результатов
### Влияние порядка входных данных на BST
На случайных данных BST работает значительно быстрее, чем на отсортированных. Это связано с тем, что при случайной вставке дерево остаётся ближе к сбалансированному состоянию.
На отсортированных данных дерево вырождается в цепочку, поэтому вставка становится медленной, а поиск и удаление тоже деградируют по времени.
### Почему хеш-таблица почти не чувствительна к порядку
Хеш-таблица распределяет элементы по бакетам через хеш-функцию, поэтому сам порядок входа почти не влияет на скорость. Влияние может появляться только из-за коллизий, но в целом поведение остаётся близким к постоянному времени.
### Почему связный список всегда медленен при поиске
Поиск в связном списке выполняется последовательным просмотром элементов. Поэтому при большом количестве записей приходится проходить много узлов, и операция остаётся линейной по времени.
### Как удаление работает в каждой структуре
- В связном списке нужно сначала найти нужный узел, затем переназначить ссылку.
- В хеш-таблице сначала выбирается бакет, затем удаление выполняется внутри короткой цепочки.
- В BST удаление зависит от числа потомков: если потомок один или ноль, операция простая; если два — нужно найти преемника.
## Вывод
Для частых вставок и особенно частого поиска в реальной задаче чаще всего лучше подходит **хеш-таблица**.
Если важно получать данные в отсортированном виде, удобнее использовать **BST**.
**Связный список** подходит для маленьких объёмов данных или очень простых сценариев, но при большом числе записей он проигрывает по скорости поиска.

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
BolonkinNM/Task 1/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,60 @@
from __future__ import annotations
import csv
from collections import defaultdict
from pathlib import Path
import matplotlib.pyplot as plt
def load_average_results(csv_file: str):
results = []
with open(csv_file, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
if row["Замер"] != "среднее":
continue
results.append({
"structure": row["Структура"],
"mode": row["Режим"],
"operation": row["Операция"],
"time": float(row["Время (сек)"]),
})
return results
def build_graphs(results, output_dir: str = "docs/data"):
output = Path(output_dir)
output.mkdir(parents=True, exist_ok=True)
grouped = defaultdict(list)
for row in results:
grouped[row["operation"]].append(row)
for operation in ("insert", "find", "delete"):
rows = grouped[operation]
labels = [f"{r['structure']}\n{r['mode']}" for r in rows]
values = [r["time"] for r in rows]
plt.figure(figsize=(11, 6))
plt.bar(labels, values)
plt.title(f"{operation.capitalize()} comparison")
plt.xlabel("Structure / data order")
plt.ylabel("Time, seconds")
plt.xticks(rotation=20)
plt.tight_layout()
filename = output / f"{operation}.png"
plt.savefig(filename, dpi=160)
plt.close()
print(f"Saved {filename}")
def main():
results = load_average_results("results.csv")
build_graphs(results)
if __name__ == "__main__":
main()

View File

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

View File

@ -0,0 +1,109 @@
Структура,Режим,Операция,Замер,Время (сек)
LinkedList,случайный,insert,1,2.4210275000
LinkedList,случайный,find,1,0.0214394000
LinkedList,случайный,delete,1,0.0108667000
LinkedList,случайный,insert,2,2.4208055000
LinkedList,случайный,find,2,0.0216110000
LinkedList,случайный,delete,2,0.0106216000
LinkedList,случайный,insert,3,2.4210881000
LinkedList,случайный,find,3,0.0216503000
LinkedList,случайный,delete,3,0.0106497000
LinkedList,случайный,insert,4,2.4530798000
LinkedList,случайный,find,4,0.0222764000
LinkedList,случайный,delete,4,0.0108350000
LinkedList,случайный,insert,5,2.4567773000
LinkedList,случайный,find,5,0.0219400000
LinkedList,случайный,delete,5,0.0108697000
LinkedList,случайный,insert,среднее,2.4345556400
LinkedList,случайный,find,среднее,0.0217834200
LinkedList,случайный,delete,среднее,0.0107685400
HashTable,случайный,insert,1,0.1621210000
HashTable,случайный,find,1,0.0011201000
HashTable,случайный,delete,1,0.0005854000
HashTable,случайный,insert,2,0.1732676000
HashTable,случайный,find,2,0.0011247000
HashTable,случайный,delete,2,0.0005818000
HashTable,случайный,insert,3,0.1638609000
HashTable,случайный,find,3,0.0011355000
HashTable,случайный,delete,3,0.0005814000
HashTable,случайный,insert,4,0.1642886000
HashTable,случайный,find,4,0.0011268000
HashTable,случайный,delete,4,0.0005785000
HashTable,случайный,insert,5,0.1640916000
HashTable,случайный,find,5,0.0011287000
HashTable,случайный,delete,5,0.0005787000
HashTable,случайный,insert,среднее,0.1655259400
HashTable,случайный,find,среднее,0.0011271600
HashTable,случайный,delete,среднее,0.0005811600
BST,случайный,insert,1,0.0153754000
BST,случайный,find,1,0.0001491000
BST,случайный,delete,1,0.0000786000
BST,случайный,insert,2,0.0155821000
BST,случайный,find,2,0.0001453000
BST,случайный,delete,2,0.0000724000
BST,случайный,insert,3,0.0151360000
BST,случайный,find,3,0.0001437000
BST,случайный,delete,3,0.0000741000
BST,случайный,insert,4,0.0153703000
BST,случайный,find,4,0.0001425000
BST,случайный,delete,4,0.0000715000
BST,случайный,insert,5,0.0153753000
BST,случайный,find,5,0.0001455000
BST,случайный,delete,5,0.0000723000
BST,случайный,insert,среднее,0.0153678200
BST,случайный,find,среднее,0.0001452200
BST,случайный,delete,среднее,0.0000737800
LinkedList,отсортированный,insert,1,2.5884851000
LinkedList,отсортированный,find,1,0.0227221000
LinkedList,отсортированный,delete,1,0.0111309000
LinkedList,отсортированный,insert,2,2.5095731000
LinkedList,отсортированный,find,2,0.0217208000
LinkedList,отсортированный,delete,2,0.0107773000
LinkedList,отсортированный,insert,3,2.5642096000
LinkedList,отсортированный,find,3,0.0228242000
LinkedList,отсортированный,delete,3,0.0115945000
LinkedList,отсортированный,insert,4,2.7163021000
LinkedList,отсортированный,find,4,0.0431456000
LinkedList,отсортированный,delete,4,0.0136020000
LinkedList,отсортированный,insert,5,2.6891794000
LinkedList,отсортированный,find,5,0.0217679000
LinkedList,отсортированный,delete,5,0.0106384000
LinkedList,отсортированный,insert,среднее,2.6135498600
LinkedList,отсортированный,find,среднее,0.0264361200
LinkedList,отсортированный,delete,среднее,0.0115486200
HashTable,отсортированный,insert,1,0.1524640000
HashTable,отсортированный,find,1,0.0014973000
HashTable,отсортированный,delete,1,0.0006991000
HashTable,отсортированный,insert,2,0.1537592000
HashTable,отсортированный,find,2,0.0012225000
HashTable,отсортированный,delete,2,0.0006561000
HashTable,отсортированный,insert,3,0.1555816000
HashTable,отсортированный,find,3,0.0012080000
HashTable,отсортированный,delete,3,0.0006472000
HashTable,отсортированный,insert,4,0.1546417000
HashTable,отсортированный,find,4,0.0015017000
HashTable,отсортированный,delete,4,0.0007512000
HashTable,отсортированный,insert,5,0.1531659000
HashTable,отсортированный,find,5,0.0012219000
HashTable,отсортированный,delete,5,0.0006493000
HashTable,отсортированный,insert,среднее,0.1539224800
HashTable,отсортированный,find,среднее,0.0013302800
HashTable,отсортированный,delete,среднее,0.0006805800
BST,отсортированный,insert,1,4.5025059000
BST,отсортированный,find,1,0.0387267000
BST,отсортированный,delete,1,0.0162161000
BST,отсортированный,insert,2,4.6704081000
BST,отсортированный,find,2,0.0435012000
BST,отсортированный,delete,2,0.0203211000
BST,отсортированный,insert,3,6.2192950000
BST,отсортированный,find,3,0.0578654000
BST,отсортированный,delete,3,0.0327529000
BST,отсортированный,insert,4,4.7844525000
BST,отсортированный,find,4,0.0380228000
BST,отсортированный,delete,4,0.0159740000
BST,отсортированный,insert,5,4.4861403000
BST,отсортированный,find,5,0.0382484000
BST,отсортированный,delete,5,0.0159402000
BST,отсортированный,insert,среднее,4.9325603600
BST,отсортированный,find,среднее,0.0432729000
BST,отсортированный,delete,среднее,0.0202408600
1 Структура Режим Операция Замер Время (сек)
2 LinkedList случайный insert 1 2.4210275000
3 LinkedList случайный find 1 0.0214394000
4 LinkedList случайный delete 1 0.0108667000
5 LinkedList случайный insert 2 2.4208055000
6 LinkedList случайный find 2 0.0216110000
7 LinkedList случайный delete 2 0.0106216000
8 LinkedList случайный insert 3 2.4210881000
9 LinkedList случайный find 3 0.0216503000
10 LinkedList случайный delete 3 0.0106497000
11 LinkedList случайный insert 4 2.4530798000
12 LinkedList случайный find 4 0.0222764000
13 LinkedList случайный delete 4 0.0108350000
14 LinkedList случайный insert 5 2.4567773000
15 LinkedList случайный find 5 0.0219400000
16 LinkedList случайный delete 5 0.0108697000
17 LinkedList случайный insert среднее 2.4345556400
18 LinkedList случайный find среднее 0.0217834200
19 LinkedList случайный delete среднее 0.0107685400
20 HashTable случайный insert 1 0.1621210000
21 HashTable случайный find 1 0.0011201000
22 HashTable случайный delete 1 0.0005854000
23 HashTable случайный insert 2 0.1732676000
24 HashTable случайный find 2 0.0011247000
25 HashTable случайный delete 2 0.0005818000
26 HashTable случайный insert 3 0.1638609000
27 HashTable случайный find 3 0.0011355000
28 HashTable случайный delete 3 0.0005814000
29 HashTable случайный insert 4 0.1642886000
30 HashTable случайный find 4 0.0011268000
31 HashTable случайный delete 4 0.0005785000
32 HashTable случайный insert 5 0.1640916000
33 HashTable случайный find 5 0.0011287000
34 HashTable случайный delete 5 0.0005787000
35 HashTable случайный insert среднее 0.1655259400
36 HashTable случайный find среднее 0.0011271600
37 HashTable случайный delete среднее 0.0005811600
38 BST случайный insert 1 0.0153754000
39 BST случайный find 1 0.0001491000
40 BST случайный delete 1 0.0000786000
41 BST случайный insert 2 0.0155821000
42 BST случайный find 2 0.0001453000
43 BST случайный delete 2 0.0000724000
44 BST случайный insert 3 0.0151360000
45 BST случайный find 3 0.0001437000
46 BST случайный delete 3 0.0000741000
47 BST случайный insert 4 0.0153703000
48 BST случайный find 4 0.0001425000
49 BST случайный delete 4 0.0000715000
50 BST случайный insert 5 0.0153753000
51 BST случайный find 5 0.0001455000
52 BST случайный delete 5 0.0000723000
53 BST случайный insert среднее 0.0153678200
54 BST случайный find среднее 0.0001452200
55 BST случайный delete среднее 0.0000737800
56 LinkedList отсортированный insert 1 2.5884851000
57 LinkedList отсортированный find 1 0.0227221000
58 LinkedList отсортированный delete 1 0.0111309000
59 LinkedList отсортированный insert 2 2.5095731000
60 LinkedList отсортированный find 2 0.0217208000
61 LinkedList отсортированный delete 2 0.0107773000
62 LinkedList отсортированный insert 3 2.5642096000
63 LinkedList отсортированный find 3 0.0228242000
64 LinkedList отсортированный delete 3 0.0115945000
65 LinkedList отсортированный insert 4 2.7163021000
66 LinkedList отсортированный find 4 0.0431456000
67 LinkedList отсортированный delete 4 0.0136020000
68 LinkedList отсортированный insert 5 2.6891794000
69 LinkedList отсортированный find 5 0.0217679000
70 LinkedList отсортированный delete 5 0.0106384000
71 LinkedList отсортированный insert среднее 2.6135498600
72 LinkedList отсортированный find среднее 0.0264361200
73 LinkedList отсортированный delete среднее 0.0115486200
74 HashTable отсортированный insert 1 0.1524640000
75 HashTable отсортированный find 1 0.0014973000
76 HashTable отсортированный delete 1 0.0006991000
77 HashTable отсортированный insert 2 0.1537592000
78 HashTable отсортированный find 2 0.0012225000
79 HashTable отсортированный delete 2 0.0006561000
80 HashTable отсортированный insert 3 0.1555816000
81 HashTable отсортированный find 3 0.0012080000
82 HashTable отсортированный delete 3 0.0006472000
83 HashTable отсортированный insert 4 0.1546417000
84 HashTable отсортированный find 4 0.0015017000
85 HashTable отсортированный delete 4 0.0007512000
86 HashTable отсортированный insert 5 0.1531659000
87 HashTable отсортированный find 5 0.0012219000
88 HashTable отсортированный delete 5 0.0006493000
89 HashTable отсортированный insert среднее 0.1539224800
90 HashTable отсортированный find среднее 0.0013302800
91 HashTable отсортированный delete среднее 0.0006805800
92 BST отсортированный insert 1 4.5025059000
93 BST отсортированный find 1 0.0387267000
94 BST отсортированный delete 1 0.0162161000
95 BST отсортированный insert 2 4.6704081000
96 BST отсортированный find 2 0.0435012000
97 BST отсортированный delete 2 0.0203211000
98 BST отсортированный insert 3 6.2192950000
99 BST отсортированный find 3 0.0578654000
100 BST отсортированный delete 3 0.0327529000
101 BST отсортированный insert 4 4.7844525000
102 BST отсортированный find 4 0.0380228000
103 BST отсортированный delete 4 0.0159740000
104 BST отсортированный insert 5 4.4861403000
105 BST отсортированный find 5 0.0382484000
106 BST отсортированный delete 5 0.0159402000
107 BST отсортированный insert среднее 4.9325603600
108 BST отсортированный find среднее 0.0432729000
109 BST отсортированный delete среднее 0.0202408600

View File

@ -0,0 +1,35 @@
import random
from typing import List, Tuple
Record = Tuple[str, str]
def generate_records(n: int, repeat_names: bool = False, seed: int = 42) -> List[Record]:
rng = random.Random(seed)
records: List[Record] = []
if repeat_names:
name_pool = [
"User_Alex", "User_Bob", "User_Cat", "User_Dan", "User_Eva",
"User_Fox", "User_Geo", "User_Hen", "User_Ira", "User_Leo",
]
for _ in range(n):
name = rng.choice(name_pool)
phone = f"{rng.randint(1000000000, 9999999999)}"
records.append((name, phone))
else:
for i in range(n):
name = f"User_{i:05d}"
phone = f"{1000000000 + i}"
records.append((name, phone))
return records
def prepare_records_variants(records: List[Record], seed: int = 42):
rng = random.Random(seed)
records_shuffled = list(records)
rng.shuffle(records_shuffled)
records_sorted = sorted(records, key=lambda x: x[0])
return records_shuffled, records_sorted

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.