diff --git a/SimonovaMS/428.txt b/SimonovaMS/428.txt deleted file mode 100644 index e69de29..0000000 diff --git a/SimonovaMS/analys_report.txt b/SimonovaMS/analys_report.txt new file mode 100644 index 0000000..42aea90 --- /dev/null +++ b/SimonovaMS/analys_report.txt @@ -0,0 +1,50 @@ +['Structura', 'shuffled/sorted', 'Operation', 'Time'] +LinkedList | shuffled | insert | 3.798362 +LinkedList | shuffled | find | 0.028610 +LinkedList | shuffled | delete | 0.035444 +LinkedList | sorted | insert | 3.117239 +LinkedList | sorted | find | 0.020465 +LinkedList | sorted | delete | 0.028734 +HashTable | shuffled | insert | 0.013259 +HashTable | shuffled | find | 0.000109 +HashTable | shuffled | delete | 0.000079 +HashTable | sorted | insert | 0.014760 +HashTable | sorted | find | 0.000107 +HashTable | sorted | delete | 0.000076 +Bst | shuffled | insert | 0.020712 +Bst | shuffled | find | 0.000246 +Bst | shuffled | delete | 0.000096 +Bst | sorted | insert | 3.905296 +Bst | sorted | find | 0.029092 +Bst | sorted | delete | 0.018350 + +Результаты: +Структура Режим вставка поиск удаление +LinkedList shuffled 3.798362 0.028610 0.035444 +LinkedList sorted 3.117239 0.020465 0.028734 +HashTable shuffled 0.013259 0.000109 0.000079 +HashTable sorted 0.014760 0.000107 0.000076 +Bst shuffled 0.020712 0.000246 0.000096 +Bst sorted 3.905296 0.029092 0.018350 +График +График сохранён в файл: results_plot.png + +Анализ: + +ВСТАВКА: + Лучшая: HashTable (0.014010 сек) + Худшая: LinkedList (3.457801 сек) + +ПОИСК: + Лучшая: HashTable (0.000108 сек) + Худшая: LinkedList (0.024537 сек) + +УДАЛЕНИЕ: + Лучшая: HashTable (0.000077 сек) + Худшая: LinkedList (0.032089 сек) + +Вывод: +Для вставок, поиска и удаления лучше всего использовать HashTable как для отсортированных, так и для неотсортированных данных +BST неплох для отсортированных данных, но всё равно хуже HashTable +LinkedList показал худшие результаты +HashTable - оптимальный выбор для телефонного справочника diff --git a/SimonovaMS/analyz.py b/SimonovaMS/analyz.py new file mode 100644 index 0000000..14d1992 --- /dev/null +++ b/SimonovaMS/analyz.py @@ -0,0 +1,121 @@ +import csv +import matplotlib.pyplot as plt +import numpy as np +from collections import defaultdict +import os + +report_file = open("analys_report.txt", "w", encoding="utf-8") +data = defaultdict(lambda: defaultdict(dict)) + +with open("C:/Users/Honor/Documents/dep2k/lab_inf_1/data/results.csv", "r", encoding="utf-8") as f: + reader = csv.reader(f) + header = next(reader) + print(f"{header}") + report_file.write(f"{header}\n") + + for row in reader: + if len(row) >= 4: + struct = row[0] # LinkedList, HashTable, Bst + mode = row[1] # shuffled или sorted + op = row[2] # insert, find, delete + time_val = float(row[3]) + + data[struct][mode][op] = time_val + print(f"{struct} | {mode} | {op} | {time_val:.6f}") + report_file.write(f"{struct} | {mode} | {op} | {time_val:.6f}\n") + +op_names = { + 'insert': 'вставка', + 'find': 'поиск', + 'delete': 'удаление' +} + +structures = ["LinkedList", "HashTable", "Bst"] +modes = ["shuffled", "sorted"] +operations = ["insert", "find", "delete"] + +print("Результаты:") +report_file.write("\nРезультаты:\n") +print(f"{'Структура':<15} {'Режим':<10} {'вставка':<15} {'поиск':<15} {'удаление':<15}") +report_file.write(f"{'Структура':<15} {'Режим':<10} {'вставка':<15} {'поиск':<15} {'удаление':<15}\n") + +for struct in structures: + for mode in modes: + insert_time = data[struct][mode]['insert'] + find_time = data[struct][mode]['find'] + delete_time = data[struct][mode]['delete'] + print(f"{struct:<15} {mode:<10} {insert_time:<15.6f} {find_time:<15.6f} {delete_time:<15.6f}") + report_file.write(f"{struct:<15} {mode:<10} {insert_time:<15.6f} {find_time:<15.6f} {delete_time:<15.6f}\n") + +#графики +fig, axes = plt.subplots(1, 3, figsize=(15, 5)) + +for idx, op in enumerate(operations): + ax = axes[idx] + + x = np.arange(len(structures)) + width = 0.35 + + shuffled_vals = [data[s]["shuffled"][op] for s in structures] + sorted_vals = [data[s]["sorted"][op] for s in structures] + + bars1 = ax.bar(x - width/2, shuffled_vals, width, label='shuffled', color='orange', alpha=0.8) + bars2 = ax.bar(x + width/2, sorted_vals, width, label='sorted', color='cyan', alpha=0.8) + + ax.set_xlabel('Структура') + ax.set_ylabel('Время (сек)') + ax.set_title(f'{op_names[op]}') + ax.set_xticks(x) + ax.set_xticklabels(structures, rotation=45) + ax.legend() + ax.set_yscale('log') + + for bar in bars1: + height = bar.get_height() + ax.text(bar.get_x() + bar.get_width()/2, height, + f'{height:.3f}', ha='center', va='bottom', fontsize=8) + for bar in bars2: + height = bar.get_height() + ax.text(bar.get_x() + bar.get_width()/2, height, + f'{height:.3f}', ha='center', va='bottom', fontsize=8) + +plt.tight_layout() +plot_filename = "results_plot.png" +plt.savefig('results_plot.png', dpi=150) +plt.show() + +report_file.write("График\n") +report_file.write(f"График сохранён в файл: {plot_filename}\n") + +print("Анализ:") +report_file.write("\nАнализ:\n") + +for op in operations: + print(f"\n{op_names[op].upper()}:") + report_file.write(f"\n{op_names[op].upper()}:\n") + + # Среднее по двум режимам + avg_times = [] + for s in structures: + avg = (data[s]["shuffled"][op] + data[s]["sorted"][op]) / 2 + avg_times.append((s, avg)) + + avg_times.sort(key=lambda x: x[1]) + print(f" Лучшая: {avg_times[0][0]} ({avg_times[0][1]:.6f} сек)") + print(f" Худшая: {avg_times[-1][0]} ({avg_times[-1][1]:.6f} сек)") + report_file.write(f" Лучшая: {avg_times[0][0]} ({avg_times[0][1]:.6f} сек)\n") + report_file.write(f" Худшая: {avg_times[-1][0]} ({avg_times[-1][1]:.6f} сек)\n") + + +print("Вывод:") +report_file.write("\nВывод:\n") +print("Для вставок, поиска и удаления лучше всего использовать HashTable как для отсортированных, так и для неотсортированных данных") +print("BST неплох для отсортированных данных, но всё равно хуже HashTable") +print("LinkedList показал худшие результаты") +print("HashTable - оптимальный выбор для телефонного справочника") + +report_file.write("Для вставок, поиска и удаления лучше всего использовать HashTable как для отсортированных, так и для неотсортированных данных\n") +report_file.write("BST неплох для отсортированных данных, но всё равно хуже HashTable\n") +report_file.write("LinkedList показал худшие результаты\n") +report_file.write("HashTable - оптимальный выбор для телефонного справочника\n") +report_file.close() \ No newline at end of file diff --git a/SimonovaMS/generator.py b/SimonovaMS/generator.py new file mode 100644 index 0000000..4907297 --- /dev/null +++ b/SimonovaMS/generator.py @@ -0,0 +1,29 @@ +import random +from typing import List, Tuple + +def generate_data(n=10000): + records = [] + for i in range(n): + name = f"User_{i:05d}" + phone = f"8{random.randint(900,999)}{random.randint(100,999)}{random.randint(0,9)}{random.randint(0,9)}{random.randint(0,9)}{random.randint(0,9)}" + records.append((name,phone)) + + records_shuffled = records.copy() + random.shuffle(records_shuffled) + records_sorted = sorted(records, key=lambda x:x[0]) + + return records_shuffled, records_sorted + +def generate_search(records, exist_count=100, no_exist_count=10): + exist_names = [name for name, _ in records] + select_exist = random.sample(exist_names, min(exist_count, len(exist_names))) + + no_exist_count=[f"None_{i:05d}" for i in range(no_exist_count)] + + return select_exist + no_exist_count + +def generate_delete(records, count=50): + names = [name for name, _ in records] + return random.sample(names, min(count, len(names))) + + diff --git a/SimonovaMS/phonebook.py b/SimonovaMS/phonebook.py new file mode 100644 index 0000000..ac33ef1 --- /dev/null +++ b/SimonovaMS/phonebook.py @@ -0,0 +1,247 @@ +import time +import csv +import random +from functools import lru_cache +from operator import index + + +#LinkedListPhoneBook +def create_node(name, phone): + return {'name': name, 'phone': phone, 'next': None} + +def ll_insert(head, name, phone): + new_node = create_node(name,phone) + + if head is None: + return new_node + current = head + while current['next'] is not None: + if current['next']['name'] == name: + new_node['next'] = current['next']['next'] + current['next']=new_node + return head + current=current['next'] + + 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 create_buckets(size=1000): + return [None] * size + +def hash_function(name, buckest_size): + hash_value = 0 + for char in name: + hash_value = (hash_value * 31 + ord(char)) % buckest_size + return hash_value + +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 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 + +#bts +def create_bst_node(name, phone): + return {'name': name, 'phone': phone, 'left': None, 'right': None} + +def bst_insert(root, name, phone): + new_node = create_bst_node(name, phone) + if root is None: + return new_node + current = root + while True: + if name == current['name']: + current['phone'] = phone + return root + elif name < current['name']: + if current['left'] is None: + current['left'] = new_node + return root + current = current['left'] + else: + if current['right'] is None: + current['right'] = new_node + return root + current = current['right'] + + +def bst_find(root, name): + current = root + while current is not None: + if name == current['name']: + return current['phone'] + elif name < current['name']: + current=current['left'] + else: + current=current['right'] + return None + +def bst_find_min(node): + current = node + while current['left'] is not None: + current = current['left'] + return current + + +def bst_delete(root, name): + if root is None: + return None + + if root['name'] == name: + if root['left'] is None and root['right'] is None: + return None + if root['left'] is None: + return root['right'] + if root['right'] is None: + return root['left'] + parent = root + min_node = root['right'] + while min_node['left']: + parent = min_node + min_node = min_node['left'] + + root['name'] = min_node['name'] + root['phone'] = min_node['phone'] + + + if parent == root: + parent['right'] = min_node['right'] + else: + parent['left'] = min_node['right'] + + return root + + parent = None + current = root + while current 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 and current['right'] is None: + if parent['left'] == current: + parent['left'] = None + else: + parent['right'] = None + + + elif current['left'] is None: + if parent['left'] == current: + parent['left'] = current['right'] + else: + parent['right'] = current['right'] + + + elif current['right'] is None: + if parent['left'] == current: + parent['left'] = current['left'] + else: + parent['right'] = current['left'] + + else: + min_parent = current + min_node = current['right'] + while min_node['left']: + min_parent = min_node + min_node = min_node['left'] + + + current['name'] = min_node['name'] + current['phone'] = min_node['phone'] + + + if min_parent == current: + min_parent['right'] = min_node['right'] + else: + min_parent['left'] = min_node['right'] + + return root + + +def bst_list_all(root): + records = [] + stack = [] + current = root + + while stack or current: + while current: + stack.append(current) + current = current['left'] + + current = stack.pop() + records.append((current['name'], current['phone'])) + current = current['right'] + + return records + +def bst_list_all(root): + records =[] + stack = [] + current = root + while stack or current is not None: + while current is not None: + stack.append(current) + current=current['left'] + + current=stack.pop() + records.append((current['name'], current['phone'])) + + current=current['right'] + return records + diff --git a/SimonovaMS/result_plot.png b/SimonovaMS/result_plot.png new file mode 100644 index 0000000..1b903d7 Binary files /dev/null and b/SimonovaMS/result_plot.png differ diff --git a/SimonovaMS/test.py b/SimonovaMS/test.py new file mode 100644 index 0000000..d9cade5 --- /dev/null +++ b/SimonovaMS/test.py @@ -0,0 +1,211 @@ +import time +import csv +import random + +from phonebook import (ll_insert, ll_find, ll_delete, create_buckets, ht_insert, ht_find, ht_delete, bst_insert, bst_find, bst_delete) +from generator import generate_data + +def run_exp(): + records_shuffled, records_sorted = generate_data(10000) + all_names = [name for name, _ in records_shuffled] + search_names = random.sample(all_names, 100) + [f"None_{i}" for i in range(10)] + delete_names = random.sample(all_names, 50) + + results = [["Structura", "shuffled/sorted", "Operation", "Time"]] + + times =[] + print('LinkedList - shuffled') + for r in range(5): + head = None + start = time.perf_counter() + for name, phone in records_shuffled: + head = ll_insert(head, name, phone) + times.append(time.perf_counter() - start) + avg = sum(times)/5 + results.append(["LinkedList", "shuffled", "insert", avg]) + print(f"вставка - {avg:.6f}") + + times=[] + for r in range(5): + start = time.perf_counter() + for name in search_names: + ll_find(head, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["LinkedList", "shuffled", "find", avg]) + print(f"поиск - {avg:.6f}") + + times=[] + for r in range(5): + start = time.perf_counter() + for name in delete_names: + head = ll_delete(head, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["LinkedList", "shuffled", "delete", avg]) + print(f"удаление - {avg:.6f}") + + print('LinkedList - sorted') + for r in range(5): + head = None + start = time.perf_counter() + for name, phone in records_sorted: + head = ll_insert(head, name, phone) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["LinkedList", "sorted", "insert", avg]) + print(f"вставка - {avg:.6f}") + + times = [] + for r in range(5): + start = time.perf_counter() + for name in search_names: + ll_find(head, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["LinkedList", "sorted", "find", avg]) + print(f"поиск - {avg:.6f}") + + times = [] + for r in range(5): + start = time.perf_counter() + for name in delete_names: + head = ll_delete(head, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["LinkedList", "sorted", "delete", avg]) + print(f"удаление - {avg:.6f}") + + print('HashTable - shuffled') + times =[] + for r in range(5): + buckets = create_buckets(1000) + start = time.perf_counter() + for name, phone in records_shuffled: + ht_insert(buckets,name,phone) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["HashTable", "shuffled", "insert", avg]) + print(f"вставка - {avg:.6f}") + + times = [] + for r in range(5): + start = time.perf_counter() + for name in search_names: + ht_find(buckets, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["HashTable", "shuffled", "find", avg]) + print(f"поиск - {avg:.6f}") + + times = [] + for r in range(5): + start = time.perf_counter() + for name in delete_names: + ht_delete(buckets, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["HashTable", "shuffled", "delete", avg]) + print(f"удаление - {avg:.6f}") + + print('sorted') + times = [] + for r in range(5): + buckets = create_buckets(1000) + start = time.perf_counter() + for name, phone in records_sorted: + ht_insert(buckets, name, phone) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["HashTable", "sorted", "insert", avg]) + print(f"вставка - {avg:.6f}") + + times = [] + for r in range(5): + start = time.perf_counter() + for name in search_names: + ht_find(buckets, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["HashTable", "sorted", "find", avg]) + print(f"поиск - {avg:.6f}") + + times = [] + for r in range(5): + start = time.perf_counter() + for name in delete_names: + ht_delete(buckets, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["HashTable", "sorted", "delete", avg]) + print(f"удаление - {avg:.6f}") + + print("BST - shuffled") + times = [] + for r in range(5): + root = None + start = time.perf_counter() + for name, phone in records_shuffled: + root = bst_insert(root, name, phone) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["Bst", "shuffled", "insert", avg]) + print(f"вставка - {avg:.6f}") + + times = [] + for r in range(5): + start = time.perf_counter() + for name in search_names: + bst_find(root, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["Bst", "shuffled", "find", avg]) + print(f"поиск - {avg:.6f}") + + times = [] + for r in range(5): + start = time.perf_counter() + for name in delete_names: + root = bst_delete(root, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["Bst", "shuffled", "delete", avg]) + print(f"удаление - {avg:.6f}") + + print('sorted') + times = [] + for r in range(5): + root = None + start = time.perf_counter() + for name, phone in records_sorted: + root = bst_insert(root, name, phone) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["Bst", "sorted", "insert", avg]) + print(f"вставка - {avg:.6f}") + + times = [] + for r in range(5): + start = time.perf_counter() + for name in search_names: + bst_find(root, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["Bst", "sorted", "find", avg]) + print(f"поиск - {avg:.6f}") + + times = [] + for r in range(5): + start = time.perf_counter() + for name in delete_names: + root = bst_delete(root, name) + times.append(time.perf_counter() - start) + avg = sum(times) / 5 + results.append(["Bst", "sorted", "delete", avg]) + print(f"удаление - {avg:.6f}") + + with open("C:/Users/Honor/Documents/dep2k/lab_inf_1/data/results.csv", "w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerows(results) +if __name__ == "__main__": + run_exp() \ No newline at end of file