From 5c9750d97b33fba6a6103a632315578e5feec3cf Mon Sep 17 00:00:00 2001 From: Alvin Philips Date: Sun, 24 Oct 2021 20:49:27 +0530 Subject: [PATCH 1/2] fix: Intersection of two arrays (#1781) * Create reverse_binary_tree.cpp * Added documentation Added Documentation for the level_order_traversal() function, and implemented a print() function to display the tree to STDOUT * Added documentation * Renamed tests to test * Fixed issue with incorrect using statement * updating DIRECTORY.md * clang-format and clang-tidy fixes for fb86292d * Added Test cases * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal * Changed int to int64_t * Updated documentation wording * Reused code from union_of_two_arrays and modified for intersection * Fixed bug and corrected test output * Renamed file to better meet filename guidelines * updating DIRECTORY.md * clang-format and clang-tidy fixes for e653f77a * Changed integer type from int64_t to int32_t * Added reference to similar union_of_two_arrays file Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> --- DIRECTORY.md | 2 +- .../intersection_of_2_arrays.cpp | 26 --- .../intersection_of_two_arrays.cpp | 203 ++++++++++++++++++ 3 files changed, 204 insertions(+), 27 deletions(-) delete mode 100644 operations_on_datastructures/intersection_of_2_arrays.cpp create mode 100644 operations_on_datastructures/intersection_of_two_arrays.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 4480f7892..e8b2604d0 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -241,7 +241,7 @@ * [Circular Queue Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/circular_queue_using_array.cpp) * [Get Size Of Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/get_size_of_linked_list.cpp) * [Inorder Successor Of Bst](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/inorder_successor_of_bst.cpp) - * [Intersection Of 2 Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/intersection_of_2_arrays.cpp) + * [Intersection Of Two Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/intersection_of_two_arrays.cpp) * [Reverse A Linked List Using Recusion](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/reverse_a_linked_list_using_recusion.cpp) * [Reverse Binary Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/reverse_binary_tree.cpp) * [Selectionsortlinkedlist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/selectionsortlinkedlist.cpp) diff --git a/operations_on_datastructures/intersection_of_2_arrays.cpp b/operations_on_datastructures/intersection_of_2_arrays.cpp deleted file mode 100644 index 8a3b27edf..000000000 --- a/operations_on_datastructures/intersection_of_2_arrays.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include -int main() { - int i, j, m, n; - cout << "Enter size of array 1:"; - cin >> m; - cout << "Enter size of array 2:"; - cin >> n; - int a[m]; - int b[n]; - cout << "Enter elements of array 1:"; - for (i = 0; i < m; i++) cin >> a[i]; - for (i = 0; i < n; i++) cin >> b[i]; - i = 0; - j = 0; - while ((i < m) && (j < n)) { - if (a[i] < b[j]) - i++; - else if (a[i] > b[j]) - j++; - else { - cout << a[i++] << " "; - j++; - } - } - return 0; -} diff --git a/operations_on_datastructures/intersection_of_two_arrays.cpp b/operations_on_datastructures/intersection_of_two_arrays.cpp new file mode 100644 index 000000000..c660f505b --- /dev/null +++ b/operations_on_datastructures/intersection_of_two_arrays.cpp @@ -0,0 +1,203 @@ +/** + * @file + * @brief Implementation for the [Intersection of two sorted + * Arrays](https://en.wikipedia.org/wiki/Intersection_(set_theory)) + * algorithm. + * @details The intersection of two arrays is the collection of all the elements + * that are common in both the first and second arrays. This implementation uses + * ordered arrays, and an algorithm to correctly order them and return the + * result as a new array (vector). + * @see union_of_two_arrays.cpp + * @author [Alvin](https://github.com/polarvoid) + */ + +#include /// for std::sort +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace operations_on_datastructures + * @brief Operations on Data Structures + */ +namespace operations_on_datastructures { + +/** + * @brief Prints the values of a vector sequentially, ending with a newline + * character. + * @param array Reference to the array to be printed + * @returns void + */ +void print(const std::vector &array) { + for (int32_t i : array) { + std::cout << i << " "; /// Print each value in the array + } + std::cout << "\n"; /// Print newline +} + +/** + * @brief Gets the intersection of two sorted arrays, and returns them in a + * vector. + * @details An algorithm is used that compares the elements of the two vectors, + * incrementing the index of the smaller of the two. If the elements are the + * same, the element is appended to the result array to be returned. + * @param first A std::vector of sorted integer values + * @param second A std::vector of sorted integer values + * @returns A std::vector of the intersection of the two arrays, in ascending + * order + */ +std::vector get_intersection(const std::vector &first, + const std::vector &second) { + std::vector res; ///< Vector to hold the intersection + size_t f_index = 0; ///< Index for the first array + size_t s_index = 0; ///< Index for the second array + size_t f_length = first.size(); ///< Length of first array + size_t s_length = second.size(); ///< Length of second array + + while (f_index < f_length && s_index < s_length) { + if (first[f_index] < second[s_index]) { + f_index++; ///< Increment index of second array + } else if (first[f_index] > second[s_index]) { + s_index++; ///< Increment index of second array + } else { + if ((res.size() == 0) || (first[f_index] != res.back())) { + res.push_back( + first[f_index]); ///< Add the element if it is unique + } + f_index++; ///< Increment index of first array + s_index++; ///< Increment index of second array too + } + } + return res; +} + +} // namespace operations_on_datastructures + +/** + * @namespace tests + * @brief Testcases to check intersection of Two Arrays. + */ +namespace tests { +using operations_on_datastructures::get_intersection; +using operations_on_datastructures::print; +/** + * @brief A Test to check an edge case (two empty arrays) + * @returns void + */ +void test1() { + std::cout << "TEST CASE 1\n"; + std::cout << "Intialized a = {} b = {}\n"; + std::cout << "Expected result: {}\n"; + std::vector a = {}; + std::vector b = {}; + std::vector result = get_intersection(a, b); + assert(result == a); ///< Check if result is empty + print(result); ///< Should only print newline + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check an edge case (one empty array) + * @returns void + */ +void test2() { + std::cout << "TEST CASE 2\n"; + std::cout << "Intialized a = {} b = {2, 3}\n"; + std::cout << "Expected result: {}\n"; + std::vector a = {}; + std::vector b = {2, 3}; + std::vector result = get_intersection(a, b); + assert(result == a); ///< Check if result is equal to a + print(result); ///< Should only print newline + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with a simple test case + * @returns void + */ +void test3() { + std::cout << "TEST CASE 3\n"; + std::cout << "Intialized a = {4, 6} b = {3, 6}\n"; + std::cout << "Expected result: {6}\n"; + std::vector a = {4, 6}; + std::vector b = {3, 6}; + std::vector result = get_intersection(a, b); + std::vector expected = {6}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 6 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with duplicate values + * @returns void + */ +void test4() { + std::cout << "TEST CASE 4\n"; + std::cout << "Intialized a = {4, 6, 6, 6} b = {2, 4, 4, 6}\n"; + std::cout << "Expected result: {4, 6}\n"; + std::vector a = {4, 6, 6, 6}; + std::vector b = {2, 4, 4, 6}; + std::vector result = get_intersection(a, b); + std::vector expected = {4, 6}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 4 6 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with a harder test case + * @returns void + */ +void test5() { + std::cout << "TEST CASE 5\n"; + std::cout << "Intialized a = {1, 2, 3, 4, 6, 7, 9} b = {2, 3, 4, 5}\n"; + std::cout << "Expected result: {2, 3, 4}\n"; + std::vector a = {1, 2, 3, 4, 6, 7, 9}; + std::vector b = {2, 3, 4, 5}; + std::vector result = get_intersection(a, b); + std::vector expected = {2, 3, 4}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 2 3 4 + std::cout << "TEST PASSED!\n\n"; +} +/** + * @brief A Test to check correct functionality with an array sorted using + * std::sort + * @returns void + */ +void test6() { + std::cout << "TEST CASE 6\n"; + std::cout << "Intialized a = {1, 3, 3, 2, 5, 9, 4, 7, 3, 2} "; + std::cout << "b = {11, 3, 7, 8, 6}\n"; + std::cout << "Expected result: {3, 7}\n"; + std::vector a = {1, 3, 3, 2, 5, 9, 4, 7, 3, 2}; + std::vector b = {11, 3, 7, 8, 6}; + std::sort(a.begin(), a.end()); ///< Sort vector a + std::sort(b.begin(), b.end()); ///< Sort vector b + std::vector result = get_intersection(a, b); + std::vector expected = {3, 7}; + assert(result == expected); ///< Check if result is correct + print(result); ///< Should print 3 7 + std::cout << "TEST PASSED!\n\n"; +} +} // namespace tests + +/** + * @brief Function to test the correctness of get_intersection() function + * @returns void + */ +static void test() { + tests::test1(); + tests::test2(); + tests::test3(); + tests::test4(); + tests::test5(); + tests::test6(); +} + +/** + * @brief main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} From f821fae69861ac638f1ea27509feed88b86705ae Mon Sep 17 00:00:00 2001 From: Aayush Vyas <1830002@kiit.ac.in> Date: Sun, 24 Oct 2021 21:11:13 +0530 Subject: [PATCH 2/2] feat : add Class Based DSU for Path Compression O(1) & Union Rank O(logN) (#1571) * Add files via upload # Class Based DSU -Using Path Compression to get the best time complexity O(1) -Using Union Rank to keep track of changes using parent(p) O(logN) * Class based DSU : Path Compression O(1) and Union Rank O(logN) * made changes to satisfy the meets of the PR changes made to satisfy the needs of the PR - used base lib instead of - changed all stdin's and included pre-declared test cases * removed stdin for testing * changed file name from upper case to lower case * made necessary changes * Delete DSU_union_rank.cpp * Delete DSU_path_compresssion.cpp * added explicit to contructors, return 0, n=dec * Delete dsu_path_compresssion.cpp * added documentations, to match the typical structure Added @brief @details @author @param @returns * Update data_structures/dsu_union_rank.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_union_rank.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * added self-implementation test cases, changed int to uint64_t * std::cout after assert * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_union_rank.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * updating DIRECTORY.md * clang-format and clang-tidy fixes for b8c37d09 * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * documentation changes * Update dsu_union_rank.cpp * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_union_rank.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_union_rank.cpp Co-authored-by: David Leal * Update data_structures/dsu_union_rank.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 18843179 * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_path_compression.cpp Co-authored-by: David Leal * Update data_structures/dsu_union_rank.cpp Co-authored-by: David Leal * clang-format and clang-tidy fixes for 5c24d9a9 * Update data_structures/dsu_union_rank.cpp Co-authored-by: David Leal Co-authored-by: David Leal Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com> Co-authored-by: Ayaan Khan --- DIRECTORY.md | 2 + data_structures/dsu_path_compression.cpp | 213 +++++++++++++++++++++++ data_structures/dsu_union_rank.cpp | 187 ++++++++++++++++++++ 3 files changed, 402 insertions(+) create mode 100644 data_structures/dsu_path_compression.cpp create mode 100644 data_structures/dsu_union_rank.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index e8b2604d0..7c2e6956b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -46,6 +46,8 @@ * [Main Cll](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/cll/main_cll.cpp) * [Disjoint Set](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/disjoint_set.cpp) * [Doubly Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/doubly_linked_list.cpp) + * [Dsu Path Compression](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/dsu_path_compression.cpp) + * [Dsu Union Rank](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/dsu_union_rank.cpp) * [Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/linked_list.cpp) * [Linkedlist Implentation Usingarray](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/linkedlist_implentation_usingarray.cpp) * [List Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/list_array.cpp) diff --git a/data_structures/dsu_path_compression.cpp b/data_structures/dsu_path_compression.cpp new file mode 100644 index 000000000..a5c0aec33 --- /dev/null +++ b/data_structures/dsu_path_compression.cpp @@ -0,0 +1,213 @@ +/** + * @file + * @brief [DSU (Disjoint + * sets)](https://en.wikipedia.org/wiki/Disjoint-set-data_structure) + * @details + * It is a very powerful data structure that keeps track of different + * clusters(sets) of elements, these sets are disjoint(doesnot have a common + * element). Disjoint sets uses cases : for finding connected components in a + * graph, used in Kruskal's algorithm for finding Minimum Spanning tree. + * Operations that can be performed: + * 1) UnionSet(i,j): add(element i and j to the set) + * 2) findSet(i): returns the representative of the set to which i belogngs to. + * 3) get_max(i),get_min(i) : returns the maximum and minimum + * Below is the class-based approach which uses the heuristic of path + * compression. Using path compression in findSet(i),we are able to get to the + * representative of i in O(1) time. + * @author [AayushVyasKIIT](https://github.com/AayushVyasKIIT) + * @see dsu_union_rank.cpp + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +using std::cout; +using std::endl; +using std::vector; + +/** + * @brief Disjoint sets union data structure, class based representation. + * @param n number of elements + */ +class dsu { + private: + vector p; ///< keeps track of the parent of ith element + vector depth; ///< tracks the depth(rank) of i in the tree + vector setSize; ///< size of each chunk(set) + vector maxElement; ///< maximum of each set to which i belongs to + vector minElement; ///< minimum of each set to which i belongs to + public: + /** + * @brief contructor for initialising all data members. + * @param n number of elements + */ + explicit dsu(uint64_t n) { + p.assign(n, 0); + /// initially, all of them are their own parents + for (uint64_t i = 0; i < n; i++) { + p[i] = i; + } + /// initially all have depth are equals to zero + depth.assign(n, 0); + maxElement.assign(n, 0); + minElement.assign(n, 0); + for (uint64_t i = 0; i < n; i++) { + depth[i] = 0; + maxElement[i] = i; + minElement[i] = i; + } + setSize.assign(n, 0); + /// initially set size will be equals to one + for (uint64_t i = 0; i < n; i++) { + setSize[i] = 1; + } + } + + /** + * @brief Method to find the representative of the set to which i belongs + * to, T(n) = O(1) + * @param i element of some set + * @returns representative of the set to which i belongs to. + */ + uint64_t findSet(uint64_t i) { + /// using path compression + if (p[i] == i) { + return i; + } + return (p[i] = findSet(p[i])); + } + /** + * @brief Method that combines two disjoint sets to which i and j belongs to + * and make a single set having a common representative. + * @param i element of some set + * @param j element of some set + * @returns void + */ + void UnionSet(uint64_t i, uint64_t j) { + /// check if both belongs to the same set or not + if (isSame(i, j)) { + return; + } + + // we find the representative of the i and j + uint64_t x = findSet(i); + uint64_t y = findSet(j); + + /// always keeping the min as x + /// shallow tree + if (depth[x] > depth[y]) { + std::swap(x, y); + } + /// making the shallower root's parent the deeper root + p[x] = y; + + /// if same depth, then increase one's depth + if (depth[x] == depth[y]) { + depth[y]++; + } + /// total size of the resultant set + setSize[y] += setSize[x]; + /// changing the maximum elements + maxElement[y] = std::max(maxElement[x], maxElement[y]); + minElement[y] = std::min(minElement[x], minElement[y]); + } + /** + * @brief A utility function which check whether i and j belongs to + * same set or not + * @param i element of some set + * @param j element of some set + * @returns `true` if element `i` and `j` ARE in the same set + * @returns `false` if element `i` and `j` are NOT in same set + */ + bool isSame(uint64_t i, uint64_t j) { + if (findSet(i) == findSet(j)) { + return true; + } + return false; + } + /** + * @brief prints the minimum, maximum and size of the set to which i belongs + * to + * @param i element of some set + * @returns void + */ + vector get(uint64_t i) { + vector ans; + ans.push_back(get_min(i)); + ans.push_back(get_max(i)); + ans.push_back(size(i)); + return ans; + } + /** + * @brief A utility function that returns the size of the set to which i + * belongs to + * @param i element of some set + * @returns size of the set to which i belongs to + */ + uint64_t size(uint64_t i) { return setSize[findSet(i)]; } + /** + * @brief A utility function that returns the max element of the set to + * which i belongs to + * @param i element of some set + * @returns maximum of the set to which i belongs to + */ + uint64_t get_max(uint64_t i) { return maxElement[findSet(i)]; } + /** + * @brief A utility function that returns the min element of the set to + * which i belongs to + * @param i element of some set + * @returns minimum of the set to which i belongs to + */ + uint64_t get_min(uint64_t i) { return minElement[findSet(i)]; } +}; + +/** + * @brief Self-test implementations, 1st test + * @returns void + */ +static void test1() { + // the minimum, maximum, and size of the set + uint64_t n = 10; ///< number of items + dsu d(n + 1); ///< object of class disjoint sets + // set 1 + d.UnionSet(1, 2); // performs union operation on 1 and 2 + d.UnionSet(1, 4); // performs union operation on 1 and 4 + vector ans = {1, 4, 3}; + for (uint64_t i = 0; i < ans.size(); i++) { + assert(d.get(4).at(i) == ans[i]); // makes sure algorithm works fine + } + cout << "1st test passed!" << endl; +} +/** + * @brief Self-implementations, 2nd test + * @returns void + */ +static void test2() { + // the minimum, maximum, and size of the set + uint64_t n = 10; ///< number of items + dsu d(n + 1); ///< object of class disjoint sets + // set 1 + d.UnionSet(3, 5); + d.UnionSet(5, 6); + d.UnionSet(5, 7); + vector ans = {3, 7, 4}; + for (uint64_t i = 0; i < ans.size(); i++) { + assert(d.get(3).at(i) == ans[i]); // makes sure algorithm works fine + } + cout << "2nd test passed!" << endl; +} + +/** + * @brief Main function + * @returns 0 on exit + * */ +int main() { + uint64_t n = 10; ///< number of items + dsu d(n + 1); ///< object of class disjoint sets + + test1(); // run 1st test case + test2(); // run 2nd test case + + return 0; +} diff --git a/data_structures/dsu_union_rank.cpp b/data_structures/dsu_union_rank.cpp new file mode 100644 index 000000000..8936d6d69 --- /dev/null +++ b/data_structures/dsu_union_rank.cpp @@ -0,0 +1,187 @@ +/** + * @file + * @brief [DSU (Disjoint + * sets)](https://en.wikipedia.org/wiki/Disjoint-set-data_structure) + * @details + * dsu : It is a very powerful data structure which keeps track of different + * clusters(sets) of elements, these sets are disjoint(doesnot have a common + * element). Disjoint sets uses cases : for finding connected components in a + * graph, used in Kruskal's algorithm for finding Minimum Spanning tree. + * Operations that can be performed: + * 1) UnionSet(i,j): add(element i and j to the set) + * 2) findSet(i): returns the representative of the set to which i belogngs to. + * 3) getParents(i): prints the parent of i and so on and so forth. + * Below is the class-based approach which uses the heuristic of union-ranks. + * Using union-rank in findSet(i),we are able to get to the representative of i + * in slightly delayed O(logN) time but it allows us to keep tracks of the + * parent of i. + * @author [AayushVyasKIIT](https://github.com/AayushVyasKIIT) + * @see dsu_path_compression.cpp + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +using std::cout; +using std::endl; +using std::vector; + +/** + * @brief Disjoint sets union data structure, class based representation. + * @param n number of elements + */ +class dsu { + private: + vector p; ///< keeps track of the parent of ith element + vector depth; ///< tracks the depth(rank) of i in the tree + vector setSize; ///< size of each chunk(set) + public: + /** + * @brief constructor for initialising all data members + * @param n number of elements + */ + explicit dsu(uint64_t n) { + p.assign(n, 0); + /// initially all of them are their own parents + depth.assign(n, 0); + setSize.assign(n, 0); + for (uint64_t i = 0; i < n; i++) { + p[i] = i; + depth[i] = 0; + setSize[i] = 1; + } + } + /** + * @brief Method to find the representative of the set to which i belongs + * to, T(n) = O(logN) + * @param i element of some set + * @returns representative of the set to which i belongs to + */ + uint64_t findSet(uint64_t i) { + /// using union-rank + while (i != p[i]) { + i = p[i]; + } + return i; + } + /** + * @brief Method that combines two disjoint sets to which i and j belongs to + * and make a single set having a common representative. + * @param i element of some set + * @param j element of some set + * @returns void + */ + void unionSet(uint64_t i, uint64_t j) { + /// checks if both belongs to same set or not + if (isSame(i, j)) { + return; + } + /// we find representative of the i and j + uint64_t x = findSet(i); + uint64_t y = findSet(j); + + /// always keeping the min as x + /// in order to create a shallow tree + if (depth[x] > depth[y]) { + std::swap(x, y); + } + /// making the shallower tree, root parent of the deeper root + p[x] = y; + + /// if same depth, then increase one's depth + if (depth[x] == depth[y]) { + depth[y]++; + } + /// total size of the resultant set + setSize[y] += setSize[x]; + } + /** + * @brief A utility function which check whether i and j belongs to same set + * or not + * @param i element of some set + * @param j element of some set + * @returns `true` if element i and j are in same set + * @returns `false` if element i and j are not in same set + */ + bool isSame(uint64_t i, uint64_t j) { + if (findSet(i) == findSet(j)) { + return true; + } + return false; + } + /** + * @brief Method to print all the parents of i, or the path from i to + * representative. + * @param i element of some set + * @returns void + */ + vector getParents(uint64_t i) { + vector ans; + while (p[i] != i) { + ans.push_back(i); + i = p[i]; + } + ans.push_back(i); + return ans; + } +}; +/** + * @brief Self-implementations, 1st test + * @returns void + */ +static void test1() { + /* checks the parents in the resultant structures */ + uint64_t n = 10; ///< number of elements + dsu d(n + 1); ///< object of class disjoint sets + d.unionSet(2, 1); ///< performs union operation on 1 and 2 + d.unionSet(1, 4); + d.unionSet(8, 1); + d.unionSet(3, 5); + d.unionSet(5, 6); + d.unionSet(5, 7); + d.unionSet(9, 10); + d.unionSet(2, 10); + // keeping track of the changes using parent pointers + vector ans = {7, 5}; + for (uint64_t i = 0; i < ans.size(); i++) { + assert(d.getParents(7).at(i) == + ans[i]); // makes sure algorithm works fine + } + cout << "1st test passed!" << endl; +} +/** + * @brief Self-implementations, 2nd test + * @returns void + */ +static void test2() { + // checks the parents in the resultant structures + uint64_t n = 10; ///< number of elements + dsu d(n + 1); ///< object of class disjoint sets + d.unionSet(2, 1); /// performs union operation on 1 and 2 + d.unionSet(1, 4); + d.unionSet(8, 1); + d.unionSet(3, 5); + d.unionSet(5, 6); + d.unionSet(5, 7); + d.unionSet(9, 10); + d.unionSet(2, 10); + + /// keeping track of the changes using parent pointers + vector ans = {2, 1, 10}; + for (uint64_t i = 0; i < ans.size(); i++) { + assert(d.getParents(2).at(i) == + ans[i]); /// makes sure algorithm works fine + } + cout << "2nd test passed!" << endl; +} +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test1(); // run 1st test case + test2(); // run 2nd test case + + return 0; +}