-
Notifications
You must be signed in to change notification settings - Fork 35
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
Add minimum spanning tree algorithm #22
Changes from all commits
63adf9e
ede23c9
26fbf69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
#pragma once | ||
|
||
#include <graaflib/graph.h> | ||
#include <graaflib/types.h> | ||
|
||
#include <algorithm> | ||
#include <utility> | ||
#include <vector> | ||
|
||
namespace graaf::algorithm { | ||
|
||
// Helper struct for representing disjoint sets | ||
struct DisjointSet { | ||
std::vector<vertex_id_t> parent; | ||
std::vector<size_t> rank; | ||
|
||
DisjointSet(size_t num_vertices) { | ||
parent.resize(num_vertices); | ||
rank.resize(num_vertices, 0); | ||
for (vertex_id_t i = 0; i < num_vertices; ++i) parent[i] = i; | ||
} | ||
|
||
vertex_id_t find(vertex_id_t vertex) { | ||
if (vertex != parent[vertex]) parent[vertex] = find(parent[vertex]); | ||
return parent[vertex]; | ||
} | ||
|
||
void union_sets(vertex_id_t vertex1, vertex_id_t vertex2) { | ||
vertex_id_t root1 = find(vertex1); | ||
vertex_id_t root2 = find(vertex2); | ||
if (root1 != root2) { | ||
if (rank[root1] < rank[root2]) std::swap(root1, root2); | ||
parent[root2] = root1; | ||
if (rank[root1] == rank[root2]) ++rank[root1]; | ||
} | ||
} | ||
}; | ||
|
||
template <typename V, typename E, graph_spec S> | ||
std::vector<std::pair<vertex_id_t, vertex_id_t>> minimum_spanning_tree( | ||
const graph<V, E, S>& graph) { | ||
using Edge = std::pair<edge_weight_t, std::pair<vertex_id_t, vertex_id_t>>; | ||
Comment on lines
+38
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, could you move the implementation to the Maybe you could take a look at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done sir |
||
std::vector<Edge> edges; | ||
|
||
// Populate the edges vector with all edges in the graph | ||
for (vertex_id_t source = 0; source < graph.num_vertices(); ++source) { | ||
for (auto edge : graph.get_outgoing_edges(source)) { | ||
vertex_id_t target = edge.target; | ||
edge_weight_t weight = edge.weight; | ||
edges.push_back({weight, {source, target}}); | ||
} | ||
} | ||
|
||
// Sort the edges in ascending order based on their weights | ||
std::sort(edges.begin(), edges.end()); | ||
|
||
// Initialize the minimum spanning tree and the disjoint set | ||
std::vector<std::pair<vertex_id_t, vertex_id_t>> minimum_spanning_tree; | ||
DisjointSet disjoint_set(graph.num_vertices()); | ||
|
||
// Perform Kruskal's algorithm | ||
for (const auto& edge : edges) { | ||
vertex_id_t source = edge.second.first; | ||
vertex_id_t target = edge.second.second; | ||
|
||
if (disjoint_set.find(source) != disjoint_set.find(target)) { | ||
disjoint_set.union_sets(source, target); | ||
minimum_spanning_tree.push_back({source, target}); | ||
} | ||
} | ||
|
||
return minimum_spanning_tree; | ||
} | ||
|
||
} // namespace graaf::algorithm |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#include "minimum_spanning_tree.h" | ||
|
||
namespace graaf::algorithm { | ||
|
||
// No additional implementation is required for this example | ||
// as the entire implementation is already provided in the header file. | ||
|
||
} // namespace graaf::algorithm |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,70 @@ | ||||||||||
#include <cassert> | ||||||||||
#include <iostream> | ||||||||||
|
||||||||||
#include "minimum_spanning_tree.h" | ||||||||||
Comment on lines
+3
to
+4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #include <graaflib/algorithm/minimum_spanning_tree.h> Getting this error again : - graaflib/algorithm/minimum_spanning_tree.h: No such file or directory |
||||||||||
|
||||||||||
void testMinimumSpanningTree() { | ||||||||||
// Test Case 1: Empty graph | ||||||||||
{ | ||||||||||
graaf::graph<int, int> graph; | ||||||||||
auto result = graaf::algorithm::minimum_spanning_tree(graph); | ||||||||||
assert(result.empty()); | ||||||||||
} | ||||||||||
|
||||||||||
// Test Case 2: Single vertex | ||||||||||
{ | ||||||||||
graaf::graph<int, int> graph; | ||||||||||
graph.add_vertex(0); | ||||||||||
auto result = graaf::algorithm::minimum_spanning_tree(graph); | ||||||||||
assert(result.empty()); | ||||||||||
} | ||||||||||
|
||||||||||
// Test Case 3: Linear graph | ||||||||||
{ | ||||||||||
graaf::graph<int, int> graph; | ||||||||||
graph.add_vertex(0); | ||||||||||
graph.add_vertex(1); | ||||||||||
graph.add_vertex(2); | ||||||||||
graph.add_vertex(3); | ||||||||||
graph.add_edge(0, 1, 2); | ||||||||||
graph.add_edge(1, 2, 3); | ||||||||||
graph.add_edge(2, 3, 4); | ||||||||||
auto result = graaf::algorithm::minimum_spanning_tree(graph); | ||||||||||
std::vector<std::pair<graaf::vertex_id_t, graaf::vertex_id_t>> expected{ | ||||||||||
{0, 1}, {1, 2}, {2, 3}}; | ||||||||||
assert(result == expected); | ||||||||||
} | ||||||||||
|
||||||||||
// Test Case 4: Complete graph | ||||||||||
{ | ||||||||||
graaf::graph<int, int> graph; | ||||||||||
graph.add_vertex(0); | ||||||||||
graph.add_vertex(1); | ||||||||||
graph.add_vertex(2); | ||||||||||
graph.add_edge(0, 1, 2); | ||||||||||
graph.add_edge(0, 2, 1); | ||||||||||
graph.add_edge(1, 2, 3); | ||||||||||
auto result = graaf::algorithm::minimum_spanning_tree(graph); | ||||||||||
std::vector<std::pair<graaf::vertex_id_t, graaf::vertex_id_t>> expected{ | ||||||||||
{0, 2}, {0, 1}}; | ||||||||||
assert(result == expected); | ||||||||||
} | ||||||||||
|
||||||||||
// Test Case 5: Graph with disconnected components | ||||||||||
{ | ||||||||||
graaf::graph<int, int> graph; | ||||||||||
graph.add_vertex(0); | ||||||||||
graph.add_vertex(1); | ||||||||||
graph.add_vertex(2); | ||||||||||
graph.add_vertex(3); | ||||||||||
graph.add_edge(0, 1, 2); | ||||||||||
graph.add_edge(2, 3, 3); | ||||||||||
auto result = graaf::algorithm::minimum_spanning_tree(graph); | ||||||||||
std::vector<std::pair<graaf::vertex_id_t, graaf::vertex_id_t>> expected{ | ||||||||||
{0, 1}, {2, 3}}; | ||||||||||
assert(result == expected); | ||||||||||
} | ||||||||||
|
||||||||||
// If no assert fails print - | ||||||||||
std::cout << "All tests passed!\n"; | ||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we put this in a namespace
detail
? I think it can also be moved tominimum_spanning_tree.tpp
to keep the interface in the header file as clean as possible.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This I have done