-
-
Notifications
You must be signed in to change notification settings - Fork 342
Add-Prims's Algorithm for MST #248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
8ffcc02
Add-Prims's Algorithm for MST
Erennn7 41025d4
Fix roxygen2 @param syntax in prim_mst functions
Erennn7 81f6b80
Update graph_algorithms/prim_mst.r
siriak 97180bb
Update graph_algorithms/prim_mst.r
siriak ec2b0b5
Merge branch 'master' into Add_Prims_algo
siriak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,255 @@ | ||
| # Prim's Algorithm for Minimum Spanning Tree (MST) | ||
| # | ||
| # Prim's algorithm finds the MST of a connected, weighted, undirected graph. | ||
| # It starts from an arbitrary node and repeatedly adds the smallest edge | ||
| # connecting the growing MST to a new vertex. | ||
| # | ||
| # Time Complexity: O(V^2) using adjacency matrix, O((V + E) log V) with priority queue | ||
| # Space Complexity: O(V) for key, parent, and visited arrays | ||
| # | ||
| # Applications: | ||
| # - Network design (telecommunications, computer networks) | ||
| # - Circuit design and electrical grids | ||
| # - Clustering algorithms in machine learning | ||
| # - Transportation and logistics planning | ||
| # - Approximation algorithms for NP-hard problems | ||
|
|
||
| #' Compute the Minimum Spanning Tree using Prim's algorithm | ||
| #' @param graph Adjacency matrix of the graph (use 0 or Inf for no edge) | ||
| #' @param start_vertex Starting vertex (default is 1) | ||
| #' @return List with MST edges, total weight, and parent array | ||
| prim_mst <- function(graph, start_vertex = 1) { | ||
| # Validate input | ||
| if (!is.matrix(graph)) { | ||
| stop("Error: Input must be a matrix") | ||
| } | ||
|
|
||
| if (nrow(graph) != ncol(graph)) { | ||
| stop("Error: Graph must be a square adjacency matrix") | ||
| } | ||
|
|
||
| n <- nrow(graph) | ||
|
|
||
| if (start_vertex < 1 || start_vertex > n) { | ||
| stop(sprintf("Error: start_vertex must be between 1 and %d", n)) | ||
| } | ||
|
|
||
| # Initialize arrays | ||
| key <- rep(Inf, n) # Minimum weight to include vertex | ||
| parent <- rep(NA, n) # Store MST edges | ||
| in_mst <- rep(FALSE, n) # Vertices included in MST | ||
|
|
||
| # Start from specified vertex | ||
| key[start_vertex] <- 0 | ||
| parent[start_vertex] <- -1 # Root of MST | ||
|
|
||
| # Build MST with n vertices | ||
| for (count in 1:n) { | ||
| # Pick vertex u not in MST with minimum key value | ||
| min_key <- Inf | ||
| u <- NA | ||
|
|
||
| for (v in 1:n) { | ||
| if (!in_mst[v] && key[v] < min_key) { | ||
| min_key <- key[v] | ||
| u <- v | ||
| } | ||
| } | ||
|
|
||
| # Check if graph is disconnected | ||
| if (is.na(u)) { | ||
| warning("Graph is disconnected. MST is incomplete.") | ||
| break | ||
| } | ||
|
|
||
| # Include u in MST | ||
| in_mst[u] <- TRUE | ||
|
|
||
| # Update key and parent for adjacent vertices of u | ||
| for (v in 1:n) { | ||
| # Check if there's an edge, v is not in MST, and edge weight is smaller | ||
| if (graph[u, v] != 0 && graph[u, v] != Inf && | ||
| !in_mst[v] && graph[u, v] < key[v]) { | ||
| key[v] <- graph[u, v] | ||
| parent[v] <- u | ||
| } | ||
| } | ||
| } | ||
|
|
||
| # Construct MST edges and calculate total weight | ||
| mst_edges <- list() | ||
| total_weight <- 0 | ||
| edge_count <- 0 | ||
|
|
||
| for (v in 1:n) { | ||
| if (!is.na(parent[v]) && parent[v] != -1) { | ||
| edge_count <- edge_count + 1 | ||
| mst_edges[[edge_count]] <- list( | ||
| from = parent[v], | ||
| to = v, | ||
| weight = graph[parent[v], v] | ||
| ) | ||
| total_weight <- total_weight + graph[parent[v], v] | ||
| } | ||
| } | ||
|
|
||
| return(list( | ||
| edges = mst_edges, | ||
| total_weight = total_weight, | ||
| parent = parent, | ||
| num_edges = edge_count | ||
| )) | ||
| } | ||
|
|
||
| #' Print MST in a formatted way | ||
| #' @param mst Result from prim_mst function | ||
| #' @param graph Original graph (for verification) | ||
| print_mst <- function(mst, graph = NULL) { | ||
| cat("Minimum Spanning Tree:\n") | ||
| cat(strrep("=", 50), "\n\n") | ||
|
|
||
| if (length(mst$edges) == 0) { | ||
| cat("No edges in MST (graph may be disconnected)\n") | ||
| return() | ||
| } | ||
|
|
||
| cat(sprintf("%-10s %-10s %-10s\n", "Edge", "Vertices", "Weight")) | ||
| cat(strrep("-", 50), "\n") | ||
|
|
||
| for (i in seq_along(mst$edges)) { | ||
| edge <- mst$edges[[i]] | ||
| cat(sprintf("%-10d %-10s %-10g\n", | ||
| i, | ||
| paste0(edge$from, " -- ", edge$to), | ||
| edge$weight)) | ||
| } | ||
|
|
||
| cat(strrep("-", 50), "\n") | ||
| cat(sprintf("Total Weight: %g\n", mst$total_weight)) | ||
| cat(sprintf("Number of Edges: %d\n", mst$num_edges)) | ||
|
|
||
| # Verify MST properties | ||
| if (!is.null(graph)) { | ||
| n <- nrow(graph) | ||
| expected_edges <- n - 1 | ||
| if (mst$num_edges == expected_edges) { | ||
| cat(sprintf("[OK] MST has correct number of edges (%d)\n", expected_edges)) | ||
| } else { | ||
| cat(sprintf("[WARN] MST has %d edges, expected %d (graph may be disconnected)\n", | ||
| mst$num_edges, expected_edges)) | ||
| } | ||
| } | ||
| cat("\n") | ||
| } | ||
|
|
||
| #' Create adjacency matrix from edge list | ||
| #' @param edges List of edges, each with from, to, and weight | ||
siriak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| #' @param n_vertices Number of vertices | ||
| #' @return Adjacency matrix | ||
| create_graph_from_edges <- function(edges, n_vertices) { | ||
| graph <- matrix(0, nrow = n_vertices, ncol = n_vertices) | ||
|
|
||
| for (edge in edges) { | ||
| graph[edge$from, edge$to] <- edge$weight | ||
| graph[edge$to, edge$from] <- edge$weight # Undirected graph | ||
| } | ||
|
|
||
| return(graph) | ||
| } | ||
|
|
||
| # ========== Example 1: Basic 5-vertex graph ========== | ||
| cat("========== Example 1: Basic 5-Vertex Graph ==========\n\n") | ||
| graph1 <- matrix(c( | ||
| 0, 2, 0, 6, 0, | ||
| 2, 0, 3, 8, 5, | ||
| 0, 3, 0, 0, 7, | ||
| 6, 8, 0, 0, 9, | ||
| 0, 5, 7, 9, 0 | ||
| ), nrow = 5, byrow = TRUE) | ||
| cat("Graph adjacency matrix:\n") | ||
| print(graph1) | ||
| cat("\n") | ||
| mst1 <- prim_mst(graph1) | ||
| print_mst(mst1, graph1) | ||
|
|
||
| # ========== Example 2: 6-vertex graph ========== | ||
| cat("========== Example 2: 6-Vertex Graph ==========\n\n") | ||
| graph2 <- matrix(c( | ||
| 0, 4, 0, 0, 0, 0, | ||
| 4, 0, 8, 0, 0, 0, | ||
| 0, 8, 0, 7, 0, 4, | ||
| 0, 0, 7, 0, 9, 14, | ||
| 0, 0, 0, 9, 0, 10, | ||
| 0, 0, 4, 14, 10, 0 | ||
| ), nrow = 6, byrow = TRUE) | ||
| cat("Graph adjacency matrix:\n") | ||
| print(graph2) | ||
| cat("\n") | ||
| mst2 <- prim_mst(graph2, start_vertex = 1) | ||
| print_mst(mst2, graph2) | ||
|
|
||
| # ========== Example 3: Using edge list representation ========== | ||
| cat("========== Example 3: Graph from Edge List ==========\n\n") | ||
| edges <- list( | ||
| list(from = 1, to = 2, weight = 1), | ||
| list(from = 1, to = 3, weight = 4), | ||
| list(from = 2, to = 3, weight = 2), | ||
| list(from = 2, to = 4, weight = 5), | ||
| list(from = 3, to = 4, weight = 3) | ||
| ) | ||
| graph3 <- create_graph_from_edges(edges, 4) | ||
| cat("Graph from edge list:\n") | ||
| for (edge in edges) { | ||
| cat(sprintf("%d -- %d : %g\n", edge$from, edge$to, edge$weight)) | ||
| } | ||
| cat("\nAdjacency matrix:\n") | ||
| print(graph3) | ||
| cat("\n") | ||
| mst3 <- prim_mst(graph3) | ||
| print_mst(mst3, graph3) | ||
|
|
||
| # ========== Example 4: Disconnected graph ========== | ||
| cat("========== Example 4: Disconnected Graph ==========\n\n") | ||
| graph4 <- matrix(c( | ||
| 0, 1, 0, 0, | ||
| 1, 0, 0, 0, | ||
| 0, 0, 0, 2, | ||
| 0, 0, 2, 0 | ||
| ), nrow = 4, byrow = TRUE) | ||
| cat("Disconnected graph adjacency matrix:\n") | ||
| print(graph4) | ||
| cat("\n") | ||
| mst4 <- prim_mst(graph4) | ||
| print_mst(mst4, graph4) | ||
|
|
||
| # ========== Example 5: Complete graph K4 ========== | ||
| cat("========== Example 5: Complete Graph K4 ==========\n\n") | ||
| graph5 <- matrix(c( | ||
| 0, 1, 2, 3, | ||
| 1, 0, 4, 5, | ||
| 2, 4, 0, 6, | ||
| 3, 5, 6, 0 | ||
| ), nrow = 4, byrow = TRUE) | ||
| cat("Complete graph K4:\n") | ||
| print(graph5) | ||
| cat("\n") | ||
| mst5 <- prim_mst(graph5) | ||
| print_mst(mst5, graph5) | ||
|
|
||
| # ========== Notes ========== | ||
| cat("========== Algorithm Properties ==========\n\n") | ||
| cat("1. Prim's algorithm guarantees finding the MST for connected graphs\n") | ||
| cat("2. Works only on undirected graphs with non-negative weights\n") | ||
| cat("3. MST has exactly (V-1) edges for a connected graph with V vertices\n") | ||
| cat("4. Total weight of MST is unique, but MST itself may not be unique\n") | ||
| cat("5. Starting vertex doesn't affect the total weight of the MST\n\n") | ||
|
|
||
| cat("========== Comparison with Kruskal's Algorithm ==========\n\n") | ||
| cat("Prim's Algorithm:\n") | ||
| cat(" - Starts from a vertex and grows the tree\n") | ||
| cat(" - Better for dense graphs (many edges)\n") | ||
| cat(" - O(V^2) with simple implementation\n\n") | ||
| cat("Kruskal's Algorithm:\n") | ||
| cat(" - Starts with edges sorted by weight\n") | ||
| cat(" - Better for sparse graphs (few edges)\n") | ||
| cat(" - O(E log E) or O(E log V)\n") | ||
siriak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.