|
| 1 | +# Prim's Minimum Spanning Tree Algorithm |
| 2 | +# |
| 3 | +# The Prim algorithm finds the Minimum Spanning Tree (MST) of a connected, undirected, weighted graph. |
| 4 | +# It starts from a source vertex and grows the MST by adding the smallest-weight edge connecting |
| 5 | +# the MST to a new vertex. |
| 6 | +# |
| 7 | +# Time Complexity: O(V^2) with adjacency matrix, can be O(E log V) with priority queue |
| 8 | +# Space Complexity: O(V) |
| 9 | +# |
| 10 | +# Input: graph as an adjacency list where each entry is a list of edges with fields |
| 11 | +# `vertex` and `weight`, and `source` vertex index (integer) |
| 12 | +# Output: A list containing MST edges, total weight |
| 13 | + |
| 14 | +prim_mst <- function(graph, source = 1) { |
| 15 | + all_vertices <- unique(c(names(graph), unlist(lapply(graph, function(x) sapply(x, function(e) e$vertex))))) |
| 16 | + all_vertices <- as.numeric(all_vertices) |
| 17 | + num_vertices <- max(all_vertices) |
| 18 | + |
| 19 | + in_mst <- rep(FALSE, num_vertices) |
| 20 | + key <- rep(Inf, num_vertices) |
| 21 | + parent <- rep(-1, num_vertices) |
| 22 | + |
| 23 | + key[source] <- 0 |
| 24 | + |
| 25 | + for (i in 1:num_vertices) { |
| 26 | + # Pick the minimum key vertex not in MST |
| 27 | + u <- which.min(ifelse(in_mst, Inf, key)) |
| 28 | + |
| 29 | + in_mst[u] <- TRUE |
| 30 | + |
| 31 | + # Update keys and parents for adjacent vertices |
| 32 | + for (edge in graph[[as.character(u)]]) { |
| 33 | + v <- edge$vertex |
| 34 | + w <- edge$weight |
| 35 | + if (!in_mst[v] && w < key[v]) { |
| 36 | + key[v] <- w |
| 37 | + parent[v] <- u |
| 38 | + } |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + # Build MST edges |
| 43 | + mst_edges <- list() |
| 44 | + total_weight <- 0 |
| 45 | + for (v in 1:num_vertices) { |
| 46 | + if (parent[v] != -1) { |
| 47 | + mst_edges <- append(mst_edges, list(list(from = parent[v], to = v, weight = key[v]))) |
| 48 | + total_weight <- total_weight + key[v] |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + return(list( |
| 53 | + edges = mst_edges, |
| 54 | + total_weight = total_weight |
| 55 | + )) |
| 56 | +} |
| 57 | + |
| 58 | +# Example usage |
| 59 | +cat("=== Prim's Minimum Spanning Tree Algorithm ===\n") |
| 60 | + |
| 61 | +# Example undirected graph |
| 62 | +# Graph structure: |
| 63 | +# 1 --2--> 2 |
| 64 | +# 1 --3--> 3 |
| 65 | +# 2 --1--> 3 |
| 66 | +# 2 --4--> 4 |
| 67 | +# 3 --5--> 4 |
| 68 | +prim_graph <- list( |
| 69 | + "1" = list(list(vertex = 2, weight = 2), list(vertex = 3, weight = 3)), |
| 70 | + "2" = list(list(vertex = 1, weight = 2), list(vertex = 3, weight = 1), list(vertex = 4, weight = 4)), |
| 71 | + "3" = list(list(vertex = 1, weight = 3), list(vertex = 2, weight = 1), list(vertex = 4, weight = 5)), |
| 72 | + "4" = list(list(vertex = 2, weight = 4), list(vertex = 3, weight = 5)) |
| 73 | +) |
| 74 | + |
| 75 | +cat("Graph (adjacency list):\n") |
| 76 | +for (v in names(prim_graph)) { |
| 77 | + edges <- prim_graph[[v]] |
| 78 | + edge_strs <- sapply(edges, function(e) paste0(e$vertex, "(", e$weight, ")")) |
| 79 | + cat("Vertex", v, "-> [", paste(edge_strs, collapse = ", "), "]\n") |
| 80 | +} |
| 81 | + |
| 82 | +cat("\nRunning Prim's MST from vertex 1:\n") |
| 83 | +mst_result <- prim_mst(prim_graph, 1) |
| 84 | +cat("MST edges:\n") |
| 85 | +for (edge in mst_result$edges) { |
| 86 | + cat(edge$from, "--", edge$weight, "-->", edge$to, "\n") |
| 87 | +} |
| 88 | +cat("Total weight of MST:", mst_result$total_weight, "\n") |
0 commit comments