From c6a3279b9bda52dea5c8972ec63ddf0052f2c514 Mon Sep 17 00:00:00 2001 From: Tim Maloney Date: Wed, 31 Mar 2021 01:36:12 -0700 Subject: [PATCH] feat: Prims algorithm (#815) * Added prim.c * Updated formatting in prim.c * Docs: updated prim.c documentation * feat: Included testing in prim.c * feat: eliminated globals & changed variable types * Docs: added documentation for minimum function * updating DIRECTORY.md * Updated documentation * Docs: Changed function docs & made test function static * Docs: made further requested changes Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 1 + greedy_approach/prim.c | 203 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 greedy_approach/prim.c diff --git a/DIRECTORY.md b/DIRECTORY.md index 86b0fd0d..3b8a713b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -134,6 +134,7 @@ ## Greedy Approach * [Djikstra](https://github.com/TheAlgorithms/C/blob/master/greedy_approach/djikstra.c) + * [Prim](https://github.com/TheAlgorithms/C/blob/master/greedy_approach/prim.c) ## Hash * [Hash Adler32](https://github.com/TheAlgorithms/C/blob/master/hash/hash_adler32.c) diff --git a/greedy_approach/prim.c b/greedy_approach/prim.c new file mode 100644 index 00000000..e4076a08 --- /dev/null +++ b/greedy_approach/prim.c @@ -0,0 +1,203 @@ +/** + * @file + * @author [Timothy Maloney](https://github.com/sl1mb0) + * @brief [Prim's algorithm](https://en.wikipedia.org/wiki/Prim%27s_algorithm) + * implementation in C to find the MST of a weighted, connected graph. + * @details Prim's algorithm uses a greedy approach to generate the MST of a weighted connected graph. + * The algorithm begins at an arbitrary vertex v, and selects a next vertex u, + * where v and u are connected by a weighted edge whose weight is the minimum of all edges connected to v. + * @references Page 319 "Introduction to the Design and Analysis of Algorithms" - Anany Levitin + * + * To test - run './prim -test' + * prim() will find the MST of the following adj. matrix: + * + * 0 1 2 3 + * 1 0 4 6 + * 2 4 0 5 + * 3 6 5 0 + * + * The minimum spanning tree for the above weighted connected graph is given by the following adj matrix: + * + * 0 1 2 3 + * 1 0 0 0 + * 2 0 0 0 + * 3 0 0 0 + * + * + * The following [link](https://visualgo.net/en/mst) provides a visual representation of graphs that can be used to test/verify the algorithm for different adj + * matrices and their weighted, connected graphs. + */ + +#include /// for IO operations +#include /// for string comparison +#include /// for assert() +#include /// for uint16_t + +#define MAX 20 +#define INF 999 + +/** + * @brief Finds index of minimum element in edge list for an arbitrary vertex + * @param arr graph row + * @param N number of elements in arr + * @returns index of minimum element in arr + */ +uint16_t minimum(uint16_t arr[], uint16_t N) +{ + uint16_t index = 0; + uint16_t min = INF; + + for (uint16_t i = 0; i < N; i++) + { + if (arr[i] < min) + { + min = arr[i]; + index = i; + } + } + return index; +} + +/** + * @brief Used to find MST of user-generated adj matrix G + * @returns void + */ +void prim(uint16_t G[][MAX], uint16_t MST[][MAX], uint16_t V) +{ + uint16_t u, v; + uint16_t E_t[MAX], path[MAX]; + uint16_t V_t[MAX], no_of_edges; + + E_t[0] = 0; // edges for current vertex + V_t[0] = 1; // list of visited vertices + + for (uint16_t i = 1; i < V; i++) + { + E_t[i] = G[i][0]; + path[i] = 0; + V_t[i] = 0; + } + + no_of_edges = V - 1; + + while (no_of_edges > 0) + { + u = minimum(E_t, V); + while (V_t[u] == 1) + { + E_t[u] = INF; + u = minimum(E_t, V); + } + + v = path[u]; + MST[v][u] = E_t[u]; + MST[u][v] = E_t[u]; + no_of_edges--; + V_t[u] = 1; + + for (uint16_t i = 1; i < V; i++) + { + if (V_t[i] == 0 && G[u][i] < E_t[i]) + { + E_t[i] = G[u][i]; + path[i] = v; + } + } + } +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test(uint16_t G[][MAX], uint16_t MST[][MAX], uint16_t V) +{ + + uint16_t test[4][4] = {{0,1,2,3},{1,0,4,6},{2,4,0,5},{3,6,5,0}}; + uint16_t solution[4][4] = {{0,1,2,3},{1,0,0,0},{2,0,0,0},{3,0,0,0}}; + + V = 4; + + for(uint16_t i = 0; i < V; ++i) + { + for(uint16_t j = 0; j < V; ++j) + { + G[i][j] = test[i][j]; + } + } + + prim(&(*G),&(*MST),V); + + for(uint16_t i = 0; i < V; ++i) + { + for(uint16_t j = 0; j < V; ++j) + { + assert(MST[i][j] == solution[i][j]); + } + } +} + +/** + * @brief Function user_graph(); + * gets user input adj. matrix and finds MST of that graph + * @returns void + */ +void user_graph(uint16_t G[][MAX], uint16_t MST[][MAX], uint16_t V) +{ + printf("Enter the number of vertices: "); + scanf(" %hd", &V); + + assert(V <= MAX); + + printf("Enter the adj matrix\n"); + uint16_t i, j; + for (i = 0; i < V; ++i) + { + for (j = 0; j < V; ++j) + { + printf("G[%d][%d]: ", i, j); + scanf(" %hd", &G[i][j]); + if (G[i][j] == 0) + G[i][j] = INF; + } + } + + prim(&(*G),&(*MST),V); + + printf("minimum spanning tree:\n"); + for (i = 0; i < V; ++i) + { + printf("\n"); + for (j = 0; j < V; ++j) + { + printf("%d\t", MST[i][j]); + } + } +} + + +/** + * @brief Main function + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ +int main(int argc, char const *argv[]) +{ + + uint16_t G[MAX][MAX]; ///< weighted, connected graph G + uint16_t MST[MAX][MAX]; ///< adj matrix to hold minimum spanning tree of G + uint16_t V; ///< number of vertices in V in G + + + if(argc == 2 && strcmp(argv[1],"-test") == 0) + { + test(&(*G),&(*MST),V); + } + else + { + user_graph(&(*G),&(*MST),V); + } + + return 0; +}