[1] Data structures lab

This commit is contained in:
Кузнецов Максим 2026-09-23 12:22:47 +03:00
parent 8124ef4551
commit 030469c8f9
8 changed files with 505 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,19 @@
structure,order,operation,run1,run2,run3,run4,run5,average
LinkedList,random,insert,3.000600399999712,3.022712899999533,2.9421689999999217,2.9075659000000087,3.0319512999994913,2.980999899999733
LinkedList,random,find,0.031094500000108383,0.02800200000001496,0.034349299999121286,0.029372199999670556,0.03242119999958959,0.031047839999700955
LinkedList,random,delete,0.017322699999567703,0.0368361000000732,0.04029200000059063,0.03775789999963308,0.03554420000000391,0.033550579999973705
HashTable,random,insert,0.011551699999472476,0.012756400000398571,0.011765299999751733,0.011679000000185624,0.011983400000644906,0.011947160000090662
HashTable,random,find,0.00012409999999363208,0.00011009999980160501,0.0001415999995515449,0.00010400000064691994,0.00010089999977935804,0.000116139999954612
HashTable,random,delete,6.38999999864609e-05,6.779999966965988e-05,6.0600000324484427e-05,6.070000017643906e-05,6.0600000324484427e-05,6.272000009630574e-05
BST,random,insert,0.014788199999202334,0.014159299999846553,0.013975800000480376,0.014118900000539725,0.013331299999663315,0.01407469999994646
BST,random,find,0.00013829999988956843,0.00011389999963284936,0.00011369999992894009,0.00011379999978089472,0.00011439999980211724,0.00011881999980687397
BST,random,delete,8.690000049682567e-05,6.450000000768341e-05,6.2199999774748e-05,6.209999992279336e-05,6.229999962670263e-05,6.759999996575061e-05
LinkedList,sorted,insert,2.4411346000006233,2.36463619999995,2.2797248999995645,2.2860746000005747,2.2526011999998445,2.3248343000001115
LinkedList,sorted,find,0.024703000000044995,0.02455259999987902,0.02468479999970441,0.02444869999999355,0.02606350000041857,0.02489052000000811
LinkedList,sorted,delete,0.012835599999561964,0.027673999999933585,0.027570299999752024,0.02708100000018021,0.02999909999925876,0.02503199999973731
HashTable,sorted,insert,0.011780100000578386,0.010850699999537028,0.010314100000869075,0.010621500000524975,0.011015500000212342,0.010916380000344362
HashTable,sorted,find,0.0001464000006308197,0.00017980000029638177,0.00016909999976633117,0.00012620000052265823,0.00023630000032426324,0.0001715600003080908
HashTable,sorted,delete,0.00016370000048482325,0.00018089999957737746,0.0001443999999537482,7.579999964946182e-05,6.469999971159268e-05,0.0001258999998754007
BST,sorted,insert,3.5400651999998445,3.5145174999997835,3.5583661999999094,3.5149656000003233,3.481246600000304,3.521832220000033
BST,sorted,find,0.03275260000009439,0.030442500000390282,0.02994349999971746,0.030269500000031258,0.030329999999594293,0.030747619999965538
BST,sorted,delete,0.012705400000413647,0.01333390000036161,0.013192000000344706,0.013699000000087835,0.013079800000014075,0.013202020000244374
1 structure order operation run1 run2 run3 run4 run5 average
2 LinkedList random insert 3.000600399999712 3.022712899999533 2.9421689999999217 2.9075659000000087 3.0319512999994913 2.980999899999733
3 LinkedList random find 0.031094500000108383 0.02800200000001496 0.034349299999121286 0.029372199999670556 0.03242119999958959 0.031047839999700955
4 LinkedList random delete 0.017322699999567703 0.0368361000000732 0.04029200000059063 0.03775789999963308 0.03554420000000391 0.033550579999973705
5 HashTable random insert 0.011551699999472476 0.012756400000398571 0.011765299999751733 0.011679000000185624 0.011983400000644906 0.011947160000090662
6 HashTable random find 0.00012409999999363208 0.00011009999980160501 0.0001415999995515449 0.00010400000064691994 0.00010089999977935804 0.000116139999954612
7 HashTable random delete 6.38999999864609e-05 6.779999966965988e-05 6.0600000324484427e-05 6.070000017643906e-05 6.0600000324484427e-05 6.272000009630574e-05
8 BST random insert 0.014788199999202334 0.014159299999846553 0.013975800000480376 0.014118900000539725 0.013331299999663315 0.01407469999994646
9 BST random find 0.00013829999988956843 0.00011389999963284936 0.00011369999992894009 0.00011379999978089472 0.00011439999980211724 0.00011881999980687397
10 BST random delete 8.690000049682567e-05 6.450000000768341e-05 6.2199999774748e-05 6.209999992279336e-05 6.229999962670263e-05 6.759999996575061e-05
11 LinkedList sorted insert 2.4411346000006233 2.36463619999995 2.2797248999995645 2.2860746000005747 2.2526011999998445 2.3248343000001115
12 LinkedList sorted find 0.024703000000044995 0.02455259999987902 0.02468479999970441 0.02444869999999355 0.02606350000041857 0.02489052000000811
13 LinkedList sorted delete 0.012835599999561964 0.027673999999933585 0.027570299999752024 0.02708100000018021 0.02999909999925876 0.02503199999973731
14 HashTable sorted insert 0.011780100000578386 0.010850699999537028 0.010314100000869075 0.010621500000524975 0.011015500000212342 0.010916380000344362
15 HashTable sorted find 0.0001464000006308197 0.00017980000029638177 0.00016909999976633117 0.00012620000052265823 0.00023630000032426324 0.0001715600003080908
16 HashTable sorted delete 0.00016370000048482325 0.00018089999957737746 0.0001443999999537482 7.579999964946182e-05 6.469999971159268e-05 0.0001258999998754007
17 BST sorted insert 3.5400651999998445 3.5145174999997835 3.5583661999999094 3.5149656000003233 3.481246600000304 3.521832220000033
18 BST sorted find 0.03275260000009439 0.030442500000390282 0.02994349999971746 0.030269500000031258 0.030329999999594293 0.030747619999965538
19 BST sorted delete 0.012705400000413647 0.01333390000036161 0.013192000000344706 0.013699000000087835 0.013079800000014075 0.013202020000244374

