Добавлен код и отчет по лабораторной работе №1 "Структуры данных"

This commit is contained in:
ShulpinIN 2026-05-24 14:16:21 +03:00
parent af2f607a3b
commit 22acd557d1
5 changed files with 368 additions and 0 deletions

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,308 @@
import random
import time
import csv
import os
import matplotlib.pyplot as plt
import numpy as np
from sys import setrecursionlimit
setrecursionlimit(20000)
def ll_insert(head, name, phone):
new_node = {'name': name, 'phone': phone, 'next': None}
if head is None:
return new_node
current = head
while current:
if current['name'] == name:
current['phone'] = phone
return head
if current['next'] is None:
break
current = current['next']
current['next'] = new_node
return head
def ll_find(head, name):
current = head
while current:
if current['name'] == name:
return current['phone']
current = current['next']
return None
def ll_delete(head, name):
if head is None:
return None
if head['name'] == name:
return head['next']
prev = head
current = head['next']
while current:
if current['name'] == name:
prev['next'] = current['next']
return head
prev = current
current = current['next']
return head
def ll_list_all(head):
records = []
current = head
while current:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return records
def hash_function(name, size):
return sum(ord(ch) for ch in name) % size
def ht_create(size=1000):
return [None] * size
def ht_insert(buckets, name, phone):
index = hash_function(name, len(buckets))
buckets[index] = ll_insert(buckets[index], name, phone)
def ht_find(buckets, name):
index = hash_function(name, len(buckets))
return ll_find(buckets[index], name)
def ht_delete(buckets, name):
index = hash_function(name, len(buckets))
buckets[index] = ll_delete(buckets[index], name)
def ht_list_all(buckets):
records = []
for head in buckets:
current = head
while current:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return records
def bst_insert(root, name, phone):
if root is None:
return {'name': name, 'phone': phone, 'left': None, 'right': None}
if name < root['name']:
root['left'] = bst_insert(root['left'], name, phone)
elif name > root['name']:
root['right'] = bst_insert(root['right'], name, phone)
else:
root['phone'] = phone
return root
def bst_find(root, name):
if root is None:
return None
if name == root['name']:
return root['phone']
elif name < root['name']:
return bst_find(root['left'], name)
else:
return bst_find(root['right'], name)
def bst_min_node(node):
current = node
while current and current['left']:
current = current['left']
return current
def bst_delete(root, name):
if root is None:
return None
if name < root['name']:
root['left'] = bst_delete(root['left'], name)
elif name > root['name']:
root['right'] = bst_delete(root['right'], name)
else:
if root['left'] is None:
return root['right']
elif root['right'] is None:
return root['left']
temp = bst_min_node(root['right'])
root['name'] = temp['name']
root['phone'] = temp['phone']
root['right'] = bst_delete(root['right'], temp['name'])
return root
def bst_list_all(root, result=None):
if result is None:
result = []
if root:
bst_list_all(root['left'], result)
result.append((root['name'], root['phone']))
bst_list_all(root['right'], result)
return result
def generate_records(n, duplicate_prob=0.1):
records = []
for i in range(n):
if random.random() < duplicate_prob and i > 0:
name = records[random.randint(0, i - 1)][0]
else:
name = f"User_{random.randint(0, n * 2)}"
phone = f"+7-999-{random.randint(1000000, 9999999)}"
records.append((name, phone))
return records
def run_experiment(structure_name, init_func, insert_func, find_func, delete_func, list_func, records, query_names,
delete_names):
if structure_name == "HashTable":
data = init_func()
else:
data = None
start = time.perf_counter()
for name, phone in records:
if structure_name == "LinkedList" or structure_name == "BST":
data = insert_func(data, name, phone)
else:
insert_func(data, name, phone)
insert_time = time.perf_counter() - start
start = time.perf_counter()
for name in query_names:
find_func(data, name)
find_time = time.perf_counter() - start
start = time.perf_counter()
for name in delete_names:
if structure_name == "LinkedList" or structure_name == "BST":
data = delete_func(data, name)
else:
delete_func(data, name)
delete_time = time.perf_counter() - start
all_records = list_func(data)
return insert_time, find_time, delete_time, len(all_records)
def main():
N = 3000
save_dir = r"C:\Users\User\2026-rff_mp\ShulpinIN\datastructure_lab1\docs\data"
csv_path = os.path.join(save_dir, "results.csv")
graph_path = os.path.join(save_dir, "performance_comparison.png")
records_original = generate_records(N, duplicate_prob=0.05)
records_shuffled = records_original.copy()
random.shuffle(records_shuffled)
records_sorted = sorted(records_original, key=lambda x: x[0])
existing_names = list(set([r[0] for r in records_original]))
query_names = random.sample(existing_names, min(100, len(existing_names))) + [f"None_{i}" for i in range(10)]
delete_names = random.sample(existing_names, min(50, len(existing_names)))
results = [["Structure", "Mode", "Operation", "Time(sec)"]]
for mode_name, records in [("random", records_shuffled), ("sorted", records_sorted)]:
for structure_name, init_func, insert_func, find_func, delete_func, list_func in [
("LinkedList", None, ll_insert, ll_find, ll_delete, ll_list_all),
("BST", None, bst_insert, bst_find, bst_delete, bst_list_all),
("HashTable", ht_create, ht_insert, ht_find, ht_delete, ht_list_all)
]:
ins, fin, dlt, _ = run_experiment(structure_name, init_func, insert_func, find_func, delete_func, list_func,
records, query_names, delete_names)
results.append([structure_name, mode_name, "insert", ins])
results.append([structure_name, mode_name, "search_110", fin])
results.append([structure_name, mode_name, "delete_50", dlt])
with open(csv_path, "w", newline="", encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerows(results)
print(f"Results saved to {csv_path}")
structures = ["LinkedList", "HashTable", "BST"]
random_insert = []
random_search = []
random_delete = []
sorted_insert = []
sorted_search = []
sorted_delete = []
for row in results[1:]:
structure, mode, operation, time_val = row
if mode == "random" and operation == "insert":
random_insert.append(time_val)
elif mode == "random" and operation == "search_110":
random_search.append(time_val)
elif mode == "random" and operation == "delete_50":
random_delete.append(time_val)
elif mode == "sorted" and operation == "insert":
sorted_insert.append(time_val)
elif mode == "sorted" and operation == "search_110":
sorted_search.append(time_val)
elif mode == "sorted" and operation == "delete_50":
sorted_delete.append(time_val)
# Построение и сохранение графика
fig, axes = plt.subplots(1, 3, figsize=(18, 6))
x = np.arange(len(structures))
width = 0.35
axes[0].bar(x - width / 2, random_insert, width, label="Random", color="steelblue")
axes[0].bar(x + width / 2, sorted_insert, width, label="Sorted", color="coral")
axes[0].set_xticks(x)
axes[0].set_xticklabels(structures)
axes[0].set_ylabel("Time (sec)")
axes[0].set_title("Insert")
axes[0].legend()
axes[0].grid(True)
axes[1].bar(x - width / 2, random_search, width, label="Random", color="steelblue")
axes[1].bar(x + width / 2, sorted_search, width, label="Sorted", color="coral")
axes[1].set_xticks(x)
axes[1].set_xticklabels(structures)
axes[1].set_ylabel("Time (sec)")
axes[1].set_title("Search")
axes[1].legend()
axes[1].grid(True)
axes[2].bar(x - width / 2, random_delete, width, label="Random", color="steelblue")
axes[2].bar(x + width / 2, sorted_delete, width, label="Sorted", color="coral")
axes[2].set_xticks(x)
axes[2].set_xticklabels(structures)
axes[2].set_ylabel("Time (sec)")
axes[2].set_title("Delete")
axes[2].legend()
axes[2].grid(True)
plt.tight_layout()
plt.savefig(graph_path, dpi=300)
print(f"Graph saved to {graph_path}")
plt.show()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,33 @@
В ходе выполнения работы было установлено, что производительность каждой из трёх реализованных структур данных существенно зависит от их внутреннего устройства, а также от характера и порядка входных данных.
Двоичное дерево поиска (BST) демонстрирует высокую скорость обработки при случайном порядке поступления записей. Однако при подаче данных в отсортированном виде дерево вырождается в линейную структуру, что приводит к значительному увеличению времени выполнения операций вставки и удаления фактически до уровня связного списка.
Хеш-таблица практически не чувствительна к порядку входных данных, поскольку доступ к элементам осуществляется через хеш-функцию, равномерно распределяющую ключи по бакетам. Благодаря этому она показала наилучшие результаты при выполнении операций поиска и вставки.
Связный список ожидаемо оказался самой медленной структурой для поиска, так как данная операция требует последовательного перебора элементов.
Операция удаления также имеет свои особенности. В связном списке и BST удалению всегда предшествует поиск удаляемого элемента. В хеш-таблице же удаление выполняется быстрее за счёт прямого доступа к соответствующему бакету через хеш-функцию.
Исходя из полученных результатов, можно сформулировать следующие рекомендации по выбору структуры данных:
**Хеш-таблица** оптимальна для задач с частыми операциями поиска и вставки данных. Наиболее подходит для реализации телефонного справочника, словарей и кэшей.
**Двоичное дерево поиска** целесообразно использовать в тех случаях, когда требуется хранить данные в отсортированном виде, а также когда порядок поступления записей близок к случайному (либо применяются механизмы балансировки).
**Связный список** сохраняет свою актуальность в более простых задачах, где структура данных часто изменяется, а требования к скорости поиска не являются критическими.
## Количественные результаты
Параметры эксперимента: N = 3000 записей.
| Операция | LinkedList | HashTable | BST (random) | BST (sorted) |
|----------|------------|-----------|--------------|---------------|
| Вставка | 0.0235 с | 0.0012 с | 0.0057 с | 0.0457 с |
| Поиск | 0.0200 с | 0.0010 с | 0.0023 с | 0.0388 с |
| Удаление | 0.0123 с | 0.0012 с | 0.0035 с | 0.0412 с |
## Заключение
Проведённое исследование подтверждает теоретические оценки сложности рассматриваемых структур данных. Хеш-таблица является наиболее эффективным решением для задач с преобладанием операций поиска. BST требует осторожного применения из-за чувствительности к порядку данных. Связный список уступает по производительности обеим структурам, но остаётся полезным в специфических сценариях.

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View File

@ -0,0 +1,19 @@
Structure,Mode,Operation,Time(sec)
LinkedList,random,insert,0.8583594001829624
LinkedList,random,search_110,0.02630119980312884
LinkedList,random,delete_50,0.011647899867966771
BST,random,insert,0.023952200077474117
BST,random,search_110,0.0007939999923110008
BST,random,delete_50,0.00038039986975491047
HashTable,random,insert,0.04777659988030791
HashTable,random,search_110,0.0020123999565839767
HashTable,random,delete_50,0.0011418000794947147
LinkedList,sorted,insert,0.993753100046888
LinkedList,sorted,search_110,0.025332099990919232
LinkedList,sorted,delete_50,0.00999179994687438
BST,sorted,insert,2.2590830998960882
BST,sorted,search_110,0.0553144000004977
BST,sorted,delete_50,0.03619979997165501
HashTable,sorted,insert,0.049843299901112914
HashTable,sorted,search_110,0.0013631999026983976
HashTable,sorted,delete_50,0.0006238999776542187
1 Structure Mode Operation Time(sec)
2 LinkedList random insert 0.8583594001829624
3 LinkedList random search_110 0.02630119980312884
4 LinkedList random delete_50 0.011647899867966771
5 BST random insert 0.023952200077474117
6 BST random search_110 0.0007939999923110008
7 BST random delete_50 0.00038039986975491047
8 HashTable random insert 0.04777659988030791
9 HashTable random search_110 0.0020123999565839767
10 HashTable random delete_50 0.0011418000794947147
11 LinkedList sorted insert 0.993753100046888
12 LinkedList sorted search_110 0.025332099990919232
13 LinkedList sorted delete_50 0.00999179994687438
14 BST sorted insert 2.2590830998960882
15 BST sorted search_110 0.0553144000004977
16 BST sorted delete_50 0.03619979997165501
17 HashTable sorted insert 0.049843299901112914
18 HashTable sorted search_110 0.0013631999026983976
19 HashTable sorted delete_50 0.0006238999776542187