2026-rff_mp/ShulpinIN/datastructure_lab1/datastruct.py

308 lines
9.0 KiB
Python

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()