View File

@ -0,0 +1,34 @@
Лабораторная работа 1
Цель работы
Нужно было сделать три структуры данных и проверить как они работают на телефонном справочнике.
Ход работы
Сделал связный список хеш таблицу и двоичное дерево поиска. Для всех структур сделал добавление поиск удаление и вывод записей. Для проверки создал 10000 записей с именами User\_00000 и т.д. Потом проверил работу со случайным порядком и с отсортированным порядком. Каждый эксперимент повторял 5 раз.
Результаты
Результаты сохранились в results.csv. Также сделал графики для добавления поиска и удаления. По результатам видно что связный список медленно ищет записи потому что нужно идти по элементам. Хеш таблица работает примерно одинаково при разном порядке записей. У двоичного дерева порядок записей влияет намного сильнее. Если добавлять записи по порядку дерево становится похожим на обычный список и работает медленнее.
Вывод
В работе я сделал три структуры данных и проверил их работу. Самой удобной для телефонного справочника получилась хеш таблица. Связный список проще но поиск медленный. Двоичное дерево может работать быстро но сильно зависит от порядка добавления данных.

View File

@ -0,0 +1,185 @@
import random
import time
import csv
import os
from phonebook import *
N = 10000
REPEATS = 5
def generate_test_data():
records = [
(f"User_{i:05d}", f"+7900000{i:04d}")
for i in range(N)
]
records_shuffled = records.copy()
random.shuffle(records_shuffled)
records_sorted = records.copy()
return records_shuffled, records_sorted
def measure_experiment(insert_function, find_function, delete_function, records):
insert_times = []
find_times = []
delete_times = []
for _ in range(REPEATS):
structure = None
start = time.perf_counter()
for name, phone in records:
structure = insert_function(structure, name, phone)
insert_times.append(time.perf_counter() - start)
structure_for_find = structure
names = [name for name, phone in records]
search_names = random.sample(names, 100) + [
"NotFound_001",
"NotFound_002",
"NotFound_003",
"NotFound_004",
"NotFound_005",
"NotFound_006",
"NotFound_007",
"NotFound_008",
"NotFound_009",
"NotFound_010"
]
for _ in range(REPEATS):
start = time.perf_counter()
for name in search_names:
find_function(structure_for_find, name)
find_times.append(time.perf_counter() - start)
delete_names = random.sample(names, 50)
for _ in range(REPEATS):
structure = structure_for_find
start = time.perf_counter()
for name in delete_names:
structure = delete_function(structure, name)
delete_times.append(time.perf_counter() - start)
return insert_times, find_times, delete_times
def measure_hash(records):
insert_times = []
find_times = []
delete_times = []
names = [name for name, phone in records]
search_names = random.sample(names, 100) + [
f"NotFound_{i:03d}" for i in range(10)
]
delete_names = random.sample(names, 50)
for _ in range(REPEATS):
buckets = ht_create()
start = time.perf_counter()
for name, phone in records:
ht_insert(buckets, name, phone)
insert_times.append(time.perf_counter() - start)
structure_for_find = buckets
for _ in range(REPEATS):
start = time.perf_counter()
for name in search_names:
ht_find(structure_for_find, name)
find_times.append(time.perf_counter() - start)
for _ in range(REPEATS):
buckets = structure_for_find.copy()
start = time.perf_counter()
for name in delete_names:
ht_delete(buckets, name)
delete_times.append(time.perf_counter() - start)
return insert_times, find_times, delete_times
def average(values):
return sum(values) / len(values)
def run():
records_shuffled, records_sorted = generate_test_data()
results = []
for order_name, records in [
("random", records_shuffled),
("sorted", records_sorted)
]:
print("Order:", order_name)
ll = measure_experiment(
ll_insert,
ll_find,
ll_delete,
records
)
results.append(["LinkedList", order_name, "insert", *ll[0]])
results.append(["LinkedList", order_name, "find", *ll[1]])
results.append(["LinkedList", order_name, "delete", *ll[2]])
ht = measure_hash(records)
results.append(["HashTable", order_name, "insert", *ht[0]])
results.append(["HashTable", order_name, "find", *ht[1]])
results.append(["HashTable", order_name, "delete", *ht[2]])
bst = measure_experiment(
bst_insert,
bst_find,
bst_delete,
records
)
results.append(["BST", order_name, "insert", *bst[0]])
results.append(["BST", order_name, "find", *bst[1]])
results.append(["BST", order_name, "delete", *bst[2]])
os.makedirs("docs/data", exist_ok=True)
with open("docs/data/results.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerow([
"structure",
"order",
"operation",
"run1",
"run2",
"run3",
"run4",
"run5",
"average"
])
for row in results:
writer.writerow(row + [average(row[3:])])
print("Results saved to docs/data/results.csv")
if __name__ == "__main__":
run()

