Skip to content

Commit dc2e91c

Browse files
authored
Union-Find Data Structure (#113)
* subset struct for union-find * set union find operations * basic tests for union-find data structure
1 parent a90d4c9 commit dc2e91c

File tree

5 files changed

+119
-1
lines changed

5 files changed

+119
-1
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@
3030
*.exe
3131
*.out
3232
*.app
33+
34+
# ignore the build folder contents from git
35+
build/

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ add_executable(test_exe test/main.cpp
6060
test/PartitionTest.cpp
6161
test/DialTest.cpp
6262
test/GraphSlicingTest.cpp
63+
test/UnionFindTest.cpp
6364
)
6465
target_include_directories(test_exe PUBLIC
6566
"${PROJECT_SOURCE_DIR}/include"

include/Graph/Graph.hpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,25 @@ namespace CXXGRAPH
153153
*/
154154
virtual const AdjacencyMatrix<T> getAdjMatrix() const;
155155
/**
156+
* @brief This function finds the subset of given a nodeId
157+
* @param subset query subset, we want to find target in this subset
158+
* @param elem elem that we wish to find in the subset
159+
*
160+
* @return parent node of elem
161+
* Note: No Thread Safe
162+
*/
163+
virtual const unsigned long setFind(Subset subsets [], const unsigned long elem) const;
164+
/**
165+
* @brief This function modifies the original subset array
166+
* such that it the union of two sets a and b
167+
* @param subset query subset, we want to find target in this subset
168+
* @param a parent id of set1
169+
* @param b parent id of set2
170+
*
171+
* Note: No Thread Safe
172+
*/
173+
virtual void setUnion(Subset subsets [], const unsigned long set1, const unsigned long elem2) const;
174+
/**
156175
* @brief Function runs the dijkstra algorithm for some source node and
157176
* target node in the graph and returns the shortest distance of target
158177
* from the source.
@@ -864,6 +883,39 @@ namespace CXXGRAPH
864883
return 0;
865884
}
866885

886+
template <typename T>
887+
const unsigned long Graph<T>::setFind(Subset subsets [], const unsigned long nodeId) const
888+
{
889+
// find root and make root as parent of i
890+
// (path compression)
891+
if (subsets[nodeId].parent != nodeId)
892+
{
893+
subsets[nodeId].parent = Graph<T>::setFind(subsets, subsets[nodeId].parent);
894+
}
895+
896+
return subsets[nodeId].parent;
897+
}
898+
899+
template <typename T>
900+
void Graph<T>::setUnion(Subset subsets [], const unsigned long elem1, const unsigned long elem2) const
901+
{
902+
// if both sets have same parent
903+
// then there's nothing to be done
904+
if (subsets[elem1].parent==subsets[elem2].parent)
905+
return;
906+
auto elem1Parent = Graph<T>::setFind(subsets, elem1);
907+
auto elem2Parent = Graph<T>::setFind(subsets, elem2);
908+
if(subsets[elem1Parent].rank < subsets[elem2Parent].rank)
909+
subsets[elem1Parent].parent = elem2Parent;
910+
else if(subsets[elem1Parent].rank > subsets[elem2Parent].rank)
911+
subsets[elem2Parent].parent = elem1Parent;
912+
else
913+
{
914+
subsets[elem2Parent].parent = elem1Parent;
915+
subsets[elem1Parent].rank++;
916+
}
917+
}
918+
867919
template <typename T>
868920
const AdjacencyMatrix<T> Graph<T>::getAdjMatrix() const
869921
{

include/Utility/Typedef.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,15 @@ namespace CXXGRAPH
5656

5757
/////////////////////////////////////////////////////
5858
// Structures ///////////////////////////////////////
59-
59+
60+
/// Struct useful for union-find operations
61+
struct Subset_struct
62+
{
63+
unsigned long parent; // parent of the current set
64+
unsigned long rank; // rank of the current set, used for balancing the trees
65+
};
66+
typedef Subset_struct Subset;
67+
6068
/// Struct that contains the information about Dijsktra's Algorithm results
6169
struct DijkstraResult_struct
6270
{

test/UnionFindTest.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "gtest/gtest.h"
2+
#include "CXXGraph.hpp"
3+
4+
TEST(UnionFindTest, test_1)
5+
{
6+
CXXGRAPH::Node<int> node0(0, 0);
7+
CXXGRAPH::Node<int> node1(1, 1);
8+
CXXGRAPH::Node<int> node2(2, 2);
9+
CXXGRAPH::Node<int> node3(3, 3);
10+
11+
/*
12+
0
13+
1 2
14+
3
15+
*/
16+
CXXGRAPH::UndirectedWeightedEdge<int> edge1(0, node0, node1, 5);
17+
CXXGRAPH::UndirectedWeightedEdge<int> edge2(1, node0, node2, 10);
18+
CXXGRAPH::UndirectedWeightedEdge<int> edge3(2, node1, node3, 5);
19+
20+
std::list<const CXXGRAPH::Edge<int> *> edgeSet;
21+
edgeSet.push_back(&edge1);
22+
23+
CXXGRAPH::Graph<int> graph(edgeSet);
24+
25+
// every element is a subset of itself
26+
CXXGRAPH::Subset subset[4] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}};
27+
auto res = graph.setFind(subset, node0.getId());
28+
ASSERT_EQ(res, 0);
29+
res = graph.setFind(subset, node1.getId());
30+
ASSERT_EQ(res, 1);
31+
res = graph.setFind(subset, node2.getId());
32+
ASSERT_EQ(res, 2);
33+
34+
// element 1 & 2 are subset of 0
35+
// element 3 is subset of 1
36+
CXXGRAPH::Subset subset1[4] = {{0, 0}, {0, 0}, {0, 0}, {1, 0}};
37+
auto res1 = graph.setFind(subset1, node0.getId());
38+
ASSERT_EQ(res1, 0);
39+
res = graph.setFind(subset1, node3.getId());
40+
ASSERT_EQ(res1, 0);
41+
res = graph.setFind(subset1, node2.getId());
42+
ASSERT_EQ(res1, 0);
43+
44+
// union of (node 1 & node3) should increase node0 rank by 1
45+
CXXGRAPH::Subset subset2[4] = {{0, 0}, {0, 0}, {0, 0}, {1, 0}};
46+
graph.setUnion(subset2, node1.getId(), node3.getId());
47+
ASSERT_EQ(subset2[0].rank, 1);
48+
ASSERT_EQ(subset2[3].parent, 0);
49+
50+
// rank shouldn't increase since both have the same parent
51+
graph.setUnion(subset2, node2.getId(), node3.getId());
52+
ASSERT_EQ(subset2[0].rank, 1);
53+
ASSERT_EQ(subset2[3].parent, 0);
54+
}

0 commit comments

Comments
 (0)