Добавил:
lovickaaolesa
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:5 курс / lab5
.pyimport tkinter as tk
from tkinter import ttk, messagebox, filedialog
import math
import random
import time
class Graph:
def __init__(self, vertices=0):
self.vertices = vertices
self.adj_matrix = [[0] * vertices for _ in range(vertices)]
self.edges = []
def add_edge(self, u, v, weight):
if 0 <= u < self.vertices and 0 <= v < self.vertices:
self.adj_matrix[u][v] = weight
self.adj_matrix[v][u] = weight
self.edges.append((u, v, weight))
def prim_algorithm(self, start_vertex=0):
if self.vertices == 0:
return [], 0
selected = [False] * self.vertices
selected[start_vertex] = True
mst_edges = []
total_weight = 0
while len(mst_edges) < self.vertices - 1:
min_weight = float('inf')
u, v = -1, -1
for i in range(self.vertices):
if selected[i]:
for j in range(self.vertices):
if not selected[j] and self.adj_matrix[i][j] > 0:
if self.adj_matrix[i][j] < min_weight:
min_weight = self.adj_matrix[i][j]
u, v = i, j
if u != -1 and v != -1:
mst_edges.append((u, v, min_weight))
selected[v] = True
total_weight += min_weight
return mst_edges, total_weight
def get_edge_list(self):
edges = []
for i in range(self.vertices):
for j in range(i + 1, self.vertices):
if self.adj_matrix[i][j] > 0:
edges.append((i, j, self.adj_matrix[i][j]))
return edges
class GraphVisualizer:
def __init__(self, root):
self.root = root
self.root.title("Алгоритм Прима - Минимальное остовное дерево")
self.root.geometry("1200x700")
self.graph = Graph()
self.mst_edges = []
self.total_weight = 0
self.vertex_positions = []
self.create_widgets()
self.create_canvas()
def create_widgets(self):
control_frame = tk.Frame(self.root, width=300, bg="#f0f0f0")
control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10)
control_frame.pack_propagate(False)
title_label = tk.Label(control_frame, text="Управление графом",
font=("Arial", 14, "bold"), bg="#f0f0f0")
title_label.pack(pady=10)
load_button = tk.Button(control_frame, text="Загрузить из файла",
command=self.load_graph_from_file, width=20)
load_button.pack(pady=5)
save_button = tk.Button(control_frame, text="Сохранить в файл",
command=self.save_graph_to_file, width=20)
save_button.pack(pady=5)
ttk.Separator(control_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=10)
gen_frame = tk.Frame(control_frame, bg="#f0f0f0")
gen_frame.pack(pady=5)
tk.Label(gen_frame, text="Вершины:", bg="#f0f0f0").pack(side=tk.LEFT)
self.vertices_entry = tk.Entry(gen_frame, width=8)
self.vertices_entry.insert(0, "8")
self.vertices_entry.pack(side=tk.LEFT, padx=5)
tk.Label(gen_frame, text="Плотность %:", bg="#f0f0f0").pack(side=tk.LEFT, padx=(10, 0))
self.density_entry = tk.Entry(gen_frame, width=8)
self.density_entry.insert(0, "50")
self.density_entry.pack(side=tk.LEFT, padx=5)
gen_button = tk.Button(control_frame, text="Сгенерировать граф",
command=self.generate_random_graph, width=20)
gen_button.pack(pady=5)
ttk.Separator(control_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=10)
prim_frame = tk.Frame(control_frame, bg="#f0f0f0")
prim_frame.pack(pady=5)
tk.Label(prim_frame, text="Начальная вершина:", bg="#f0f0f0").pack(side=tk.LEFT)
self.start_vertex_entry = tk.Entry(prim_frame, width=8)
self.start_vertex_entry.insert(0, "0")
self.start_vertex_entry.pack(side=tk.LEFT, padx=5)
prim_button = tk.Button(control_frame, text="Запустить алгоритм Прима",
command=self.run_prim_algorithm, width=20, bg="#4CAF50", fg="white")
prim_button.pack(pady=5)
analyze_button = tk.Button(control_frame, text="Анализ временной сложности",
command=self.analyze_time_complexity, width=20)
analyze_button.pack(pady=5)
clear_button = tk.Button(control_frame, text="Очистить граф",
command=self.clear_graph, width=20)
clear_button.pack(pady=5)
ttk.Separator(control_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=10)
info_label = tk.Label(control_frame, text="Информация о графе",
font=("Arial", 12, "bold"), bg="#f0f0f0")
info_label.pack(pady=5)
self.info_text = tk.Text(control_frame, height=8, width=30, font=("Arial", 10))
self.info_text.pack(pady=5)
edges_label = tk.Label(control_frame, text="Список ребер",
font=("Arial", 12, "bold"), bg="#f0f0f0")
edges_label.pack(pady=5)
self.edges_text = tk.Text(control_frame, height=10, width=30, font=("Arial", 9))
self.edges_text.pack(pady=5)
def create_canvas(self):
canvas_frame = tk.Frame(self.root)
canvas_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=10, pady=10)
self.canvas = tk.Canvas(canvas_frame, bg="white", highlightthickness=1,
highlightbackground="black")
self.canvas.pack(fill=tk.BOTH, expand=True)
result_frame = tk.Frame(self.root, width=300, bg="#f0f0f0")
result_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=10, pady=10)
result_frame.pack_propagate(False)
result_label = tk.Label(result_frame, text="Результаты",
font=("Arial", 14, "bold"), bg="#f0f0f0")
result_label.pack(pady=10)
self.result_text = tk.Text(result_frame, height=20, width=35, font=("Arial", 10))
self.result_text.pack(pady=5)
def load_graph_from_file(self):
filename = filedialog.askopenfilename(
title="Выберите файл с графом",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if filename:
try:
with open(filename, 'r') as file:
lines = file.readlines()
vertices = int(lines[0].strip())
self.graph = Graph(vertices)
for i in range(1, len(lines)):
row = list(map(int, lines[i].strip().split()))
for j in range(vertices):
self.graph.adj_matrix[i - 1][j] = row[j]
self.mst_edges = []
self.total_weight = 0
self.update_edge_list()
self.draw_graph()
messagebox.showinfo("Успех", f"Граф загружен из файла {filename}")
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось загрузить файл: {e}")
def save_graph_to_file(self):
if self.graph.vertices == 0:
messagebox.showwarning("Предупреждение", "Нет графа для сохранения")
return
filename = filedialog.asksaveasfilename(
title="Сохранить граф",
defaultextension=".txt",
filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
)
if filename:
try:
with open(filename, 'w') as file:
file.write(str(self.graph.vertices) + "\n")
for i in range(self.graph.vertices):
row = " ".join(str(x) for x in self.graph.adj_matrix[i])
file.write(row + "\n")
messagebox.showinfo("Успех", f"Граф сохранен в файл {filename}")
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось сохранить файл: {e}")
def generate_random_graph(self):
try:
vertices = int(self.vertices_entry.get())
density = float(self.density_entry.get()) / 100
if vertices < 2 or vertices > 20:
messagebox.showwarning("Предупреждение", "Количество вершин должно быть от 2 до 20")
return
self.graph = Graph(vertices)
for i in range(vertices):
for j in range(i + 1, vertices):
if random.random() < density:
weight = random.randint(1, 20)
self.graph.adj_matrix[i][j] = weight
self.graph.adj_matrix[j][i] = weight
self.mst_edges = []
self.total_weight = 0
self.update_edge_list()
self.draw_graph()
except ValueError:
messagebox.showerror("Ошибка", "Введите корректные значения")
def update_edge_list(self):
self.info_text.delete(1.0, tk.END)
self.edges_text.delete(1.0, tk.END)
if self.graph.vertices > 0:
edges = self.graph.get_edge_list()
self.info_text.insert(tk.END, f"Вершин: {self.graph.vertices}\n")
self.info_text.insert(tk.END, f"Ребер: {len(edges)}\n")
for u, v, w in edges:
self.edges_text.insert(tk.END, f"{u} -- {v} : {w}\n")
def draw_graph(self):
self.canvas.delete("all")
if self.graph.vertices == 0:
return
center_x, center_y = 400, 300
radius = 250
self.vertex_positions = []
for i in range(self.graph.vertices):
angle = 2 * math.pi * i / self.graph.vertices
x = center_x + radius * math.cos(angle)
y = center_y + radius * math.sin(angle)
self.vertex_positions.append((x, y))
for i in range(self.graph.vertices):
for j in range(i + 1, self.graph.vertices):
if self.graph.adj_matrix[i][j] > 0:
x1, y1 = self.vertex_positions[i]
x2, y2 = self.vertex_positions[j]
is_mst_edge = any((u == i and v == j) or (u == j and v == i)
for u, v, _ in self.mst_edges)
color = "red" if is_mst_edge else "gray"
width = 3 if is_mst_edge else 1
self.canvas.create_line(x1, y1, x2, y2, fill=color, width=width)
mid_x = (x1 + x2) / 2
mid_y = (y1 + y2) / 2
self.canvas.create_text(mid_x, mid_y, text=str(self.graph.adj_matrix[i][j]),
fill="blue", font=("Arial", 10, "bold"))
for i, (x, y) in enumerate(self.vertex_positions):
self.canvas.create_oval(x - 20, y - 20, x + 20, y + 20, fill="lightblue", outline="black", width=2)
self.canvas.create_text(x, y, text=str(i), font=("Arial", 12, "bold"))
if self.mst_edges:
info_text = f"Минимальное остовное дерево\n"
info_text += f"Общий вес: {self.total_weight}\n"
info_text += f"Количество ребер: {len(self.mst_edges)}\n"
info_text += f"Ребра MST: {', '.join([f'{u}-{v}({w})' for u, v, w in self.mst_edges])}"
self.canvas.create_text(400, 550, text=info_text, font=("Arial", 10),
fill="darkgreen", justify="center")
def run_prim_algorithm(self):
if self.graph.vertices == 0:
messagebox.showwarning("Предупреждение", "Сначала создайте или загрузите граф")
return
try:
start_vertex = int(self.start_vertex_entry.get())
if start_vertex < 0 or start_vertex >= self.graph.vertices:
messagebox.showerror("Ошибка", f"Начальная вершина должна быть от 0 до {self.graph.vertices - 1}")
return
start_time = time.time()
self.mst_edges, self.total_weight = self.graph.prim_algorithm(start_vertex)
end_time = time.time()
execution_time = (end_time - start_time) * 1000
self.result_text.delete(1.0, tk.END)
self.result_text.insert(tk.END, f"Алгоритм Прима выполнен за {execution_time:.4f} мс\n\n")
self.result_text.insert(tk.END, f"Начальная вершина: {start_vertex}\n")
self.result_text.insert(tk.END, f"Общий вес MST: {self.total_weight}\n\n")
self.result_text.insert(tk.END, "Ребра минимального остовного дерева:\n")
for u, v, w in self.mst_edges:
self.result_text.insert(tk.END, f" {u} -- {v} : {w}\n")
self.draw_graph()
except ValueError:
messagebox.showerror("Ошибка", "Введите корректный номер начальной вершины")
def analyze_time_complexity(self):
analysis_window = tk.Toplevel(self.root)
analysis_window.title("Анализ временной сложности")
analysis_window.geometry("800x600")
title_label = tk.Label(analysis_window, text="Анализ временной сложности алгоритма Прима",
font=("Arial", 14, "bold"))
title_label.pack(pady=10)
text_frame = tk.Frame(analysis_window)
text_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
scrollbar = tk.Scrollbar(text_frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
text_widget = tk.Text(text_frame, wrap=tk.WORD, yscrollcommand=scrollbar.set)
text_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.config(command=text_widget.yview)
vertices_list = [5, 10, 15, 20, 25, 30]
density_list = [0.3, 0.5, 0.7]
results = []
text_widget.insert(tk.END, "ГЕНЕРАЦИЯ ТЕСТОВЫХ ДАННЫХ...\n")
text_widget.insert(tk.END, "=" * 80 + "\n\n")
for vertices in vertices_list:
for density in density_list:
test_graph = Graph(vertices)
edges_count = 0
for i in range(vertices):
for j in range(i + 1, vertices):
if random.random() < density:
weight = random.randint(1, 20)
test_graph.adj_matrix[i][j] = weight
test_graph.adj_matrix[j][i] = weight
edges_count += 1
start_time = time.time()
test_graph.prim_algorithm(0)
end_time = time.time()
execution_time = (end_time - start_time) * 1000
results.append((vertices, edges_count, density, execution_time))
text_widget.insert(tk.END, "ТАБЛИЦА АНАЛИЗА ВРЕМЕННОЙ СЛОЖНОСТИ\n")
text_widget.insert(tk.END, "=" * 80 + "\n")
text_widget.insert(tk.END, "Вершин | Ребра | Плотность | Время (мс) | O-нотация\n")
text_widget.insert(tk.END, "-" * 80 + "\n")
for vertices, edges, density, time_ms in results:
theoretical_complexity = vertices ** 2
text_widget.insert(tk.END,
f"{vertices:7d} | {edges:5d} | {density:9.1%} | {time_ms:10.4f} | O(V²) = O({vertices}²) = {theoretical_complexity}\n")
text_widget.insert(tk.END, "=" * 80 + "\n\n")
text_widget.insert(tk.END, "ВЫВОДЫ:\n")
text_widget.insert(tk.END, "=" * 40 + "\n")
text_widget.insert(tk.END, "1. Временная сложность алгоритма Прима с матрицей смежности: O(V²)\n\n")
text_widget.insert(tk.END, "2. Время выполнения растет квадратично с увеличением количества вершин\n\n")
text_widget.insert(tk.END, "3. Плотность графа незначительно влияет на время выполнения,\n")
text_widget.insert(tk.END, " так как алгоритм всегда проверяет все возможные пары вершин\n\n")
text_widget.insert(tk.END, "4. Для разреженных графов (мало ребер) эффективнее использовать\n")
text_widget.insert(tk.END, " реализацию с кучей, которая имеет сложность O(E log V)\n\n")
text_widget.insert(tk.END, "5. Для плотных графов (много ребер) текущая реализация эффективна,\n")
text_widget.insert(tk.END, " так как E ≈ V² и O(V²) ≈ O(E)\n")
close_button = tk.Button(analysis_window, text="Закрыть",
command=analysis_window.destroy, width=20)
close_button.pack(pady=10)
def clear_graph(self):
self.graph = Graph()
self.mst_edges = []
self.total_weight = 0
self.canvas.delete("all")
self.info_text.delete(1.0, tk.END)
self.edges_text.delete(1.0, tk.END)
self.result_text.delete(1.0, tk.END)
def main():
root = tk.Tk()
app = GraphVisualizer(root)
root.mainloop()
if __name__ == "__main__":
main()
Соседние файлы в папке 5 курс