View File

@ -0,0 +1,56 @@
import csv
import os
import matplotlib.pyplot as plt
data = []
with open("docs/data/results.csv", "r", encoding="utf-8") as file:
reader = csv.DictReader(file)
for row in reader:
data.append(row)
def get_average(structure, order, operation):
for row in data:
if (
row["structure"] == structure
and row["order"] == order
and row["operation"] == operation
):
return float(row["average"])
return 0
structures = ["LinkedList", "HashTable", "BST"]
orders = ["random", "sorted"]
os.makedirs("docs/data", exist_ok=True)
for operation in ["insert", "find", "delete"]:
random_values = [
get_average(s, "random", operation)
for s in structures
]
sorted_values = [
get_average(s, "sorted", operation)
for s in structures
]
x = range(len(structures))
plt.figure()
plt.bar([i - 0.2 for i in x], random_values, width=0.4, label="random")
plt.bar([i + 0.2 for i in x], sorted_values, width=0.4, label="sorted")
plt.xticks(list(x), structures)
plt.ylabel("Time, seconds")
plt.title(operation.capitalize() + " time")
plt.yscale("log")
plt.legend()
plt.tight_layout()
plt.savefig("docs/data/graph_" + operation + ".png")
plt.close()
print("Graphs saved to docs/data/")

View File

@ -0,0 +1,211 @@
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['next'] is not None:
if current['name'] == name:
current['phone'] = phone
return head
current = current['next']
if current['name'] == name:
current['phone'] = phone
else:
current['next'] = new_node
return head
def ll_find(head, name):
current = head
while current is not None:
if current['name'] == name:
return current['phone']
current = current['next']
return None
def ll_delete(head, name):
if head is None:
return None
if head['name'] == name:
return head['next']
current = head
while current['next'] is not None:
if current['next']['name'] == name:
current['next'] = current['next']['next']
return head
current = current['next']
return head
def ll_list_all(head):
records = []
current = head
while current is not None:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return records
def hash_function(name, table_size):
total = 0
for ch in name:
total = (total * 31 + ord(ch)) % table_size
return total
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)
return buckets
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)
return buckets
def ht_list_all(buckets):
records = []
for bucket in buckets:
current = bucket
while current is not None:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return records
def bst_insert(root, name, phone):
new_node = {
'name': name,
'phone': phone,
'left': None,
'right': None
}
if root is None:
return new_node
current = root
while True:
if name < current['name']:
if current['left'] is None:
current['left'] = new_node
break
current = current['left']
elif name > current['name']:
if current['right'] is None:
current['right'] = new_node
break
current = current['right']
else:
current['phone'] = phone
break
return root
def bst_find(root, name):
current = root
while current is not None:
if name == current['name']:
return current['phone']
if name < current['name']:
current = current['left']
else:
current = current['right']
return None
def bst_delete(root, name):
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:
child = current['right']
elif current['right'] is None:
child = current['left']
else:
successor_parent = current
successor = current['right']
while successor['left'] is not None:
successor_parent = successor
successor = successor['left']
current['name'] = successor['name']
current['phone'] = successor['phone']
if successor_parent['left'] == successor:
successor_parent['left'] = successor['right']
else:
successor_parent['right'] = successor['right']
return root
if parent is None:
return child
if parent['left'] == current:
parent['left'] = child
else:
parent['right'] = child
return root
def bst_list_all(root):
records = []
def inorder(node):
if node is None:
return
inorder(node['left'])
records.append((node['name'], node['phone']))
inorder(node['right'])
inorder(root)
return records