2026-rff_mp/SobolevNS/docs/data/task1_data_structures/plot_results.py

119 lines
4.3 KiB
Python
Raw Normal View History

2026-05-22 09:22:08 +00:00
"""
plot_results.py - строит столбчатые диаграммы по итогам экспериментов.
"""
import csv
import os
import matplotlib.pyplot as plt
import numpy as np
CSV = os.path.join("docs", "data", "results.csv")
PLOTS_DIR = os.path.join("docs", "data", "plots")
os.makedirs(PLOTS_DIR, exist_ok=True)
def load_means():
"""Возвращает dict[(structure, mode, op)] = (mean, N)."""
means = {}
with open(CSV, encoding="utf-8") as f:
rows = list(csv.reader(f))
# ищем секцию "--- СРЕДНИЕ ---"
start = None
for i, row in enumerate(rows):
if row and row[0] == "--- СРЕДНИЕ ---":
start = i + 2 # пропустить заголовок секции
break
for row in rows[start:]:
if not row:
continue
structure, mode, op, n, mean, _trials = row
means[(structure, mode, op)] = (float(mean), int(n))
return means
def plot_grouped(means, op, fname, title):
"""Сгруппированные столбцы: для каждой структуры - два столбца (shuffled / sorted)."""
structures = ["LinkedList", "HashTable", "BST"]
modes = ["shuffled", "sorted"]
x = np.arange(len(structures))
width = 0.36
fig, ax = plt.subplots(figsize=(8, 5))
for i, mode in enumerate(modes):
vals_ms = []
labels = []
for s in structures:
mean, n = means[(s, mode, op)]
vals_ms.append(mean * 1000)
labels.append(f"N={n}")
bars = ax.bar(x + (i - 0.5) * width, vals_ms, width,
label=mode, alpha=0.85)
for bar, lab in zip(bars, labels):
h = bar.get_height()
ax.text(bar.get_x() + bar.get_width() / 2, h,
f"{h:.2f}\n{lab}", ha="center", va="bottom", fontsize=8)
ax.set_xticks(x)
ax.set_xticklabels(structures)
ax.set_ylabel("Время, мс (среднее по 5 запускам)")
ax.set_title(title)
ax.set_yscale("log")
ax.legend(title="порядок входных данных")
ax.grid(axis="y", linestyle="--", alpha=0.4)
plt.tight_layout()
out = os.path.join(PLOTS_DIR, fname)
plt.savefig(out, dpi=130)
plt.close()
print("saved:", out)
def plot_bst_degradation(means, fname):
"""Отдельный график: BST shuffled vs sorted - даже при меньшем N
отсортированные данные дают намного большее время."""
ops = ["insert", "find", "delete"]
shuffled = [means[("BST", "shuffled", op)][0] * 1000 for op in ops]
sorted_ = [means[("BST", "sorted", op)][0] * 1000 for op in ops]
n_shuf = means[("BST", "shuffled", "insert")][1]
n_sort = means[("BST", "sorted", "insert")][1]
x = np.arange(len(ops))
width = 0.36
fig, ax = plt.subplots(figsize=(7, 4.5))
ax.bar(x - width/2, shuffled, width, label=f"shuffled (N={n_shuf})")
ax.bar(x + width/2, sorted_, width, label=f"sorted (N={n_sort})")
for i, v in enumerate(shuffled):
ax.text(i - width/2, v, f"{v:.2f}", ha="center", va="bottom", fontsize=9)
for i, v in enumerate(sorted_):
ax.text(i + width/2, v, f"{v:.2f}", ha="center", va="bottom", fontsize=9)
ax.set_xticks(x); ax.set_xticklabels(ops)
ax.set_ylabel("Время, мс")
ax.set_title("BST: деградация на отсортированных данных\n"
"(N для sorted в 5 раз меньше, но время больше)")
ax.set_yscale("log")
ax.legend()
ax.grid(axis="y", linestyle="--", alpha=0.4)
plt.tight_layout()
out = os.path.join(PLOTS_DIR, fname)
plt.savefig(out, dpi=130)
plt.close()
print("saved:", out)
def main():
means = load_means()
plot_grouped(means, "insert",
"insert_compare.png",
"Вставка всех записей (лог. шкала)")
plot_grouped(means, "find",
"find_compare.png",
"Поиск 110 ключей (лог. шкала)")
plot_grouped(means, "delete",
"delete_compare.png",
"Удаление 50 записей (лог. шкала)")
plot_bst_degradation(means, "bst_degradation.png")
if __name__ == "__main__":
main()