mirror of
https://hub.njuu.cf/TheAlgorithms/C-Plus-Plus.git
synced 2023-10-11 13:05:55 +08:00
feat: Add the Subarray Sum implementation (#1527)
* Create subarray_sum.cpp * updating DIRECTORY.md * clang-format and clang-tidy fixes for0a293ece
* Update backtracking/subarray_sum.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * clang-format and clang-tidy fixes forf37f7b7c
* Update backtracking/subarray_sum.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update subarray_sum.cpp * clang-format and clang-tidy fixes for9b0b5f87
* Update backtracking/subarray_sum.cpp * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * clang-format and clang-tidy fixes for047366a8
* Update subarray_sum.cpp * clang-format and clang-tidy fixes for512b1887
* Update backtracking/subarray_sum.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update backtracking/subarray_sum.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * fix: Apply suggestions from code review * docs: Apply suggestions from code review * clang-format and clang-tidy fixes fore6979047
Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal <halfpacho@gmail.com>
This commit is contained in:
parent
0e0ba5fc89
commit
f34f93e77a
@ -8,6 +8,7 @@
|
||||
* [N Queens All Solution Optimised](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/n_queens_all_solution_optimised.cpp)
|
||||
* [Nqueen Print All Solutions](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/nqueen_print_all_solutions.cpp)
|
||||
* [Rat Maze](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/rat_maze.cpp)
|
||||
* [Subarray Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/subarray_sum.cpp)
|
||||
* [Subset Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/subset_sum.cpp)
|
||||
* [Sudoku Solve](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/sudoku_solve.cpp)
|
||||
|
||||
|
@ -1,22 +1,24 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief prints the assigned colors
|
||||
* using [Graph Coloring](https://en.wikipedia.org/wiki/Graph_coloring) algorithm
|
||||
* using [Graph Coloring](https://en.wikipedia.org/wiki/Graph_coloring)
|
||||
* algorithm
|
||||
*
|
||||
* @details
|
||||
* In graph theory, graph coloring is a special case of graph labeling;
|
||||
* it is an assignment of labels traditionally called "colors" to elements of a graph subject to certain constraints.
|
||||
* In its simplest form, it is a way of coloring the vertices of a graph such that no two adjacent vertices are of the same color;
|
||||
* this is called a vertex coloring. Similarly, an edge coloring assigns
|
||||
* a color to each edge so that no two adjacent edges are of the same color,
|
||||
* and a face coloring of a planar graph assigns a color to each face or
|
||||
* In graph theory, graph coloring is a special case of graph labeling;
|
||||
* it is an assignment of labels traditionally called "colors" to elements of a
|
||||
* graph subject to certain constraints. In its simplest form, it is a way of
|
||||
* coloring the vertices of a graph such that no two adjacent vertices are of
|
||||
* the same color; this is called a vertex coloring. Similarly, an edge coloring
|
||||
* assigns a color to each edge so that no two adjacent edges are of the same
|
||||
* color, and a face coloring of a planar graph assigns a color to each face or
|
||||
* region so that no two faces that share a boundary have the same color.
|
||||
*
|
||||
* @author [Anup Kumar Panwar](https://github.com/AnupKumarPanwar)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
@ -24,70 +26,72 @@
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/** A utility function to print solution
|
||||
* @tparam V number of vertices in the graph
|
||||
* @param color array of colors assigned to the nodes
|
||||
*/
|
||||
template <size_t V>
|
||||
void printSolution(const std::array <int, V>& color) {
|
||||
std::cout << "Following are the assigned colors" << std::endl;
|
||||
for (auto &col : color) {
|
||||
std::cout << col;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
/** A utility function to print solution
|
||||
* @tparam V number of vertices in the graph
|
||||
* @param color array of colors assigned to the nodes
|
||||
*/
|
||||
template <size_t V>
|
||||
void printSolution(const std::array<int, V>& color) {
|
||||
std::cout << "Following are the assigned colors" << std::endl;
|
||||
for (auto& col : color) {
|
||||
std::cout << col;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/** A utility function to check if the current color assignment is safe for
|
||||
* vertex v
|
||||
* @tparam V number of vertices in the graph
|
||||
* @param v index of graph vertex to check
|
||||
* @param graph matrix of graph nonnectivity
|
||||
* @param color vector of colors assigned to the graph nodes/vertices
|
||||
* @param c color value to check for the node `v`
|
||||
* @returns `true` if the color is safe to be assigned to the node
|
||||
* @returns `false` if the color is not safe to be assigned to the node
|
||||
*/
|
||||
template <size_t V>
|
||||
bool isSafe(int v, const std::array<std::array <int, V>, V>& graph, const std::array <int, V>& color, int c) {
|
||||
for (int i = 0; i < V; i++) {
|
||||
if (graph[v][i] && c == color[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** A recursive utility function to solve m coloring problem
|
||||
* @tparam V number of vertices in the graph
|
||||
* @param graph matrix of graph nonnectivity
|
||||
* @param m number of colors
|
||||
* @param [in,out] color description // used in,out to notify in documentation
|
||||
* that this parameter gets modified by the function
|
||||
* @param v index of graph vertex to check
|
||||
*/
|
||||
template <size_t V>
|
||||
void graphColoring(const std::array<std::array <int, V>, V>& graph, int m, std::array <int, V> color, int v) {
|
||||
// base case:
|
||||
// If all vertices are assigned a color then return true
|
||||
if (v == V) {
|
||||
backtracking::printSolution<V>(color);
|
||||
return;
|
||||
}
|
||||
|
||||
// Consider this vertex v and try different colors
|
||||
for (int c = 1; c <= m; c++) {
|
||||
// Check if assignment of color c to v is fine
|
||||
if (backtracking::isSafe<V>(v, graph, color, c)) {
|
||||
color[v] = c;
|
||||
|
||||
// recur to assign colors to rest of the vertices
|
||||
backtracking::graphColoring<V>(graph, m, color, v + 1);
|
||||
|
||||
// If assigning color c doesn't lead to a solution then remove it
|
||||
color[v] = 0;
|
||||
}
|
||||
/** A utility function to check if the current color assignment is safe for
|
||||
* vertex v
|
||||
* @tparam V number of vertices in the graph
|
||||
* @param v index of graph vertex to check
|
||||
* @param graph matrix of graph nonnectivity
|
||||
* @param color vector of colors assigned to the graph nodes/vertices
|
||||
* @param c color value to check for the node `v`
|
||||
* @returns `true` if the color is safe to be assigned to the node
|
||||
* @returns `false` if the color is not safe to be assigned to the node
|
||||
*/
|
||||
template <size_t V>
|
||||
bool isSafe(int v, const std::array<std::array<int, V>, V>& graph,
|
||||
const std::array<int, V>& color, int c) {
|
||||
for (int i = 0; i < V; i++) {
|
||||
if (graph[v][i] && c == color[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** A recursive utility function to solve m coloring problem
|
||||
* @tparam V number of vertices in the graph
|
||||
* @param graph matrix of graph nonnectivity
|
||||
* @param m number of colors
|
||||
* @param [in,out] color description // used in,out to notify in documentation
|
||||
* that this parameter gets modified by the function
|
||||
* @param v index of graph vertex to check
|
||||
*/
|
||||
template <size_t V>
|
||||
void graphColoring(const std::array<std::array<int, V>, V>& graph, int m,
|
||||
std::array<int, V> color, int v) {
|
||||
// base case:
|
||||
// If all vertices are assigned a color then return true
|
||||
if (v == V) {
|
||||
backtracking::printSolution<V>(color);
|
||||
return;
|
||||
}
|
||||
|
||||
// Consider this vertex v and try different colors
|
||||
for (int c = 1; c <= m; c++) {
|
||||
// Check if assignment of color c to v is fine
|
||||
if (backtracking::isSafe<V>(v, graph, color, c)) {
|
||||
color[v] = c;
|
||||
|
||||
// recur to assign colors to rest of the vertices
|
||||
backtracking::graphColoring<V>(graph, m, color, v + 1);
|
||||
|
||||
// If assigning color c doesn't lead to a solution then remove it
|
||||
color[v] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
@ -102,15 +106,12 @@ int main() {
|
||||
// (0)---(1)
|
||||
|
||||
const int V = 4; // number of vertices in the graph
|
||||
std::array <std::array <int, V>, V> graph = {
|
||||
std::array <int, V>({0, 1, 1, 1}),
|
||||
std::array <int, V>({1, 0, 1, 0}),
|
||||
std::array <int, V>({1, 1, 0, 1}),
|
||||
std::array <int, V>({1, 0, 1, 0})
|
||||
};
|
||||
std::array<std::array<int, V>, V> graph = {
|
||||
std::array<int, V>({0, 1, 1, 1}), std::array<int, V>({1, 0, 1, 0}),
|
||||
std::array<int, V>({1, 1, 0, 1}), std::array<int, V>({1, 0, 1, 0})};
|
||||
|
||||
int m = 3; // Number of colors
|
||||
std::array <int, V> color{};
|
||||
std::array<int, V> color{};
|
||||
|
||||
backtracking::graphColoring<V>(graph, m, color, 0);
|
||||
return 0;
|
||||
|
117
backtracking/subarray_sum.cpp
Normal file
117
backtracking/subarray_sum.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Subset-sum](https://en.wikipedia.org/wiki/Subset_sum_problem) (only
|
||||
* continuous subsets) problem
|
||||
* @details We are given an array and a sum value. The algorithms find all
|
||||
* the subarrays of that array with sum equal to the given sum and return such
|
||||
* subarrays count. This approach will have \f$O(n)\f$ time complexity and
|
||||
* \f$O(n)\f$ space complexity. NOTE: In this problem, we are only referring to
|
||||
* the continuous subsets as subarrays everywhere. Subarrays can be created
|
||||
* using deletion operation at the end of the front of an array only. The parent
|
||||
* array is also counted in subarrays having 0 number of deletion operations.
|
||||
*
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <unordered_map> /// for unordered_map
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace subarray_sum
|
||||
* @brief Functions for the [Subset
|
||||
* sum](https://en.wikipedia.org/wiki/Subset_sum_problem) implementation
|
||||
*/
|
||||
namespace subarray_sum {
|
||||
/**
|
||||
* @brief The main function that implements the count of the subarrays
|
||||
* @param sum is the required sum of any subarrays
|
||||
* @param in_arr is the input array
|
||||
* @returns count of the number of subsets with required sum
|
||||
*/
|
||||
uint64_t subarray_sum(int64_t sum, const std::vector<int64_t> &in_arr) {
|
||||
int64_t nelement = in_arr.size();
|
||||
int64_t count_of_subset = 0;
|
||||
int64_t current_sum = 0;
|
||||
std::unordered_map<int64_t, int64_t>
|
||||
sumarray; // to store the subarrays count
|
||||
// frequency having some sum value
|
||||
|
||||
for (int64_t i = 0; i < nelement; i++) {
|
||||
current_sum += in_arr[i];
|
||||
|
||||
if (current_sum == sum) {
|
||||
count_of_subset++;
|
||||
}
|
||||
// If in case current_sum is greater than the required sum
|
||||
if (sumarray.find(current_sum - sum) != sumarray.end()) {
|
||||
count_of_subset += (sumarray[current_sum - sum]);
|
||||
}
|
||||
sumarray[current_sum]++;
|
||||
}
|
||||
return count_of_subset;
|
||||
}
|
||||
} // namespace subarray_sum
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::cout << "1st test ";
|
||||
std::vector<int64_t> array1 = {-7, -3, -2, 5, 8}; // input array
|
||||
assert(
|
||||
backtracking::subarray_sum::subarray_sum(0, array1) ==
|
||||
1); // first argument in subarray_sum function is the required sum and
|
||||
// second is the input array, answer is the subarray {(-3,-2,5)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 2nd test
|
||||
std::cout << "2nd test ";
|
||||
std::vector<int64_t> array2 = {1, 2, 3, 3};
|
||||
assert(backtracking::subarray_sum::subarray_sum(6, array2) ==
|
||||
2); // here we are expecting 2 subsets which sum up to 6 i.e.
|
||||
// {(1,2,3),(3,3)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 3rd test
|
||||
std::cout << "3rd test ";
|
||||
std::vector<int64_t> array3 = {1, 1, 1, 1};
|
||||
assert(backtracking::subarray_sum::subarray_sum(1, array3) ==
|
||||
4); // here we are expecting 4 subsets which sum up to 1 i.e.
|
||||
// {(1),(1),(1),(1)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 4rd test
|
||||
std::cout << "4th test ";
|
||||
std::vector<int64_t> array4 = {3, 3, 3, 3};
|
||||
assert(backtracking::subarray_sum::subarray_sum(6, array4) ==
|
||||
3); // here we are expecting 3 subsets which sum up to 6 i.e.
|
||||
// {(3,3),(3,3),(3,3)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 5th test
|
||||
std::cout << "5th test ";
|
||||
std::vector<int64_t> array5 = {};
|
||||
assert(backtracking::subarray_sum::subarray_sum(6, array5) ==
|
||||
0); // here we are expecting 0 subsets which sum up to 6 i.e. we
|
||||
// cannot select anything from an empty array
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
@ -1,43 +1,45 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Iterative version of Preorder, Postorder, and preorder [Traversal of the Tree]
|
||||
* (https://en.wikipedia.org/wiki/Tree_traversal)
|
||||
* @brief Iterative version of Preorder, Postorder, and preorder [Traversal of
|
||||
* the Tree] (https://en.wikipedia.org/wiki/Tree_traversal)
|
||||
* @author [Motasim](https://github.com/motasimmakki)
|
||||
* @details
|
||||
*
|
||||
*
|
||||
* ### Iterative Preorder Traversal of a tree
|
||||
* Create a Stack that will store the Node of Tree.
|
||||
* Push the root node into the stack.
|
||||
* Save the root into the variabe named as current, and pop and elemnt from the stack.
|
||||
* Store the data of current into the result array, and start traversing from it.
|
||||
* Push both the child node of the current node into the stack, first right child then left child.
|
||||
* Repeat the same set of steps untill the Stack becomes empty.
|
||||
* And return the result array as the preorder traversal of a tree.
|
||||
*
|
||||
* Save the root into the variabe named as current, and pop and elemnt from the
|
||||
* stack. Store the data of current into the result array, and start traversing
|
||||
* from it. Push both the child node of the current node into the stack, first
|
||||
* right child then left child. Repeat the same set of steps untill the Stack
|
||||
* becomes empty. And return the result array as the preorder traversal of a
|
||||
* tree.
|
||||
*
|
||||
* ### Iterative Postorder Traversal of a tree
|
||||
* Create a Stack that will store the Node of Tree.
|
||||
* Push the root node into the stack.
|
||||
* Save the root into the variabe named as current, and pop and elemnt from the stack.
|
||||
* Store the data of current into the result array, and start traversing from it.
|
||||
* Push both the child node of the current node into the stack, first left child then right child.
|
||||
* Repeat the same set of steps untill the Stack becomes empty.
|
||||
* Now reverse the result array and then return it to the calling function as a postorder traversal of a tree.
|
||||
*
|
||||
* Save the root into the variabe named as current, and pop and elemnt from the
|
||||
* stack. Store the data of current into the result array, and start traversing
|
||||
* from it. Push both the child node of the current node into the stack, first
|
||||
* left child then right child. Repeat the same set of steps untill the Stack
|
||||
* becomes empty. Now reverse the result array and then return it to the calling
|
||||
* function as a postorder traversal of a tree.
|
||||
*
|
||||
* ### Iterative Inorder Traversal of a tree
|
||||
* Create a Stack that will store the Node of Tree.
|
||||
* Push the root node into the stack.
|
||||
* Save the root into the variabe named as current.
|
||||
* Now iterate and take the current to the extreme left of the tree by traversing only to its left.
|
||||
* Pop the elemnt from the stack and assign it to the current.
|
||||
* Store the data of current into the result array.
|
||||
* Repeat the same set of steps until the Stack becomes empty or the current becomes NULL.
|
||||
* And return the result array as the inorder traversal of a tree.
|
||||
* Now iterate and take the current to the extreme left of the tree by
|
||||
* traversing only to its left. Pop the elemnt from the stack and assign it to
|
||||
* the current. Store the data of current into the result array. Repeat the same
|
||||
* set of steps until the Stack becomes empty or the current becomes NULL. And
|
||||
* return the result array as the inorder traversal of a tree.
|
||||
*/
|
||||
#include <algorithm> /// for `reverse`
|
||||
#include <cassert> /// for `assert`
|
||||
#include <iostream> /// for I/O operations
|
||||
#include <stack> /// for `stack`
|
||||
#include <vector> /// for `vector`
|
||||
#include <algorithm> /// for `reverse`
|
||||
#include <cassert> /// for `assert`
|
||||
|
||||
/**
|
||||
* @namespace others
|
||||
@ -46,35 +48,44 @@
|
||||
namespace others {
|
||||
/**
|
||||
* @namespace iterative_tree_traversals
|
||||
* @brief Functions for the [Traversal of the Tree](https://en.wikipedia.org/wiki/Tree_traversal) algorithm
|
||||
* @brief Functions for the [Traversal of the
|
||||
* Tree](https://en.wikipedia.org/wiki/Tree_traversal) algorithm
|
||||
*/
|
||||
namespace iterative_tree_traversals {
|
||||
/**
|
||||
* @brief defines the structure of a node of the tree
|
||||
*/
|
||||
struct Node {
|
||||
int64_t data = 0; ///< The value/key of the node.
|
||||
struct Node *left; ///< struct pointer to left subtree.
|
||||
struct Node *right; ///< struct pointer to right subtree.
|
||||
int64_t data = 0; ///< The value/key of the node.
|
||||
struct Node *left{}; ///< struct pointer to left subtree.
|
||||
struct Node *right{}; ///< struct pointer to right subtree.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief defines the functions associated with the binary tree
|
||||
*/
|
||||
class BinaryTree {
|
||||
public:
|
||||
Node *createNewNode(int64_t); ///< function that will create new node for insertion.
|
||||
std::vector<int64_t> preOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its preorder traversal.
|
||||
std::vector<int64_t> postOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its postorder traversal.
|
||||
std::vector<int64_t> inOrderIterative(Node *); ///< function that takes root of the tree as an argument, and returns its inorder traversal.
|
||||
public:
|
||||
Node *createNewNode(
|
||||
int64_t); ///< function that will create new node for insertion.
|
||||
std::vector<int64_t> preOrderIterative(
|
||||
Node *); ///< function that takes root of the tree as an argument, and
|
||||
///< returns its preorder traversal.
|
||||
std::vector<int64_t> postOrderIterative(
|
||||
Node *); ///< function that takes root of the tree as an argument, and
|
||||
///< returns its postorder traversal.
|
||||
std::vector<int64_t> inOrderIterative(
|
||||
Node *); ///< function that takes root of the tree as an argument, and
|
||||
///< returns its inorder traversal.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief will allocate the memory for a node and, along the data and return the node.
|
||||
* @brief will allocate the memory for a node and, along the data and return the
|
||||
* node.
|
||||
* @param data value that a particular node will contain.
|
||||
* @return pointer to the newly created node with assigned data.
|
||||
* @return pointer to the newly created node with assigned data.
|
||||
*/
|
||||
Node * BinaryTree::createNewNode(int64_t data) {
|
||||
Node *BinaryTree::createNewNode(int64_t data) {
|
||||
Node *node = new Node();
|
||||
node->data = data;
|
||||
node->left = node->right = nullptr;
|
||||
@ -82,85 +93,91 @@ Node * BinaryTree::createNewNode(int64_t data) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief preOrderIterative() function that will perform the preorder traversal iteratively,
|
||||
* and return the result array that contain the preorder traversal of a tree.
|
||||
* @brief preOrderIterative() function that will perform the preorder traversal
|
||||
* iteratively, and return the result array that contain the preorder traversal
|
||||
* of a tree.
|
||||
* @param root head/root node of a tree
|
||||
* @return result that is containing the preorder traversal of a tree
|
||||
*/
|
||||
std::vector<int64_t> BinaryTree::preOrderIterative(Node *root) {
|
||||
std::stack<Node *> stack; ///< is used to find and traverse the child nodes.
|
||||
std::vector<int64_t> BinaryTree::preOrderIterative(Node *root) {
|
||||
std::stack<Node *>
|
||||
stack; ///< is used to find and traverse the child nodes.
|
||||
std::vector<int64_t> result; ///< list of values, sorted in pre-order.
|
||||
|
||||
|
||||
stack.push(root);
|
||||
|
||||
while(!stack.empty()) {
|
||||
|
||||
while (!stack.empty()) {
|
||||
result.push_back(stack.top()->data);
|
||||
Node *current = stack.top();
|
||||
stack.pop();
|
||||
|
||||
if(current->right) {
|
||||
|
||||
if (current->right) {
|
||||
stack.push(current->right);
|
||||
}
|
||||
if(current->left) {
|
||||
if (current->left) {
|
||||
stack.push(current->left);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief postOrderIterative() function that will perform the postorder traversal iteratively,
|
||||
* and return the result array that contain the postorder traversal of a tree.
|
||||
* @brief postOrderIterative() function that will perform the postorder
|
||||
* traversal iteratively, and return the result array that contain the postorder
|
||||
* traversal of a tree.
|
||||
* @param root head/root node of a tree
|
||||
* @return result that is containing the postorder traversal of a tree
|
||||
*/
|
||||
std::vector<int64_t> BinaryTree::postOrderIterative(Node *root) {
|
||||
std::stack<Node *> stack; ///< is used to find and traverse the child nodes.
|
||||
std::vector<int64_t> BinaryTree::postOrderIterative(Node *root) {
|
||||
std::stack<Node *>
|
||||
stack; ///< is used to find and traverse the child nodes.
|
||||
std::vector<int64_t> result; ///< List of values, sorted in post-order.
|
||||
|
||||
|
||||
stack.push(root);
|
||||
|
||||
while(!stack.empty()) {
|
||||
|
||||
while (!stack.empty()) {
|
||||
result.push_back(stack.top()->data);
|
||||
Node *current = stack.top();
|
||||
stack.pop();
|
||||
|
||||
if(current->left) {
|
||||
|
||||
if (current->left) {
|
||||
stack.push(current->left);
|
||||
}
|
||||
if(current->right) {
|
||||
if (current->right) {
|
||||
stack.push(current->right);
|
||||
}
|
||||
}
|
||||
|
||||
reverse(result.begin(), result.end());
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief inOrderIterative() function that will perform the inorder traversal iteratively,
|
||||
* and return the result array that contain the inorder traversal of a tree.
|
||||
* @brief inOrderIterative() function that will perform the inorder traversal
|
||||
* iteratively, and return the result array that contain the inorder traversal
|
||||
* of a tree.
|
||||
* @param root head/root node of a tree
|
||||
* @return result that is containing the inorder traversal of a tree
|
||||
*/
|
||||
std::vector<int64_t> BinaryTree::inOrderIterative(Node *root) {
|
||||
std::stack<Node *> stack; ///< is used to find and traverse the child nodes.
|
||||
std::stack<Node *>
|
||||
stack; ///< is used to find and traverse the child nodes.
|
||||
std::vector<int64_t> result; ///< List of values, sorted in in-order.
|
||||
|
||||
Node *current = root;
|
||||
|
||||
while(!stack.empty() || current) {
|
||||
while(current) {
|
||||
|
||||
while (!stack.empty() || current) {
|
||||
while (current) {
|
||||
stack.push(current);
|
||||
current = current->left;
|
||||
}
|
||||
current = stack.top();
|
||||
stack.pop();
|
||||
result.push_back(current->data);
|
||||
stack.pop();
|
||||
result.push_back(current->data);
|
||||
current = current->right;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace iterative_tree_traversals
|
||||
@ -171,22 +188,25 @@ std::vector<int64_t> BinaryTree::inOrderIterative(Node *root) {
|
||||
* @param binaryTree instance of the BinaryTree class
|
||||
* @param root head/root node of a tree
|
||||
*/
|
||||
static void test1(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){
|
||||
static void test1(others::iterative_tree_traversals::BinaryTree binaryTree,
|
||||
others::iterative_tree_traversals::Node *root) {
|
||||
std::vector<int64_t> actual_result{1, 2, 4, 5, 3};
|
||||
std::vector<int64_t> result; ///< result stores the preorder traversal of the binary tree
|
||||
std::vector<int64_t>
|
||||
result; ///< result stores the preorder traversal of the binary tree
|
||||
|
||||
// Calling preOrderIterative() function by passing a root node,
|
||||
// and storing the preorder traversal in result.
|
||||
result = binaryTree.preOrderIterative(root);
|
||||
result = binaryTree.preOrderIterative(root);
|
||||
|
||||
// Self-testing the result using `assert`
|
||||
for(int i = 0; i < result.size(); i++)
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
assert(actual_result[i] == result[i]);
|
||||
}
|
||||
|
||||
// Printing the result storing preorder.
|
||||
std::cout<< "\nPreOrder Traversal Is : "<< std::endl;
|
||||
for(auto i: result) {
|
||||
std::cout<< i<< " ";
|
||||
std::cout << "\nPreOrder Traversal Is : " << std::endl;
|
||||
for (auto i : result) {
|
||||
std::cout << i << " ";
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,22 +215,25 @@ static void test1(others::iterative_tree_traversals::BinaryTree binaryTree, othe
|
||||
* @param binaryTree instance of BinaryTree class
|
||||
* @param root head/root node of a tree
|
||||
*/
|
||||
static void test2(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){
|
||||
static void test2(others::iterative_tree_traversals::BinaryTree binaryTree,
|
||||
others::iterative_tree_traversals::Node *root) {
|
||||
std::vector<int64_t> actual_result{4, 5, 2, 3, 1};
|
||||
std::vector<int64_t> result; ///< result stores the postorder traversal of the binary tree.
|
||||
std::vector<int64_t>
|
||||
result; ///< result stores the postorder traversal of the binary tree.
|
||||
|
||||
// Calling postOrderIterative() function by passing a root node,
|
||||
// and storing the postorder traversal in result.
|
||||
result = binaryTree.postOrderIterative(root);
|
||||
|
||||
// Self-testing the result using `assert`
|
||||
for(int i = 0; i < result.size(); i++)
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
assert(actual_result[i] == result[i]);
|
||||
}
|
||||
|
||||
// Printing the result storing postorder.
|
||||
std::cout<< "\nPostOrder Traversal Is : "<< std::endl;
|
||||
for(auto i: result) {
|
||||
std::cout<< i<< " ";
|
||||
std::cout << "\nPostOrder Traversal Is : " << std::endl;
|
||||
for (auto i : result) {
|
||||
std::cout << i << " ";
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,22 +242,25 @@ static void test2(others::iterative_tree_traversals::BinaryTree binaryTree, othe
|
||||
* @param binaryTree instance of BinaryTree class
|
||||
* @param root head/root node of a tree
|
||||
*/
|
||||
static void test3(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){
|
||||
static void test3(others::iterative_tree_traversals::BinaryTree binaryTree,
|
||||
others::iterative_tree_traversals::Node *root) {
|
||||
std::vector<int64_t> actual_result{4, 2, 5, 1, 3};
|
||||
std::vector<int64_t> result; ///< result stores the inorder traversal of the binary tree.
|
||||
std::vector<int64_t>
|
||||
result; ///< result stores the inorder traversal of the binary tree.
|
||||
|
||||
// Calling inOrderIterative() function by passing a root node,
|
||||
// and storing the inorder traversal in result.
|
||||
result = binaryTree.inOrderIterative(root);
|
||||
|
||||
// Self-testing the result using `assert`
|
||||
for(int i = 0; i < result.size(); i++)
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
assert(actual_result[i] == result[i]);
|
||||
}
|
||||
|
||||
// Printing the result storing inorder.
|
||||
std::cout<< "\nInOrder Traversal Is : "<< std::endl;
|
||||
for(auto i: result) {
|
||||
std::cout<< i<< " ";
|
||||
std::cout << "\nInOrder Traversal Is : " << std::endl;
|
||||
for (auto i : result) {
|
||||
std::cout << i << " ";
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,46 +269,53 @@ static void test3(others::iterative_tree_traversals::BinaryTree binaryTree, othe
|
||||
* @param binaryTree instance of BinaryTree class
|
||||
* @param root head/root node of a tree
|
||||
*/
|
||||
static void test4(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){
|
||||
static void test4(others::iterative_tree_traversals::BinaryTree binaryTree,
|
||||
others::iterative_tree_traversals::Node *root) {
|
||||
std::vector<int64_t> actual_result{-1, -2, -4, -5, -3};
|
||||
std::vector<int64_t> result; ///< result stores the preorder traversal of the binary tree
|
||||
std::vector<int64_t>
|
||||
result; ///< result stores the preorder traversal of the binary tree
|
||||
|
||||
// Calling preOrderIterative() function by passing a root node,
|
||||
// and storing the preorder traversal in result.
|
||||
result = binaryTree.preOrderIterative(root);
|
||||
result = binaryTree.preOrderIterative(root);
|
||||
|
||||
// Self-testing the result using `assert`
|
||||
for(int i = 0; i < result.size(); i++)
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
assert(actual_result[i] == result[i]);
|
||||
}
|
||||
|
||||
// Printing the result storing preorder.
|
||||
std::cout<< "\nPreOrder Traversal Is : "<< std::endl;
|
||||
for(auto i: result) {
|
||||
std::cout<< i<< " ";
|
||||
std::cout << "\nPreOrder Traversal Is : " << std::endl;
|
||||
for (auto i : result) {
|
||||
std::cout << i << " ";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test the computed postorder with the actual postorder on negative value.
|
||||
* @brief Test the computed postorder with the actual postorder on negative
|
||||
* value.
|
||||
* @param binaryTree instance of BinaryTree class
|
||||
* @param root head/root node of a tree
|
||||
*/
|
||||
static void test5(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){
|
||||
static void test5(others::iterative_tree_traversals::BinaryTree binaryTree,
|
||||
others::iterative_tree_traversals::Node *root) {
|
||||
std::vector<int64_t> actual_result{-4, -5, -2, -3, -1};
|
||||
std::vector<int64_t> result; ///< result stores the postorder traversal of the binary tree.
|
||||
std::vector<int64_t>
|
||||
result; ///< result stores the postorder traversal of the binary tree.
|
||||
|
||||
// Calling postOrderIterative() function by passing a root node,
|
||||
// and storing the postorder traversal in result.
|
||||
result = binaryTree.postOrderIterative(root);
|
||||
|
||||
// Self-testing the result using `assert`
|
||||
for(int i = 0; i < result.size(); i++)
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
assert(actual_result[i] == result[i]);
|
||||
}
|
||||
|
||||
// Printing the result storing postorder.
|
||||
std::cout<< "\nPostOrder Traversal Is : "<< std::endl;
|
||||
for(auto i: result) {
|
||||
std::cout<< i<< " ";
|
||||
std::cout << "\nPostOrder Traversal Is : " << std::endl;
|
||||
for (auto i : result) {
|
||||
std::cout << i << " ";
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,22 +324,25 @@ static void test5(others::iterative_tree_traversals::BinaryTree binaryTree, othe
|
||||
* @param binaryTree instance of BinaryTree class
|
||||
* @param root head/root node of a tree
|
||||
*/
|
||||
static void test6(others::iterative_tree_traversals::BinaryTree binaryTree, others::iterative_tree_traversals::Node *root){
|
||||
static void test6(others::iterative_tree_traversals::BinaryTree binaryTree,
|
||||
others::iterative_tree_traversals::Node *root) {
|
||||
std::vector<int64_t> actual_result{-4, -2, -5, -1, -3};
|
||||
std::vector<int64_t> result; ///< result stores the inorder traversal of the binary tree.
|
||||
std::vector<int64_t>
|
||||
result; ///< result stores the inorder traversal of the binary tree.
|
||||
|
||||
// Calling inOrderIterative() function by passing a root node,
|
||||
// and storing the inorder traversal in result.
|
||||
result = binaryTree.inOrderIterative(root);
|
||||
|
||||
// Self-testing the result using `assert`
|
||||
for(int i = 0; i < result.size(); i++)
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
assert(actual_result[i] == result[i]);
|
||||
}
|
||||
|
||||
// Printing the result storing inorder.
|
||||
std::cout<< "\nInOrder Traversal Is : "<< std::endl;
|
||||
for(auto i: result) {
|
||||
std::cout<< i<< " ";
|
||||
std::cout << "\nInOrder Traversal Is : " << std::endl;
|
||||
for (auto i : result) {
|
||||
std::cout << i << " ";
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,7 +352,7 @@ static void test6(others::iterative_tree_traversals::BinaryTree binaryTree, othe
|
||||
*/
|
||||
int main() {
|
||||
// Creating a tree with the following structure,
|
||||
/*
|
||||
/*
|
||||
1
|
||||
/ \
|
||||
2 3
|
||||
@ -324,22 +360,24 @@ int main() {
|
||||
4 5
|
||||
*/
|
||||
|
||||
others::iterative_tree_traversals::BinaryTree binaryTree; ///< instace of BinaryTree, used to access its members functions.
|
||||
others::iterative_tree_traversals::BinaryTree
|
||||
binaryTree; ///< instace of BinaryTree, used to access its members
|
||||
///< functions.
|
||||
others::iterative_tree_traversals::Node *root = binaryTree.createNewNode(1);
|
||||
root->left = binaryTree.createNewNode(2);
|
||||
root->right = binaryTree.createNewNode(3);
|
||||
root->left->left = binaryTree.createNewNode(4);
|
||||
root->left->right = binaryTree.createNewNode(5);
|
||||
|
||||
std::cout<< "\n| Tests for positive data value |"<< std::endl;
|
||||
std::cout << "\n| Tests for positive data value |" << std::endl;
|
||||
test1(binaryTree, root); // run preorder-iterative test
|
||||
std::cout<< "\nPre-order test Passed!"<< std::endl;
|
||||
std::cout << "\nPre-order test Passed!" << std::endl;
|
||||
|
||||
test2(binaryTree, root); // run postorder-iterative test
|
||||
std::cout<< "\nPost-order test Passed!"<< std::endl;
|
||||
std::cout << "\nPost-order test Passed!" << std::endl;
|
||||
|
||||
test3(binaryTree, root); // run inorder-iterative test
|
||||
std::cout<< "\nIn-order test Passed!"<< std::endl;
|
||||
std::cout << "\nIn-order test Passed!" << std::endl;
|
||||
|
||||
// Modifying tree for negative values.
|
||||
root->data = -1;
|
||||
@ -348,15 +386,15 @@ int main() {
|
||||
root->left->left->data = -4;
|
||||
root->left->right->data = -5;
|
||||
|
||||
std::cout<< "\n| Tests for negative data values |"<< std::endl;
|
||||
std::cout << "\n| Tests for negative data values |" << std::endl;
|
||||
test4(binaryTree, root); // run preorder-iterative test on negative values
|
||||
std::cout<< "\nPre-order test on-negative value Passed!"<< std::endl;
|
||||
std::cout << "\nPre-order test on-negative value Passed!" << std::endl;
|
||||
|
||||
test5(binaryTree, root); // run postorder-iterative test on negative values
|
||||
std::cout<< "\nPost-order test on-negative value Passed!"<< std::endl;
|
||||
std::cout << "\nPost-order test on-negative value Passed!" << std::endl;
|
||||
|
||||
test6(binaryTree, root); // run inorder-iterative test on negative values
|
||||
std::cout<< "\nIn-order test on-negative value Passed!"<< std::endl;
|
||||
std::cout << "\nIn-order test on-negative value Passed!" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,44 +1,55 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Random Pivot Quick Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation) algorithm.
|
||||
* @brief Implementation of the [Random Pivot Quick
|
||||
* Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation)
|
||||
* algorithm.
|
||||
* @details
|
||||
* * A random pivot quick sort algorithm is pretty much same as quick sort with a difference of having a logic of
|
||||
* selecting next pivot element from the input array.
|
||||
* * Where in quick sort is fast, but still can give you the time complexity of O(n^2) in worst case.
|
||||
* * To avoid hitting the time complexity of O(n^2), we use the logic of randomize the selection process of pivot
|
||||
* element.
|
||||
* * A random pivot quick sort algorithm is pretty much same as quick
|
||||
* sort with a difference of having a logic of selecting next pivot element from
|
||||
* the input array.
|
||||
* * Where in quick sort is fast, but still can give you the time
|
||||
* complexity of O(n^2) in worst case.
|
||||
* * To avoid hitting the time complexity of O(n^2), we use the logic
|
||||
* of randomize the selection process of pivot element.
|
||||
*
|
||||
* ### Logic
|
||||
* * The logic is pretty simple, the only change is in the partitioning algorithm, which is selecting the
|
||||
* pivot element.
|
||||
* * Instead of selecting the last or the first element from array for pivot we use a random index to select
|
||||
* pivot element.
|
||||
* * This avoids hitting the O(n^2) time complexity in practical use cases.
|
||||
* * The logic is pretty simple, the only change is in the
|
||||
* partitioning algorithm, which is selecting the pivot element.
|
||||
* * Instead of selecting the last or the first element from array
|
||||
* for pivot we use a random index to select pivot element.
|
||||
* * This avoids hitting the O(n^2) time complexity in practical
|
||||
* use cases.
|
||||
*
|
||||
* ### Partition Logic
|
||||
* * Partitions are done such as numbers lower than the "pivot" element is arranged on the left side of the "pivot",
|
||||
* and number larger than the "pivot" element are arranged on the right part of the array.
|
||||
* * Partitions are done such as numbers lower than the "pivot"
|
||||
* element is arranged on the left side of the "pivot", and number larger than
|
||||
* the "pivot" element are arranged on the right part of the array.
|
||||
*
|
||||
* ### Algorithm
|
||||
* * Select the pivot element randomly using getRandomIndex() function from this namespace.
|
||||
* * Initialize the pInd (partition index) from the start of the array.
|
||||
* * Loop through the array from start to less than end. (from start to < end).
|
||||
* (Inside the loop) :-
|
||||
* * Check if the current element (arr[i]) is less than the pivot element in each iteration.
|
||||
* * If current element in the iteration is less than the pivot element,
|
||||
* then swap the elements at current index (i) and partition index (pInd) and increment the partition index by one.
|
||||
* * At the end of the loop, swap the pivot element with partition index element.
|
||||
* * Select the pivot element randomly using getRandomIndex() function
|
||||
* from this namespace.
|
||||
* * Initialize the pInd (partition index) from the start of the
|
||||
* array.
|
||||
* * Loop through the array from start to less than end. (from start
|
||||
* to < end). (Inside the loop) :-
|
||||
* * Check if the current element (arr[i]) is less than the
|
||||
* pivot element in each iteration.
|
||||
* * If current element in the iteration is less than the
|
||||
* pivot element, then swap the elements at current index (i) and partition
|
||||
* index (pInd) and increment the partition index by one.
|
||||
* * At the end of the loop, swap the pivot element with partition
|
||||
* index element.
|
||||
* * Return the partition index from the function.
|
||||
*
|
||||
* @author [Nitin Sharma](https://github.com/foo290)
|
||||
*/
|
||||
|
||||
#include <iostream> /// for IO operations
|
||||
#include <ctime> /// for initializing random number generator
|
||||
#include <cassert> /// for assert
|
||||
#include <algorithm> /// for std::is_sorted(), std::swap()
|
||||
#include <algorithm> /// for std::is_sorted(), std::swap()
|
||||
#include <array> /// for std::array
|
||||
#include <tuple> /// for returning multiple values form a function at once
|
||||
#include <cassert> /// for assert
|
||||
#include <ctime> /// for initializing random number generator
|
||||
#include <iostream> /// for IO operations
|
||||
#include <tuple> /// for returning multiple values form a function at once
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
@ -46,111 +57,120 @@
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @brief Functions for the [Random Pivot Quick Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation) implementation
|
||||
* @brief Functions for the [Random Pivot Quick
|
||||
* Sort](https://www.sanfoundry.com/cpp-program-implement-quick-sort-using-randomisation)
|
||||
* implementation
|
||||
* @namespace random_pivot_quick_sort
|
||||
*/
|
||||
namespace random_pivot_quick_sort {
|
||||
/**
|
||||
* @brief Utility function to print the array
|
||||
* @tparam T size of the array
|
||||
* @param arr array used to print its content
|
||||
* @returns void
|
||||
* */
|
||||
template<size_t T>
|
||||
void showArray(std::array<int64_t , T> arr) {
|
||||
for (int64_t i = 0; i < arr.size(); i++) {
|
||||
std::cout << arr[i] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
namespace random_pivot_quick_sort {
|
||||
/**
|
||||
* @brief Utility function to print the array
|
||||
* @tparam T size of the array
|
||||
* @param arr array used to print its content
|
||||
* @returns void
|
||||
* */
|
||||
template <size_t T>
|
||||
void showArray(std::array<int64_t, T> arr) {
|
||||
for (int64_t i = 0; i < arr.size(); i++) {
|
||||
std::cout << arr[i] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Takes the start and end indices of an array and returns a random
|
||||
* int64_teger between the range of those two for selecting pivot element.
|
||||
*
|
||||
* @param start The starting index.
|
||||
* @param end The ending index.
|
||||
* @returns int64_t A random number between start and end index.
|
||||
* */
|
||||
int64_t getRandomIndex(int64_t start, int64_t end) {
|
||||
srand(time(nullptr)); // Initialize random number generator.
|
||||
int64_t randomPivotIndex = start + rand() % (end - start + 1);
|
||||
return randomPivotIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A partition function which handles the partition logic of quick sort.
|
||||
* @tparam size size of the array to be passed as argument.
|
||||
* @param start The start index of the passed array
|
||||
* @param end The ending index of the passed array
|
||||
* @returns std::tuple<int64_t , std::array<int64_t , size>> A tuple of pivot
|
||||
* index and pivot sorted array.
|
||||
*/
|
||||
template <size_t size>
|
||||
std::tuple<int64_t, std::array<int64_t, size>> partition(
|
||||
std::array<int64_t, size> arr, int64_t start, int64_t end) {
|
||||
int64_t pivot = arr[end]; // Randomly selected element will be here from
|
||||
// caller function (quickSortRP()).
|
||||
int64_t pInd = start;
|
||||
|
||||
for (int64_t i = start; i < end; i++) {
|
||||
if (arr[i] <= pivot) {
|
||||
std::swap(arr[i], arr[pInd]); // swapping the elements from current
|
||||
// index to pInd.
|
||||
pInd++;
|
||||
}
|
||||
}
|
||||
std::swap(arr[pInd],
|
||||
arr[end]); // swapping the pivot element to its sorted position
|
||||
return std::make_tuple(pInd, arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Takes the start and end indices of an array and returns a random int64_teger between the range of those two
|
||||
* for selecting pivot element.
|
||||
*
|
||||
* @param start The starting index.
|
||||
* @param end The ending index.
|
||||
* @returns int64_t A random number between start and end index.
|
||||
* */
|
||||
int64_t getRandomIndex(int64_t start, int64_t end) {
|
||||
srand(time(nullptr)); // Initialize random number generator.
|
||||
int64_t randomPivotIndex = start + rand() % (end - start + 1);
|
||||
return randomPivotIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A partition function which handles the partition logic of quick sort.
|
||||
* @tparam size size of the array to be passed as argument.
|
||||
* @param start The start index of the passed array
|
||||
* @param end The ending index of the passed array
|
||||
* @returns std::tuple<int64_t , std::array<int64_t , size>> A tuple of pivot index and pivot sorted array.
|
||||
*/
|
||||
template<size_t size>
|
||||
std::tuple<int64_t , std::array<int64_t , size>> partition(std::array<int64_t , size> arr, int64_t start, int64_t end) {
|
||||
|
||||
int64_t pivot = arr[end]; // Randomly selected element will be here from caller function (quickSortRP()).
|
||||
int64_t pInd = start;
|
||||
|
||||
for (int64_t i = start; i < end; i++) {
|
||||
if (arr[i] <= pivot) {
|
||||
std::swap(arr[i], arr[pInd]); // swapping the elements from current index to pInd.
|
||||
pInd++;
|
||||
}
|
||||
}
|
||||
std::swap(arr[pInd], arr[end]); // swapping the pivot element to its sorted position
|
||||
return std::make_tuple(pInd, arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Random pivot quick sort function. This function is the starting point of the algorithm.
|
||||
* @tparam size size of the array to be passed as argument.
|
||||
* @param start The start index of the passed array
|
||||
* @param end The ending index of the passed array
|
||||
* @returns std::array<int64_t , size> A fully sorted array in ascending order.
|
||||
*/
|
||||
template<size_t size>
|
||||
std::array<int64_t , size> quickSortRP(std::array<int64_t , size> arr, int64_t start, int64_t end) {
|
||||
if (start < end) {
|
||||
|
||||
int64_t randomIndex = getRandomIndex(start, end);
|
||||
|
||||
// switching the pivot with right most bound.
|
||||
std::swap(arr[end], arr[randomIndex]);
|
||||
|
||||
int64_t pivotIndex = 0;
|
||||
// getting pivot index and pivot sorted array.
|
||||
std::tie(pivotIndex, arr) = partition(arr, start, end);
|
||||
|
||||
// Recursively calling
|
||||
std::array<int64_t , arr.size()> rightSortingLeft = quickSortRP(arr, start, pivotIndex - 1);
|
||||
std::array<int64_t , arr.size()> full_sorted = quickSortRP(rightSortingLeft, pivotIndex + 1, end);
|
||||
arr = full_sorted;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A function utility to generate unsorted array of given size and range.
|
||||
* @tparam size Size of the output array.
|
||||
* @param from Stating of the range.
|
||||
* @param to Ending of the range.
|
||||
* @returns std::array<int64_t , size> Unsorted array of specified size.
|
||||
* */
|
||||
template<size_t size>
|
||||
std::array<int64_t , size> generateUnsortedArray(int64_t from, int64_t to) {
|
||||
srand(time(nullptr));
|
||||
std::array<int64_t , size> unsortedArray{};
|
||||
assert(from < to);
|
||||
int64_t i = 0;
|
||||
while (i < size) {
|
||||
int64_t randomNum = from + rand() % (to - from + 1);
|
||||
if (randomNum) {
|
||||
unsortedArray[i] = randomNum;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return unsortedArray;
|
||||
/**
|
||||
* @brief Random pivot quick sort function. This function is the starting point
|
||||
* of the algorithm.
|
||||
* @tparam size size of the array to be passed as argument.
|
||||
* @param start The start index of the passed array
|
||||
* @param end The ending index of the passed array
|
||||
* @returns std::array<int64_t , size> A fully sorted array in ascending order.
|
||||
*/
|
||||
template <size_t size>
|
||||
std::array<int64_t, size> quickSortRP(std::array<int64_t, size> arr,
|
||||
int64_t start, int64_t end) {
|
||||
if (start < end) {
|
||||
int64_t randomIndex = getRandomIndex(start, end);
|
||||
|
||||
// switching the pivot with right most bound.
|
||||
std::swap(arr[end], arr[randomIndex]);
|
||||
|
||||
int64_t pivotIndex = 0;
|
||||
// getting pivot index and pivot sorted array.
|
||||
std::tie(pivotIndex, arr) = partition(arr, start, end);
|
||||
|
||||
// Recursively calling
|
||||
std::array<int64_t, arr.size()> rightSortingLeft =
|
||||
quickSortRP(arr, start, pivotIndex - 1);
|
||||
std::array<int64_t, arr.size()> full_sorted =
|
||||
quickSortRP(rightSortingLeft, pivotIndex + 1, end);
|
||||
arr = full_sorted;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A function utility to generate unsorted array of given size and range.
|
||||
* @tparam size Size of the output array.
|
||||
* @param from Stating of the range.
|
||||
* @param to Ending of the range.
|
||||
* @returns std::array<int64_t , size> Unsorted array of specified size.
|
||||
* */
|
||||
template <size_t size>
|
||||
std::array<int64_t, size> generateUnsortedArray(int64_t from, int64_t to) {
|
||||
srand(time(nullptr));
|
||||
std::array<int64_t, size> unsortedArray{};
|
||||
assert(from < to);
|
||||
int64_t i = 0;
|
||||
while (i < size) {
|
||||
int64_t randomNum = from + rand() % (to - from + 1);
|
||||
if (randomNum) {
|
||||
unsortedArray[i] = randomNum;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return unsortedArray;
|
||||
}
|
||||
|
||||
} // namespace random_pivot_quick_sort
|
||||
} // namespace sorting
|
||||
@ -159,23 +179,23 @@ namespace sorting {
|
||||
* @brief a class containing the necessary test cases
|
||||
*/
|
||||
class TestCases {
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* @brief A function to print64_t given message on console.
|
||||
* @tparam T Type of the given message.
|
||||
* @returns void
|
||||
* */
|
||||
template<typename T>
|
||||
* @brief A function to print64_t given message on console.
|
||||
* @tparam T Type of the given message.
|
||||
* @returns void
|
||||
* */
|
||||
template <typename T>
|
||||
void log(T msg) {
|
||||
// It's just to avoid writing cout and endl
|
||||
std::cout << "[TESTS] : ---> " << msg << std::endl;
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* @brief Executes test cases
|
||||
* @returns void
|
||||
* */
|
||||
* @brief Executes test cases
|
||||
* @returns void
|
||||
* */
|
||||
void runTests() {
|
||||
log("Running Tests...");
|
||||
|
||||
@ -188,24 +208,25 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case with single input
|
||||
* @returns void
|
||||
* */
|
||||
* @brief A test case with single input
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_1() {
|
||||
const int64_t inputSize = 1;
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
log("This is test case 1 for Random Pivot Quick Sort Algorithm : ");
|
||||
log("Description:");
|
||||
log(" EDGE CASE : Only contains one element");
|
||||
std::array<int64_t , inputSize> unsorted_arr{2};
|
||||
std::array<int64_t, inputSize> unsorted_arr{2};
|
||||
|
||||
int64_t start = 0;
|
||||
int64_t end = unsorted_arr.size() - 1; // length - 1
|
||||
int64_t end = unsorted_arr.size() - 1; // length - 1
|
||||
|
||||
log("Running algorithm of data of length 50 ...");
|
||||
std::array<int64_t , unsorted_arr.size()> sorted_arr = sorting::random_pivot_quick_sort::quickSortRP(
|
||||
unsorted_arr, start, end
|
||||
);
|
||||
std::array<int64_t, unsorted_arr.size()> sorted_arr =
|
||||
sorting::random_pivot_quick_sort::quickSortRP(unsorted_arr, start,
|
||||
end);
|
||||
log("Algorithm finished!");
|
||||
|
||||
log("Checking assert expression...");
|
||||
@ -213,28 +234,32 @@ public:
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 1 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case with input array of length 500
|
||||
* @returns void
|
||||
* */
|
||||
* @brief A test case with input array of length 500
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_2() {
|
||||
const int64_t inputSize = 500;
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
log("Description:");
|
||||
log(" BIG INPUT : Contains 500 elements and repeated elements");
|
||||
log("This is test case 2 for Random Pivot Quick Sort Algorithm : ");
|
||||
std::array<int64_t , inputSize> unsorted_arr = sorting::random_pivot_quick_sort::generateUnsortedArray<inputSize>(1, 10000);
|
||||
std::array<int64_t, inputSize> unsorted_arr =
|
||||
sorting::random_pivot_quick_sort::generateUnsortedArray<inputSize>(
|
||||
1, 10000);
|
||||
|
||||
int64_t start = 0;
|
||||
int64_t end = unsorted_arr.size() - 1; // length - 1
|
||||
int64_t end = unsorted_arr.size() - 1; // length - 1
|
||||
|
||||
log("Running algorithm of data of length 500 ...");
|
||||
std::array<int64_t , unsorted_arr.size()> sorted_arr = sorting::random_pivot_quick_sort::quickSortRP(
|
||||
unsorted_arr, start, end
|
||||
);
|
||||
std::array<int64_t, unsorted_arr.size()> sorted_arr =
|
||||
sorting::random_pivot_quick_sort::quickSortRP(unsorted_arr, start,
|
||||
end);
|
||||
log("Algorithm finished!");
|
||||
|
||||
log("Checking assert expression...");
|
||||
@ -242,28 +267,32 @@ public:
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 2 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case with array of length 1000.
|
||||
* @returns void
|
||||
* */
|
||||
* @brief A test case with array of length 1000.
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_3() {
|
||||
const int64_t inputSize = 1000;
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
log("This is test case 3 for Random Pivot Quick Sort Algorithm : ");
|
||||
log("Description:");
|
||||
log(" LARGE INPUT : Contains 1000 elements and repeated elements");
|
||||
std::array<int64_t , inputSize> unsorted_arr = sorting::random_pivot_quick_sort::generateUnsortedArray<inputSize>(1, 10000);
|
||||
std::array<int64_t, inputSize> unsorted_arr =
|
||||
sorting::random_pivot_quick_sort::generateUnsortedArray<inputSize>(
|
||||
1, 10000);
|
||||
|
||||
int64_t start = 0;
|
||||
int64_t end = unsorted_arr.size() - 1; // length - 1
|
||||
int64_t end = unsorted_arr.size() - 1; // length - 1
|
||||
|
||||
log("Running algorithm...");
|
||||
std::array<int64_t , unsorted_arr.size()> sorted_arr = sorting::random_pivot_quick_sort::quickSortRP(
|
||||
unsorted_arr, start, end
|
||||
);
|
||||
std::array<int64_t, unsorted_arr.size()> sorted_arr =
|
||||
sorting::random_pivot_quick_sort::quickSortRP(unsorted_arr, start,
|
||||
end);
|
||||
log("Algorithm finished!");
|
||||
|
||||
log("Checking assert expression...");
|
||||
@ -271,11 +300,11 @@ public:
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 3 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
@ -292,17 +321,18 @@ static void test() {
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
test(); // Executes various test cases.
|
||||
test(); // Executes various test cases.
|
||||
|
||||
const int64_t inputSize = 10;
|
||||
std::array<int64_t , inputSize> unsorted_array = sorting::random_pivot_quick_sort::generateUnsortedArray<inputSize>(50, 1000);
|
||||
std::array<int64_t, inputSize> unsorted_array =
|
||||
sorting::random_pivot_quick_sort::generateUnsortedArray<inputSize>(
|
||||
50, 1000);
|
||||
std::cout << "Unsorted array is : " << std::endl;
|
||||
sorting::random_pivot_quick_sort::showArray(unsorted_array);
|
||||
|
||||
std::array<int64_t , inputSize> sorted_array = sorting::random_pivot_quick_sort::quickSortRP(
|
||||
unsorted_array, 0,
|
||||
unsorted_array.size() - 1
|
||||
);
|
||||
std::array<int64_t, inputSize> sorted_array =
|
||||
sorting::random_pivot_quick_sort::quickSortRP(
|
||||
unsorted_array, 0, unsorted_array.size() - 1);
|
||||
std::cout << "Sorted array is : " << std::endl;
|
||||
sorting::random_pivot_quick_sort::showArray(sorted_array);
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user