feat: Add the Subarray Sum implementation (#1527)

* Create subarray_sum.cpp

* updating DIRECTORY.md

* clang-format and clang-tidy fixes for 0a293ece

* Update backtracking/subarray_sum.cpp

Co-authored-by: David Leal <halfpacho@gmail.com>

* clang-format and clang-tidy fixes for f37f7b7c

* 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 for 9b0b5f87

* 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 for 047366a8

* Update subarray_sum.cpp

* clang-format and clang-tidy fixes for 512b1887

* 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 for e6979047

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Co-authored-by: David Leal <halfpacho@gmail.com>
This commit is contained in:
Swastika Gupta 2021-07-22 00:52:16 +05:30 committed by GitHub
parent 0e0ba5fc89
commit f34f93e77a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 549 additions and 362 deletions

View File

@ -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)

View File

@ -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
* 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>
/**
@ -48,7 +50,8 @@ namespace backtracking {
* @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) {
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;
@ -66,7 +69,8 @@ namespace backtracking {
* @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) {
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) {
@ -103,11 +107,8 @@ int main() {
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<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{};

View 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;
}

View File

@ -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,7 +48,8 @@
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 {
/**
@ -54,8 +57,8 @@ namespace iterative_tree_traversals {
*/
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.
struct Node *left{}; ///< struct pointer to left subtree.
struct Node *right{}; ///< struct pointer to right subtree.
};
/**
@ -63,14 +66,22 @@ struct Node {
*/
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.
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.
*/
@ -82,13 +93,15 @@ 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::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);
@ -110,13 +123,15 @@ std::vector<int64_t> BinaryTree::preOrderIterative(Node *root) {
}
/**
* @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::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);
@ -140,13 +155,15 @@ std::vector<int64_t> BinaryTree::postOrderIterative(Node *root) {
}
/**
* @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;
@ -171,17 +188,20 @@ 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);
// 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;
@ -195,17 +215,20 @@ 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;
@ -219,17 +242,20 @@ 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;
@ -243,17 +269,20 @@ 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);
// 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;
@ -263,21 +292,25 @@ static void test4(others::iterative_tree_traversals::BinaryTree binaryTree, othe
}
/**
* @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;
@ -291,17 +324,20 @@ 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;
@ -324,7 +360,9 @@ 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);

View File

@ -1,43 +1,54 @@
/**
* @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 <array> /// for std::array
#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
/**
@ -46,7 +57,9 @@
*/
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 {
@ -65,8 +78,8 @@ namespace sorting {
}
/**
* @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.
* @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.
@ -83,35 +96,40 @@ namespace sorting {
* @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.
* @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()).
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.
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
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.
* @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) {
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.
@ -122,8 +140,10 @@ namespace sorting {
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);
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;
@ -193,7 +213,8 @@ public:
* */
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");
@ -203,9 +224,9 @@ public:
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,7 +234,8 @@ public:
log("Assertion check passed!");
log("[PASS] : TEST CASE 1 PASS!");
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
"~");
}
/**
@ -222,19 +244,22 @@ public:
* */
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
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,7 +267,8 @@ public:
log("Assertion check passed!");
log("[PASS] : TEST CASE 2 PASS!");
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
"~");
}
/**
@ -251,19 +277,22 @@ public:
* */
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
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
@ -295,14 +324,15 @@ int main(int argc, char *argv[]) {
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;