mirror of
https://hub.njuu.cf/TheAlgorithms/C-Plus-Plus.git
synced 2023-10-11 13:05:55 +08:00
Merge branch 'master' into aminos
This commit is contained in:
commit
0ec45e33a3
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,33 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve. Report bugs found while using the project
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--- Provide a general summary of the issue in the Title above -->
|
||||
|
||||
## Description
|
||||
<!--- Provide a more detailed introduction to the issue itself, and why you consider it to be a bug -->
|
||||
|
||||
## Expected Behavior
|
||||
<!--- Tell us what should happen -->
|
||||
|
||||
## Actual Behavior
|
||||
<!--- Tell us what happens instead -->
|
||||
|
||||
## Possible Fix
|
||||
<!--- Not obligatory, but suggest a fix or reason for the bug -->
|
||||
|
||||
## Steps to Reproduce
|
||||
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
|
||||
<!--- reproduce this bug. Include code to reproduce, if relevant -->
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
## Context
|
||||
<!--- How has this bug affected you? What were you trying to accomplish? -->
|
64
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
64
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
name: Bug report
|
||||
description: Create a report to help us improve. Report bugs found while using the project
|
||||
title: "[BUG]"
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Provide a general summary of the issue in the Title above"
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Provide a general summary of the issue in the Title above
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: expectedbhv
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: Tell us what should happen
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: actualbhv
|
||||
attributes:
|
||||
label: Actual behavior
|
||||
description: Tell us what happens instead
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: possiblefix
|
||||
attributes:
|
||||
label: Possible fix
|
||||
description: Not obligatory, but suggest a fix or reason for the bug
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: |
|
||||
Provide a link to a live example, or an unambiguous set of steps to
|
||||
reproduce this bug. Include code to reproduce, if relevant
|
||||
placeholder: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Context
|
||||
description: How has this bug affected you? What were you trying to accomplish?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extrainformation
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Is there anything else we should know about this bug?
|
||||
validations:
|
||||
required: false
|
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest features, propose improvements, discuss new ideas.
|
||||
title: "[FEATURE]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--- Provide a general summary of the issue in the Title above -->
|
||||
|
||||
## Detailed Description
|
||||
<!--- Provide a detailed description of the change or addition you are proposing -->
|
||||
|
||||
## Context
|
||||
<!--- Why is this change important to you? How would you use it? -->
|
||||
<!--- How can it benefit other users? -->
|
||||
|
||||
## Possible Implementation
|
||||
<!--- Not obligatory, but suggest an idea for implementing addition or change -->
|
38
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
38
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: Feature request
|
||||
description: Suggest features, propose improvements, discuss new ideas.
|
||||
title: "[FEATURE]"
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Provide a general summary of the issue in the Title above
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Detailed description
|
||||
description: Provide a detailed description of the change or addition you are proposing
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Context
|
||||
description: |
|
||||
Why is this change important to you? How would you use it?
|
||||
How can it benefit other users?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: possibleimpl
|
||||
attributes:
|
||||
label: Possible implementation
|
||||
description: Not obligatory, but suggest an idea for implementing addition or change
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: extrainformation
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Is there anything else we should know about this feature?
|
||||
validations:
|
||||
required: false
|
22
.github/ISSUE_TEMPLATE/other.yml
vendored
Normal file
22
.github/ISSUE_TEMPLATE/other.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: Other
|
||||
description: Use this for any other issues. Do NOT create blank issues
|
||||
title: "[OTHER]"
|
||||
labels: [triage]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "# Other issue"
|
||||
- type: textarea
|
||||
id: issuedescription
|
||||
attributes:
|
||||
label: What would you like to share?
|
||||
description: Provide a clear and concise explanation of your issue.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extrainfo
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Is there anything else we should know about this issue?
|
||||
validations:
|
||||
required: false
|
@ -2,54 +2,58 @@
|
||||
|
||||
## Before contributing
|
||||
|
||||
Welcome to [TheAlgorithms/C-Plus-Plus](https://github.com/TheAlgorithms/C-Plus-Plus)! Before submitting pull requests, please make sure that you have **read the whole guidelines**. If you have any doubts about this contribution guide, please open [an issue](https://github.com/TheAlgorithms/C-Plus-Plus/issues/new/choose) and clearly state your concerns.
|
||||
Welcome to [TheAlgorithms/C-Plus-Plus](https://github.com/TheAlgorithms/C-Plus-Plus)! Before submitting pull requests, please make sure that you have **read the whole guidelines**. If you have any doubts about this contribution guide, please open [an issue](https://github.com/TheAlgorithms/C-Plus-Plus/issues/new/choose) or ask in our [Discord server](https://discord.gg/c7MnfGFGa6), and clearly state your concerns.
|
||||
|
||||
## Contributing
|
||||
|
||||
### Maintainer/reviewer
|
||||
|
||||
**Please check the [reviewer code](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/REVIEWER_CODE.md) file for maintainers and reviewers.**
|
||||
|
||||
### Contributor
|
||||
|
||||
We are very happy that you consider implementing algorithms and data structures for others! This repository is referred to and used by learners from around the globe. Being one of our contributors, you agree and confirm that:
|
||||
Being a contributor at The Algorithms, we request you to follow the points mentioned below:
|
||||
|
||||
- You did your own work.
|
||||
- No plagiarism allowed. Any plagiarized work will not be merged.
|
||||
- Your work will be distributed under [MIT License](License) once your pull request has been merged.
|
||||
- You submitted work fulfils or mostly fulfils our styles and standards.
|
||||
- Your work will be distributed under the [MIT License](https://github.com/TheAlgoritms/C-Plus-Plus/blob/master/LICENSE) once your pull request has been merged.
|
||||
- Please follow the repository guidelines and standards mentioned below.
|
||||
|
||||
**New implementation** New implementation are welcome!
|
||||
**New implementation** New implementations are welcome!
|
||||
|
||||
**Improving comments** and **adding tests** to existing algorithms are much appreciated.
|
||||
You can add new algorithms or data structures which are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, removing bugs or in any other resonable sense)
|
||||
|
||||
**Issues** Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request and it will be evaluated by project maintainers.
|
||||
**Issues** Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request, and it will be evaluated by project maintainers.
|
||||
|
||||
### Making Changes
|
||||
|
||||
#### Code
|
||||
|
||||
- Please use the directory structure of the repository.
|
||||
- File extension for code should be `*.hpp`, `*.h` or `*.cpp`.
|
||||
- Don't use **bits/stdc++.h** because this is quite Linux specific and slows down the compilation process.
|
||||
- Organize your code using **`struct`**, **`class`** and/or **`namespace`** keywords
|
||||
- Make sure the file extensions should be `*.hpp`, `*.h` or `*.cpp`.
|
||||
- Don't use **`bits/stdc++.h`** because this is quite Linux-specific and slows down the compilation process.
|
||||
- Organize your code using **`struct`**, **`class`**, and/or **`namespace`** keywords
|
||||
- If an implementation of the algorithm already exists, please refer to the [file-name section below](#new-file-name-guidelines).
|
||||
- You can suggest reasonable changes to existing algorithms.
|
||||
- Strictly use snake_case (underscore_separated) in filenames.
|
||||
- If you have added or modified code, please make sure the code compiles before submitting.
|
||||
- Our automated testing runs [__CMake__](https://cmake.org/) on all pull requests so please be sure that your code passes before submitting.
|
||||
- Please conform to [doxygen](https://www.doxygen.nl/manual/docblocks.html) standard and document the code as much as possible. This not only facilitates the readers but also generates the correct info on website.
|
||||
- **Be consistent in use of these guidelines.**
|
||||
- Our automated testing runs [__CMake__](https://cmake.org/) on all the pull requests, so please be sure that your code passes before submitting.
|
||||
- Please conform to [Doxygen](https://www.doxygen.nl/manual/docblocks.html) standard and document the code as much as possible. This not only facilitates the readers but also generates the correct info on the website.
|
||||
- **Be consistent in the use of these guidelines.**
|
||||
|
||||
#### Documentation
|
||||
|
||||
- Make sure you put useful comments in your code. Do not comment things that are obvious.
|
||||
- Make sure you put useful comments in your code. Do not comment on obvious things.
|
||||
- Please avoid creating new directories if at all possible. Try to fit your work into the existing directory structure. If you want to create a new directory, then please check if a similar category has been recently suggested or created by other pull requests.
|
||||
- If you have modified/added documentation, please ensure that your language is concise and contains no grammar errors.
|
||||
- Do not update [`README.md`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/README.md) along with other changes. First create an issue and then link to that issue in your pull request to suggest specific changes required to [`README.md`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/README.md).
|
||||
- The repository follows [Doxygen](https://www.doxygen.nl/manual/docblocks.html) standards and auto-generates the [repository website](https://thealgorithms.github.io/C-Plus-Plus). Please ensure the code is documented in this structure. Sample implementation is given below.
|
||||
- If you have modified/added documentation, please ensure that your language is concise and must not contain grammatical errors.
|
||||
- Do not update [`README.md`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/README.md) along with other changes. First, create an issue and then link to that issue in your pull request to suggest specific changes required to [`README.md`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/README.md).
|
||||
- The repository follows [Doxygen](https://www.doxygen.nl/manual/docblocks.html) standards and auto-generates the [repository website](https://thealgorithms.github.io/C-Plus-Plus). Please ensure the code is documented in this structure. A sample implementation is given below.
|
||||
|
||||
#### Test
|
||||
|
||||
- Make sure to add examples and test cases in your main() function.
|
||||
- If you find any algorithm or document without tests, please feel free to create a pull request or issue describing suggested changes.
|
||||
- Please try to add one or more `test()` functions that will invoke the algorithm implementation on random test data with expected output. Use `assert()` function to confirm that the tests will pass. Requires including the `cassert` header.
|
||||
- Make sure to add examples and test cases in your `main()` function.
|
||||
- If you find an algorithm or document without tests, please feel free to create a pull request or issue describing suggested changes.
|
||||
- Please try to add one or more `test()` functions that will invoke the algorithm implementation on random test data with the expected output. Use the `assert()` function to confirm that the tests will pass. Requires including the `cassert` library.
|
||||
|
||||
#### Typical structure of a program
|
||||
|
||||
@ -58,15 +62,15 @@ We are very happy that you consider implementing algorithms and data structures
|
||||
* @file
|
||||
* @brief Add one line description here
|
||||
* @details
|
||||
* This is a multi line
|
||||
* This is a multi-line
|
||||
* description containing links, references,
|
||||
* math equations, etc
|
||||
* math equations, etc.
|
||||
* @author [Name](https://github.com/handle)
|
||||
* @see related_file.cpp, another_file.cpp
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include
|
||||
#include <cassert> /// for assert
|
||||
#include /// for `some function here`
|
||||
|
||||
/**
|
||||
* @namespace <check from other files in this repo>
|
||||
@ -74,7 +78,7 @@ We are very happy that you consider implementing algorithms and data structures
|
||||
namespace name {
|
||||
|
||||
/**
|
||||
* Class documentation
|
||||
* @brief Class documentation
|
||||
*/
|
||||
class class_name {
|
||||
private:
|
||||
@ -86,7 +90,7 @@ class class_name {
|
||||
}
|
||||
|
||||
/**
|
||||
* Function documentation
|
||||
* @brief Function documentation
|
||||
* @tparam T this is a one-line info about T
|
||||
* @param param1 on-line info about param1
|
||||
* @param param2 on-line info about param2
|
||||
@ -105,11 +109,11 @@ bool func(int param1, T param2) {
|
||||
} // namespace name
|
||||
|
||||
/**
|
||||
* @brief Test implementations
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
/* desciptions of the following test */
|
||||
/* descriptions of the following test */
|
||||
assert(func(...) == ...); // this ensures that the algorithm works as expected
|
||||
|
||||
// can have multiple checks
|
||||
@ -122,7 +126,7 @@ static void test() {
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
test(); // execute the tests
|
||||
test(); // run self-test implementations
|
||||
// code here
|
||||
return 0;
|
||||
}
|
||||
@ -130,7 +134,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
#### New File Name guidelines
|
||||
|
||||
- Use lowercase words with ``"_"`` as separator
|
||||
- Use lowercase words with ``"_"`` as a separator
|
||||
- For instance
|
||||
|
||||
```markdown
|
||||
@ -139,8 +143,8 @@ my_new_cpp_class.cpp is correct format
|
||||
```
|
||||
|
||||
- It will be used to dynamically create a directory of files and implementation.
|
||||
- File name validation will run on docker to ensure the validity.
|
||||
- If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example, if `median_search.cpp` already exists in the `search` folder and you are contributing a new implementation, the filename should be `median_search2.cpp` and for a third implementation, `median_search3.cpp`.
|
||||
- File name validation will run on Docker to ensure validity.
|
||||
- If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example: if `median_search.cpp` already exists in the `search` folder, and you are contributing a new implementation, the filename should be `median_search2.cpp` and for a third implementation, `median_search3.cpp`.
|
||||
|
||||
#### New Directory guidelines
|
||||
|
||||
@ -158,7 +162,7 @@ some_new_fancy_category is correct
|
||||
|
||||
#### Commit Guidelines
|
||||
|
||||
- It is recommended to keep your changes grouped logically within individual commits. Maintainers find it easier to understand changes that are logically spilt across multiple commits. Try to modify just one or two files in the same directory. Pull requests that span multiple directories are often rejected.
|
||||
- It is recommended to keep your changes grouped logically within individual commits. Maintainers find it easier to understand changes that are logically spilled across multiple commits. Try to modify just one or two files in the same directory. Pull requests that span multiple directories are often rejected.
|
||||
|
||||
```bash
|
||||
git add file_xyz.cpp
|
||||
@ -196,7 +200,7 @@ cmake -B build -S .
|
||||
|
||||
#### Static Code Analyzer
|
||||
|
||||
We use [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) as a static code analyzer with a configuration in [.clang-tidy](.clang-tidy).
|
||||
We use [`clang-tidy`](https://clang.llvm.org/extra/clang-tidy/) as a static code analyzer with a configuration in [`.clang-tidy`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/.clang-tidy).
|
||||
|
||||
```bash
|
||||
clang-tidy --fix --quiet -p build subfolder/file_to_check.cpp --
|
||||
@ -204,7 +208,7 @@ clang-tidy --fix --quiet -p build subfolder/file_to_check.cpp --
|
||||
|
||||
#### Code Formatter
|
||||
|
||||
[__clang-format__](https://clang.llvm.org/docs/ClangFormat.html) is used for code forrmating.
|
||||
[`__clang-format__`](https://clang.llvm.org/docs/ClangFormat.html) is used for code forrmating.
|
||||
|
||||
- Installation (only needs to be installed once.)
|
||||
- Mac (using home-brew): `brew install clang-format`
|
||||
@ -216,14 +220,14 @@ clang-tidy --fix --quiet -p build subfolder/file_to_check.cpp --
|
||||
#### GitHub Actions
|
||||
|
||||
- Enable GitHub Actions on your fork of the repository.
|
||||
After enabling it will execute `clang-tidy` and `clang-format` after every push (not a commit).
|
||||
After enabling, it will execute `clang-tidy` and `clang-format` after every push (not a commit).
|
||||
- Click on the tab "Actions", then click on the big green button to enable it.
|
||||
|
||||
![GitHub Actions](https://user-images.githubusercontent.com/51391473/94609466-6e925100-0264-11eb-9d6f-3706190eab2b.png)
|
||||
|
||||
- The result can create another commit if the actions made any changes on your behalf.
|
||||
- Hence, it is better to wait and check the results of GitHub Actions after every push.
|
||||
- Run `git pull` in your local clone if these actions made many changes in order to avoid merge conflicts.
|
||||
- Run `git pull` in your local clone if these actions made many changes to avoid merge conflicts.
|
||||
|
||||
Most importantly,
|
||||
|
||||
|
18
CodingGuidelines.md
Normal file
18
CodingGuidelines.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Code style convention
|
||||
|
||||
Please orient on this guide before you sent a pull request.
|
||||
|
||||
---
|
||||
|
||||
## User-interface
|
||||
|
||||
Please write a simple user interface for your programs. Not a blinking cursor!
|
||||
What does the program do?
|
||||
What want the program an user informations?
|
||||
|
||||
---
|
||||
|
||||
## Code style conventions
|
||||
|
||||
See [here](https://users.ece.cmu.edu/~eno/coding/CppCodingStandard.html)
|
||||
Don't push all code in one line!
|
12
DIRECTORY.md
12
DIRECTORY.md
@ -2,14 +2,18 @@
|
||||
## Backtracking
|
||||
* [Graph Coloring](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/graph_coloring.cpp)
|
||||
* [Knight Tour](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/knight_tour.cpp)
|
||||
* [Magic Sequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/magic_sequence.cpp)
|
||||
* [Minimax](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/minimax.cpp)
|
||||
* [N Queens](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/n_queens.cpp)
|
||||
* [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)
|
||||
|
||||
## Bit Manipulation
|
||||
* [Count Of Set Bits](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/count_of_set_bits.cpp)
|
||||
* [Hamming Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/hamming_distance.cpp)
|
||||
|
||||
## Ciphers
|
||||
@ -47,6 +51,7 @@
|
||||
* [Queue Using Two Stacks](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/queue_using_two_stacks.cpp)
|
||||
* [Rb Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/rb_tree.cpp)
|
||||
* [Skip List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/skip_list.cpp)
|
||||
* [Sparse Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/sparse_table.cpp)
|
||||
* [Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack.h)
|
||||
* [Stack Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_array.cpp)
|
||||
* [Stack Using Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_linked_list.cpp)
|
||||
@ -72,6 +77,7 @@
|
||||
* [Egg Dropping Puzzle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/egg_dropping_puzzle.cpp)
|
||||
* [Fibonacci Bottom Up](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/fibonacci_bottom_up.cpp)
|
||||
* [Floyd Warshall](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/floyd_warshall.cpp)
|
||||
* [House Robber](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/house_robber.cpp)
|
||||
* [Kadane](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/kadane.cpp)
|
||||
* [Kadane2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/kadane2.cpp)
|
||||
* [Longest Common String](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/longest_common_string.cpp)
|
||||
@ -215,6 +221,7 @@
|
||||
* [Circular Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/circular_linked_list.cpp)
|
||||
* [Circular Queue Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/circular_queue_using_array.cpp)
|
||||
* [Get Size Of Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/get_size_of_linked_list.cpp)
|
||||
* [Inorder Successor Of Bst](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/inorder_successor_of_bst.cpp)
|
||||
* [Intersection Of 2 Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/intersection_of_2_arrays.cpp)
|
||||
* [Reverse A Linked List Using Recusion](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/reverse_a_linked_list_using_recusion.cpp)
|
||||
* [Selectionsortlinkedlist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/selectionsortlinkedlist.cpp)
|
||||
@ -228,6 +235,7 @@
|
||||
* [Decimal To Roman Numeral](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_roman_numeral.cpp)
|
||||
* [Fast Integer Input](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/fast_integer_input.cpp)
|
||||
* [Happy Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/happy_number.cpp)
|
||||
* [Iterative Tree Traversals](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/iterative_tree_traversals.cpp)
|
||||
* [Matrix Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/matrix_exponentiation.cpp)
|
||||
* [Palindrome Of Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/palindrome_of_number.cpp)
|
||||
* [Paranthesis Matching](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/paranthesis_matching.cpp)
|
||||
@ -259,6 +267,7 @@
|
||||
* [Binary Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/binary_search.cpp)
|
||||
* [Exponential Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/exponential_search.cpp)
|
||||
* [Fibonacci Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/fibonacci_search.cpp)
|
||||
* [Floyd Cycle Detection Algo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/floyd_cycle_detection_algo.cpp)
|
||||
* [Hash Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/hash_search.cpp)
|
||||
* [Interpolation Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/interpolation_search.cpp)
|
||||
* [Interpolation Search2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/interpolation_search2.cpp)
|
||||
@ -266,6 +275,7 @@
|
||||
* [Linear Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/linear_search.cpp)
|
||||
* [Median Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/median_search.cpp)
|
||||
* [Saddleback Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/saddleback_search.cpp)
|
||||
* [Sublist Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/sublist_search.cpp)
|
||||
* [Ternary Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/ternary_search.cpp)
|
||||
* [Text Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/search/text_search.cpp)
|
||||
|
||||
@ -296,6 +306,7 @@
|
||||
* [Quick Sort 3](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/quick_sort_3.cpp)
|
||||
* [Radix Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/radix_sort.cpp)
|
||||
* [Radix Sort2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/radix_sort2.cpp)
|
||||
* [Random Pivot Quick Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/random_pivot_quick_sort.cpp)
|
||||
* [Recursive Bubble Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/recursive_bubble_sort.cpp)
|
||||
* [Selection Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/selection_sort.cpp)
|
||||
* [Shell Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/shell_sort.cpp)
|
||||
@ -304,6 +315,7 @@
|
||||
* [Strand Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/strand_sort.cpp)
|
||||
* [Swap Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/swap_sort.cpp)
|
||||
* [Tim Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/tim_sort.cpp)
|
||||
* [Wave Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/wave_sort.cpp)
|
||||
* [Wiggle Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/wiggle_sort.cpp)
|
||||
|
||||
## Strings
|
||||
|
@ -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>
|
||||
|
||||
/**
|
||||
@ -24,20 +26,20 @@
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/** A utility function to print solution
|
||||
/** 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\n";
|
||||
for (auto &col : color) {
|
||||
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 << "\n";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/** A utility function to check if the current color assignment is safe for
|
||||
/** 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
|
||||
@ -47,17 +49,18 @@ namespace backtracking {
|
||||
* @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) {
|
||||
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
|
||||
/** 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
|
||||
@ -65,8 +68,9 @@ namespace backtracking {
|
||||
* 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) {
|
||||
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) {
|
||||
@ -87,7 +91,7 @@ namespace backtracking {
|
||||
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;
|
||||
|
135
backtracking/magic_sequence.cpp
Normal file
135
backtracking/magic_sequence.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* @brief [Magic sequence](https://www.csplib.org/Problems/prob019/)
|
||||
* implementation
|
||||
*
|
||||
* @details Solve the magic sequence problem with backtracking
|
||||
*
|
||||
* "A magic sequence of length $n$ is a sequence of integers $x_0
|
||||
* \ldots x_{n-1}$ between $0$ and $n-1$, such that for all $i$
|
||||
* in $0$ to $n-1$, the number $i$ occurs exactly $x_i$ times in
|
||||
* the sequence. For instance, $6,2,1,0,0,0,1,0,0,0$ is a magic
|
||||
* sequence since $0$ occurs $6$ times in it, $1$ occurs twice, etc."
|
||||
* Quote taken from the [CSPLib](https://www.csplib.org/Problems/prob019/)
|
||||
* website
|
||||
*
|
||||
* @author [Jxtopher](https://github.com/Jxtopher)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::count
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <list> /// for std::list
|
||||
#include <numeric> /// for std::accumulate
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace magic_sequence
|
||||
* @brief Functions for the [Magic
|
||||
* sequence](https://www.csplib.org/Problems/prob019/) implementation
|
||||
*/
|
||||
namespace magic_sequence {
|
||||
using sequence_t =
|
||||
std::vector<unsigned int>; ///< Definition of the sequence type
|
||||
/**
|
||||
* @brief Print the magic sequence
|
||||
* @param s working memory for the sequence
|
||||
*/
|
||||
void print(const sequence_t& s) {
|
||||
for (const auto& item : s) std::cout << item << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the sequence is magic
|
||||
* @param s working memory for the sequence
|
||||
* @returns true if it's a magic sequence
|
||||
* @returns false if it's NOT a magic sequence
|
||||
*/
|
||||
bool is_magic(const sequence_t& s) {
|
||||
for (unsigned int i = 0; i < s.size(); i++) {
|
||||
if (std::count(s.cbegin(), s.cend(), i) != s[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sub-solutions filtering
|
||||
* @param s working memory for the sequence
|
||||
* @param depth current depth in tree
|
||||
* @returns true if the sub-solution is valid
|
||||
* @returns false if the sub-solution is NOT valid
|
||||
*/
|
||||
bool filtering(const sequence_t& s, unsigned int depth) {
|
||||
return std::accumulate(s.cbegin(), s.cbegin() + depth,
|
||||
static_cast<unsigned int>(0)) <= s.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Solve the Magic Sequence problem
|
||||
* @param s working memory for the sequence
|
||||
* @param ret list of the valid magic sequences
|
||||
* @param depth current depth in the tree
|
||||
*/
|
||||
void solve(sequence_t* s, std::list<sequence_t>* ret, unsigned int depth = 0) {
|
||||
if (depth == s->size()) {
|
||||
if (is_magic(*s)) {
|
||||
ret->push_back(*s);
|
||||
}
|
||||
} else {
|
||||
for (unsigned int i = 0; i < s->size(); i++) {
|
||||
(*s)[depth] = i;
|
||||
if (filtering(*s, depth + 1)) {
|
||||
solve(s, ret, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace magic_sequence
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// test a valid magic sequence
|
||||
backtracking::magic_sequence::sequence_t s_magic = {6, 2, 1, 0, 0,
|
||||
0, 1, 0, 0, 0};
|
||||
assert(backtracking::magic_sequence::is_magic(s_magic));
|
||||
|
||||
// test a non-valid magic sequence
|
||||
backtracking::magic_sequence::sequence_t s_not_magic = {5, 2, 1, 0, 0,
|
||||
0, 1, 0, 0, 0};
|
||||
assert(!backtracking::magic_sequence::is_magic(s_not_magic));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
|
||||
// solve magic sequences of size 2 to 11 and print the solutions
|
||||
for (unsigned int i = 2; i < 12; i++) {
|
||||
std::cout << "Solution for n = " << i << std::endl;
|
||||
// valid magic sequence list
|
||||
std::list<backtracking::magic_sequence::sequence_t> list_of_solutions;
|
||||
// initialization of a sequence
|
||||
backtracking::magic_sequence::sequence_t s1(i, i);
|
||||
// launch of solving the problem
|
||||
backtracking::magic_sequence::solve(&s1, &list_of_solutions);
|
||||
// print solutions
|
||||
for (const auto& item : list_of_solutions) {
|
||||
backtracking::magic_sequence::print(item);
|
||||
}
|
||||
}
|
||||
}
|
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;
|
||||
}
|
106
backtracking/subset_sum.cpp
Normal file
106
backtracking/subset_sum.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Subset
|
||||
* Sum](https://en.wikipedia.org/wiki/Subset_sum_problem) problem.
|
||||
* @details
|
||||
* We are given an array and a sum value. The algorithm finds all
|
||||
* the subsets of that array with sum equal to the given sum and return such
|
||||
* subsets count. This approach will have exponential time complexity.
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace Subsets
|
||||
* @brief Functions for the [Subset
|
||||
* Sum](https://en.wikipedia.org/wiki/Subset_sum_problem) problem.
|
||||
*/
|
||||
namespace subset_sum {
|
||||
/**
|
||||
* @brief The main function implements count of subsets
|
||||
* @param sum is the required sum of any subset
|
||||
* @param in_arr is the input array
|
||||
* @returns count of the number of subsets with required sum
|
||||
*/
|
||||
uint64_t number_of_subsets(int32_t sum, const std::vector<int32_t> &in_arr) {
|
||||
int32_t nelement = in_arr.size();
|
||||
uint64_t count_of_subset = 0;
|
||||
|
||||
for (int32_t i = 0; i < (1 << (nelement)); i++) {
|
||||
int32_t check = 0;
|
||||
for (int32_t j = 0; j < nelement; j++) {
|
||||
if (i & (1 << j)) {
|
||||
check += (in_arr[j]);
|
||||
}
|
||||
}
|
||||
if (check == sum) {
|
||||
count_of_subset++;
|
||||
}
|
||||
}
|
||||
return count_of_subset;
|
||||
}
|
||||
} // namespace subset_sum
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::cout << "1st test ";
|
||||
std::vector<int32_t> array1 = {-7, -3, -2, 5, 8}; // input array
|
||||
assert(backtracking::subset_sum::number_of_subsets(0, array1) ==
|
||||
2); // first argument in subset_sum function is the required sum and
|
||||
// second is the input array
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 2nd test
|
||||
std::cout << "2nd test ";
|
||||
std::vector<int32_t> array2 = {1, 2, 3, 3};
|
||||
assert(backtracking::subset_sum::number_of_subsets(6, array2) ==
|
||||
3); // here we are expecting 3 subsets which sum up to 6 i.e.
|
||||
// {(1,2,3),(1,2,3),(3,3)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 3rd test
|
||||
std::cout << "3rd test ";
|
||||
std::vector<int32_t> array3 = {1, 1, 1, 1};
|
||||
assert(backtracking::subset_sum::number_of_subsets(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;
|
||||
|
||||
// 4th test
|
||||
std::cout << "4th test ";
|
||||
std::vector<int32_t> array4 = {3, 3, 3, 3};
|
||||
assert(backtracking::subset_sum::number_of_subsets(6, array4) ==
|
||||
6); // here we are expecting 6 subsets which sum up to 6 i.e.
|
||||
// {(3,3),(3,3),(3,3),(3,3),(3,3),(3,3)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// Test 5
|
||||
std::cout << "5th test ";
|
||||
std::vector<int32_t> array5 = {};
|
||||
assert(backtracking::subset_sum::number_of_subsets(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;
|
||||
}
|
80
bit_manipulation/count_of_set_bits.cpp
Normal file
80
bit_manipulation/count_of_set_bits.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation to [count sets
|
||||
* bits](https://www.geeksforgeeks.org/count-set-bits-in-an-integer/) in an
|
||||
* integer.
|
||||
*
|
||||
* @details
|
||||
* We are given an integer number. Let’s say, number. The task is to first
|
||||
* calculate the binary digit of a number and then calculate the total set bits
|
||||
* of a number.
|
||||
*
|
||||
* Set bits in a binary number is represented by 1. Whenever we calculate the
|
||||
* binary number of an integer value it is formed as the combination of 0’s and
|
||||
* 1’s. So digit 1 is known as a set bit in computer terms.
|
||||
* Time Complexity: O(log n)
|
||||
* Space complexity: O(1)
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for io operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @namespace count_of_set_bits
|
||||
* @brief Functions for the [count sets
|
||||
* bits](https://www.geeksforgeeks.org/count-set-bits-in-an-integer/)
|
||||
* implementation
|
||||
*/
|
||||
namespace count_of_set_bits {
|
||||
/**
|
||||
* @brief The main function implements set bit count
|
||||
* @param n is the number whose set bit will be counted
|
||||
* @returns the count of the number set bit in the binary representation of `n`
|
||||
*/
|
||||
std::uint64_t countSetBits(int n) {
|
||||
int count = 0; // "count" variable is used to count number of 1's in binary
|
||||
// representation of the number
|
||||
while (n != 0) {
|
||||
count += n & 1;
|
||||
n = n >> 1; // n=n/2
|
||||
}
|
||||
return count;
|
||||
}
|
||||
} // namespace count_of_set_bits
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// n = 4 return 1
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(4) == 1);
|
||||
// n = 6 return 2
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(6) == 2);
|
||||
// n = 13 return 3
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(13) == 3);
|
||||
// n = 9 return 2
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(9) == 2);
|
||||
// n = 15 return 4
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(15) == 4);
|
||||
// n = 25 return 3
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(25) == 3);
|
||||
std::cout << "All test cases successfully passed!" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
@ -2,34 +2,27 @@
|
||||
|
||||
struct node {
|
||||
int data;
|
||||
struct node *next;
|
||||
struct node* next;
|
||||
};
|
||||
class Queue {
|
||||
node *front;
|
||||
node *rear;
|
||||
node* front=nullptr;
|
||||
node* rear=nullptr;
|
||||
|
||||
public:
|
||||
Queue() {
|
||||
front = NULL;
|
||||
rear = NULL;
|
||||
}
|
||||
public:
|
||||
Queue() = default;
|
||||
void createNode(int val) {
|
||||
node *ptr;
|
||||
node *nn;
|
||||
nn = new node;
|
||||
ptr = front;
|
||||
auto* nn = new node;
|
||||
nn->data = val;
|
||||
nn->next = NULL;
|
||||
nn->next = nullptr;
|
||||
front = nn;
|
||||
rear = nn;
|
||||
}
|
||||
void enqueue(int val) {
|
||||
if (front == NULL || rear == NULL) {
|
||||
if (front == nullptr || rear == nullptr) {
|
||||
createNode(val);
|
||||
} else {
|
||||
node *ptr;
|
||||
node *nn;
|
||||
ptr = front;
|
||||
}
|
||||
else {
|
||||
node* nn;
|
||||
nn = new node;
|
||||
nn->data = val;
|
||||
rear->next = nn;
|
||||
@ -38,20 +31,24 @@ class Queue {
|
||||
}
|
||||
}
|
||||
void dequeue() {
|
||||
node *n;
|
||||
node* n;
|
||||
n = front;
|
||||
if (n) {
|
||||
front = front->next;
|
||||
delete (n);
|
||||
delete n;
|
||||
}
|
||||
}
|
||||
void traverse() {
|
||||
node *ptr;
|
||||
node* ptr;
|
||||
ptr = front;
|
||||
if (ptr) {
|
||||
do {
|
||||
std::cout << ptr->data << " ";
|
||||
ptr = ptr->next;
|
||||
} while (ptr != rear->next);
|
||||
std::cout << front->data << std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
int main(void) {
|
||||
Queue q;
|
||||
|
164
data_structures/sparse_table.cpp
Normal file
164
data_structures/sparse_table.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Sparse
|
||||
* Table](https://brilliant.org/wiki/sparse-table/) for `min()` function.
|
||||
* @author [Mann Patel](https://github.com/manncodes)
|
||||
* @details
|
||||
* Sparse Table is a data structure, that allows answering range queries.
|
||||
* It can answer most range queries in O(logn), but its true power is answering
|
||||
* range minimum queries (or equivalent range maximum queries). For those
|
||||
* queries it can compute the answer in O(1) time. The only drawback of this
|
||||
* data structure is, that it can only be used on immutable arrays. This means,
|
||||
* that the array cannot be changed between two queries.
|
||||
*
|
||||
* If any element in the array changes, the complete data structure has to be
|
||||
* recomputed.
|
||||
*
|
||||
* @todo make stress tests.
|
||||
*
|
||||
* @warning
|
||||
* This sparse table is made for `min(a1,a2,...an)` duplicate invariant
|
||||
* function. This implementation can be changed to other functions like
|
||||
* `gcd()`, `lcm()`, and `max()` by changing a few lines of code.
|
||||
*/
|
||||
|
||||
#include <array> /// for std::array
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace data_structures
|
||||
* @brief Data Structures algorithms
|
||||
*/
|
||||
namespace data_structures {
|
||||
|
||||
/**
|
||||
* @namespace sparse_table
|
||||
* @brief Functions for Implementation of [Sparse
|
||||
* Table](https://brilliant.org/wiki/sparse-table/)
|
||||
*/
|
||||
namespace sparse_table {
|
||||
|
||||
/**
|
||||
* @brief A struct to represent sparse table for `min()` as their invariant
|
||||
* function, for the given array `A`. The answer to queries are stored in the
|
||||
* array ST.
|
||||
*/
|
||||
constexpr uint32_t N = 12345; ///< the maximum size of the array.
|
||||
constexpr uint8_t M = 14; ///< ceil(log2(N)).
|
||||
|
||||
struct Sparse_table {
|
||||
size_t n = 0; ///< size of input array.
|
||||
|
||||
/** @warning check if `N` is not less than `n`. if so, manually increase the
|
||||
* value of N */
|
||||
|
||||
std::array<int64_t, N> A = {}; ///< input array to perform RMQ.
|
||||
std::array<std::array<int64_t, N>, M>
|
||||
ST{}; ///< the sparse table storing `min()` values for given interval.
|
||||
std::array<int64_t, N> LOG = {}; ///< where floor(log2(i)) are precomputed.
|
||||
|
||||
/**
|
||||
* @brief Builds the sparse table for computing min/max/gcd/lcm/...etc
|
||||
* for any contiguous sub-segment of the array.This is an example of
|
||||
* computing the index of the minimum value.
|
||||
* @return void
|
||||
* @complexity: O(n.log(n))
|
||||
*/
|
||||
void buildST() {
|
||||
LOG[0] = -1;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
ST[0][i] = static_cast<int64_t>(i);
|
||||
LOG[i + 1] = LOG[i] + !(i & (i + 1)); ///< precomputing `log2(i+1)`
|
||||
}
|
||||
|
||||
for (size_t j = 1; static_cast<size_t>(1 << j) <= n; ++j) {
|
||||
for (size_t i = 0; static_cast<size_t>(i + (1 << j)) <= n; ++i) {
|
||||
/**
|
||||
* @note notice how we deal with the range of length `pow(2,i)`,
|
||||
* and we can reuse the computation that we did for the range of
|
||||
* length `pow(2,i-1)`.
|
||||
*
|
||||
* So, ST[j][i] = min( ST[j-1][i], ST[j-1][i + pow(2,j-1)]).
|
||||
* @example ST[2][3] = min(ST[1][3], ST[1][5])
|
||||
*/
|
||||
|
||||
int64_t x = ST[j - 1][i]; ///< represents minimum value over
|
||||
///< the range [j,i]
|
||||
int64_t y =
|
||||
ST[j - 1]
|
||||
[i + (1 << (j - 1))]; ///< represents minimum value over
|
||||
///< the range [j,i + pow(2,j-1)]
|
||||
|
||||
ST[j][i] =
|
||||
(A[x] <= A[y] ? x : y); ///< represents minimum value over
|
||||
///< the range [j,i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Queries the sparse table for the value of the interval [l, r]
|
||||
* (i.e. from l to r inclusive).
|
||||
* @param l the left index of the range (inclusive).
|
||||
* @param r the right index of the range (inclusive).
|
||||
* @return the computed value of the given interval.
|
||||
* @complexity: O(1)
|
||||
*/
|
||||
int64_t query(int64_t l, int64_t r) {
|
||||
int64_t g = LOG[r - l + 1]; ///< smallest power of 2 covering [l,r]
|
||||
int64_t x = ST[g][l]; ///< represents minimum value over the range
|
||||
///< [g,l]
|
||||
int64_t y =
|
||||
ST[g][r - (1 << g) + 1]; ///< represents minimum value over the
|
||||
///< range [g, r - pow(2,g) + 1]
|
||||
|
||||
return (A[x] <= A[y] ? x : y); ///< represents minimum value over
|
||||
///< the whole range [l,r]
|
||||
}
|
||||
};
|
||||
} // namespace sparse_table
|
||||
} // namespace data_structures
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
/* We take an array as an input on which we need to perform the ranged
|
||||
* minimum queries[RMQ](https://en.wikipedia.org/wiki/Range_minimum_query).
|
||||
*/
|
||||
std::array<int64_t, 10> testcase = {
|
||||
1, 2, 3, 4, 5,
|
||||
6, 7, 8, 9, 10}; ///< array on which RMQ will be performed.
|
||||
size_t testcase_size =
|
||||
sizeof(testcase) / sizeof(testcase[0]); ///< size of self test's array
|
||||
|
||||
data_structures::sparse_table::Sparse_table
|
||||
st{}; ///< declaring sparse tree
|
||||
|
||||
std::copy(std::begin(testcase), std::end(testcase),
|
||||
std::begin(st.A)); ///< copying array to the struct
|
||||
st.n = testcase_size; ///< passing the array's size to the struct
|
||||
|
||||
st.buildST(); ///< precomputing sparse tree
|
||||
|
||||
// pass queries of the form: [l,r]
|
||||
assert(st.query(1, 9) == 1); ///< as 1 is smallest from 1..9
|
||||
assert(st.query(2, 6) == 2); ///< as 2 is smallest from 2..6
|
||||
assert(st.query(3, 8) == 3); ///< as 3 is smallest from 3..8
|
||||
|
||||
std::cout << "Self-test implementations passed!" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @param argc commandline argument count (ignored)
|
||||
* @param argv commandline array of arguments (ignored)
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
114
dynamic_programming/house_robber.cpp
Normal file
114
dynamic_programming/house_robber.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [House Robber
|
||||
* Problem](https://labuladong.gitbook.io/algo-en/i.-dynamic-programming/houserobber)
|
||||
* algorithm
|
||||
* @details
|
||||
* Solution of House robber problem uses a dynamic programming concept that
|
||||
* works in \f$O(n)\f$ time and works in \f$O(1)\f$ space.
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <climits> /// for std::max
|
||||
#include <iostream> /// for io operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @namespace house_robber
|
||||
* @brief Functions for the [House
|
||||
* Robber](https://labuladong.gitbook.io/algo-en/i.-dynamic-programming/houserobber)
|
||||
* algorithm
|
||||
*/
|
||||
namespace house_robber {
|
||||
/**
|
||||
* @brief The main function that implements the House Robber algorithm using
|
||||
* dynamic programming
|
||||
* @param money array containing money in the ith house
|
||||
* @param n size of array
|
||||
* @returns maximum amount of money that can be robbed
|
||||
*/
|
||||
std::uint32_t houseRobber(const std::vector<uint32_t> &money,
|
||||
const uint32_t &n) {
|
||||
if (n == 0) { // if there is no house
|
||||
return 0;
|
||||
}
|
||||
if (n == 1) { // if there is only one house
|
||||
return money[0];
|
||||
}
|
||||
if (n == 2) { // if there are two houses, one with the maximum amount of
|
||||
// money will be robbed
|
||||
return std::max(money[0], money[1]);
|
||||
}
|
||||
uint32_t max_value = 0; // contains maximum stolen value at the end
|
||||
uint32_t value1 = money[0];
|
||||
uint32_t value2 = std::max(money[0], money[1]);
|
||||
for (uint32_t i = 2; i < n; i++) {
|
||||
max_value = std::max(money[i] + value1, value2);
|
||||
value1 = value2;
|
||||
value2 = max_value;
|
||||
}
|
||||
|
||||
return max_value;
|
||||
}
|
||||
} // namespace house_robber
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Test 1
|
||||
// [1, 2, 3, 1] return 4
|
||||
std::vector<uint32_t> array1 = {1, 2, 3, 1};
|
||||
std::cout << "Test 1... ";
|
||||
assert(
|
||||
dynamic_programming::house_robber::houseRobber(array1, array1.size()) ==
|
||||
4); // here the two non-adjacent houses that are robbed are first and
|
||||
// third with total sum money as 4
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// Test 2
|
||||
// [6, 7, 1, 3, 8, 2, 4] return 19
|
||||
std::vector<uint32_t> array2 = {6, 7, 1, 3, 8, 2, 4};
|
||||
std::cout << "Test 2... ";
|
||||
assert(
|
||||
dynamic_programming::house_robber::houseRobber(array2, array2.size()) ==
|
||||
19); // here the four non-adjacent houses that are robbed are first,
|
||||
// third, fifth and seventh with total sum money as 19
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// Test 3
|
||||
// [] return 0
|
||||
std::vector<uint32_t> array3 = {};
|
||||
std::cout << "Test 3... ";
|
||||
assert(
|
||||
dynamic_programming::house_robber::houseRobber(array3, array3.size()) ==
|
||||
0); // since there is no house no money can be robbed
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// Test 4
|
||||
// [2,7,9,3,1] return 12
|
||||
std::vector<uint32_t> array4 = {2, 7, 9, 3, 1};
|
||||
std::cout << "Test 4... ";
|
||||
assert(
|
||||
dynamic_programming::house_robber::houseRobber(array4, array4.size()) ==
|
||||
12); // here the three non-adjacent houses that are robbed are first,
|
||||
// third and fifth with total sum money as 12
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
@ -1,32 +1,98 @@
|
||||
// Program to calculate length of longest increasing subsequence in an array
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
int LIS(int a[], int n) {
|
||||
int lis[n];
|
||||
/**
|
||||
* @file
|
||||
* @brief Calculate the length of the [longest increasing
|
||||
* subsequence](https://en.wikipedia.org/wiki/Longest_increasing_subsequence) in
|
||||
* an array
|
||||
*
|
||||
* @details
|
||||
* In computer science, the longest increasing subsequence problem is to find a
|
||||
* subsequence of a given sequence in which the subsequence's elements are in
|
||||
* sorted order, lowest to highest, and in which the subsequence is as long as
|
||||
* possible. This subsequence is not necessarily contiguous, or unique. Longest
|
||||
* increasing subsequences are studied in the context of various disciplines
|
||||
* related to mathematics, including algorithmics, random matrix theory,
|
||||
* representation theory, and physics. The longest increasing subsequence
|
||||
* problem is solvable in time O(n log n), where n denotes the length of the
|
||||
* input sequence.
|
||||
*
|
||||
* @author [Krishna Vedala](https://github.com/kvedala)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <climits> /// for std::max
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @brief Calculate the longest increasing subsequence for the specified numbers
|
||||
* @param a the array used to calculate the longest increasing subsequence
|
||||
* @param n the size used for the arrays
|
||||
* @returns the length of the longest increasing
|
||||
* subsequence in the `a` array of size `n`
|
||||
*/
|
||||
uint64_t LIS(const std::vector<uint64_t> &a, const uint32_t &n) {
|
||||
std::vector<int> lis(n);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
lis[i] = 1;
|
||||
}
|
||||
for (int i = 0; i < n; ++i) {
|
||||
for (int j = 0; j < i; ++j) {
|
||||
if (a[i] > a[j] && lis[i] < lis[j] + 1)
|
||||
if (a[i] > a[j] && lis[i] < lis[j] + 1) {
|
||||
lis[i] = lis[j] + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
int res = 0;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
res = max(res, lis[i]);
|
||||
res = std::max(res, lis[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::vector<uint64_t> a = {15, 21, 2, 3, 4, 5, 8, 4, 1, 1};
|
||||
uint32_t n = a.size();
|
||||
|
||||
uint32_t result = dynamic_programming::LIS(a, n);
|
||||
assert(result ==
|
||||
5); ///< The longest increasing subsequence is `{2,3,4,5,8}`
|
||||
|
||||
std::cout << "Self-test implementations passed!" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @param argc commandline argument count (ignored)
|
||||
* @param argv commandline array of arguments (ignored)
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main(int argc, char const *argv[]) {
|
||||
int n;
|
||||
cout << "Enter size of array: ";
|
||||
cin >> n;
|
||||
int a[n];
|
||||
cout << "Enter array elements: ";
|
||||
uint32_t n = 0;
|
||||
|
||||
std::cout << "Enter size of array: ";
|
||||
std::cin >> n;
|
||||
|
||||
std::vector<uint64_t> a(n);
|
||||
|
||||
std::cout << "Enter array elements: ";
|
||||
for (int i = 0; i < n; ++i) {
|
||||
cin >> a[i];
|
||||
std::cin >> a[i];
|
||||
}
|
||||
cout << LIS(a, n) << endl;
|
||||
|
||||
std::cout << "\nThe result is: " << dynamic_programming::LIS(a, n)
|
||||
<< std::endl;
|
||||
test(); // run self-test implementations
|
||||
|
||||
return 0;
|
||||
}
|
@ -29,7 +29,7 @@ bool is_prime(T num) {
|
||||
return 0;
|
||||
}
|
||||
if (num >= 3) {
|
||||
for (T i = 3; (i * i) < (num); i = (i + 2)) {
|
||||
for (T i = 3; (i * i) <= (num); i = (i + 2)) {
|
||||
if ((num % i) == 0) {
|
||||
result = false;
|
||||
break;
|
||||
|
429
operations_on_datastructures/inorder_successor_of_bst.cpp
Normal file
429
operations_on_datastructures/inorder_successor_of_bst.cpp
Normal file
@ -0,0 +1,429 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief An implementation for finding the [Inorder successor of a binary
|
||||
* search tree](https://www.youtube.com/watch?v=5cPbNCrdotA) Inorder
|
||||
* successor of a node is the next node in Inorder traversal of the Binary Tree.
|
||||
* Inorder Successor is NULL for the last node in Inorder traversal.
|
||||
* @details
|
||||
* ### Case 1: The given node has the right node/subtree
|
||||
*
|
||||
* * In this case, the left-most deepest node in the right subtree will
|
||||
* come just after the given node as we go to left deep in inorder.
|
||||
* - Go deep to left most node in right subtree.
|
||||
* OR, we can also say in case if BST, find the minimum of the subtree
|
||||
* for a given node.
|
||||
*
|
||||
* ### Case 2: The given node does not have a right node/subtree
|
||||
*
|
||||
* #### Method 1: Use parent pointer (store the address of parent nodes)
|
||||
* * If a node does not have the right subtree, and we already visited the
|
||||
* node itself, then the next node will be its parent node according to inorder
|
||||
* traversal, and if we are going to parent from left, then the parent would be
|
||||
* unvisited.
|
||||
* * In other words, go to the nearest ancestor for which given node would
|
||||
* be in left subtree.
|
||||
*
|
||||
* #### Method 2: Search from the root node
|
||||
* * In case if there is no link from a child node to the parent node, we
|
||||
* need to walk down the tree starting from the root node to the given node, by
|
||||
* doing so, we are visiting every ancestor of the given node.
|
||||
* * In order successor would be the deepest node in this path for which
|
||||
* given node is in left subtree.
|
||||
*
|
||||
* @author [Nitin Sharma](https://github.com/foo290)
|
||||
* */
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO Operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace operations_on_datastructures
|
||||
* @brief Operations on data structures
|
||||
*/
|
||||
namespace operations_on_datastructures {
|
||||
|
||||
/**
|
||||
* @namespace inorder_successor_of_bst
|
||||
* @brief Functions for the [Inorder successor of a binary search
|
||||
* tree](https://www.youtube.com/watch?v=5cPbNCrdotA) implementation
|
||||
*/
|
||||
namespace inorder_traversal_of_bst {
|
||||
|
||||
/**
|
||||
* @brief A Node structure representing a single node in BST
|
||||
*/
|
||||
class Node {
|
||||
public:
|
||||
int64_t data; ///< The key/value of the node
|
||||
Node *left; ///< Pointer to Left child
|
||||
Node *right; ///< Pointer to right child
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Allocates a new node in heap for given data and returns it's pointer.
|
||||
* @param data Data for the node.
|
||||
* @returns A pointer to the newly allocated Node.
|
||||
* */
|
||||
Node *makeNode(int64_t data) {
|
||||
Node *node = new Node();
|
||||
node->data = data; ///< setting data for node
|
||||
node->left = nullptr; ///< setting left child as null
|
||||
node->right = nullptr; ///< setting right child as null
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts the given data in BST while maintaining the properties of BST.
|
||||
* @param root Pointer to the root node of the BST
|
||||
* @param data Data to be inserted.
|
||||
* @returns Node* Pointer to the root node.
|
||||
* */
|
||||
Node *Insert(Node *root, int64_t data) {
|
||||
if (root == nullptr) {
|
||||
root = makeNode(data);
|
||||
} else if (data <= root->data) {
|
||||
root->left = Insert(root->left, data);
|
||||
} else {
|
||||
root->right = Insert(root->right, data);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Searches the given data in BST and returns the pointer to the node
|
||||
* containing that data.
|
||||
* @param root Pointer to the root node of the BST
|
||||
* @param data Data to be Searched.
|
||||
* @returns Node* pointer to the found node
|
||||
* */
|
||||
Node *getNode(Node *root, int64_t data) {
|
||||
if (root == nullptr) {
|
||||
return nullptr;
|
||||
} else if (root->data == data) {
|
||||
return root; /// Node found!
|
||||
} else if (data > root->data) {
|
||||
/// Traverse right subtree recursively as the given data is greater than
|
||||
/// the data in root node, data must be present in right subtree.
|
||||
return getNode(root->right, data);
|
||||
} else {
|
||||
/// Traverse left subtree recursively as the given data is less than the
|
||||
/// data in root node, data must be present in left subtree.
|
||||
return getNode(root->left, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds and return the minimum node in BST.
|
||||
* @param root A pointer to root node.
|
||||
* @returns Node* Pointer to the found node
|
||||
* */
|
||||
Node *findMinNode(Node *root) {
|
||||
if (root == nullptr) {
|
||||
return root;
|
||||
}
|
||||
while (root->left != nullptr) {
|
||||
root = root->left;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prints the BST in inorder traversal using recursion.
|
||||
* @param root A pointer to the root node of the BST.
|
||||
* @returns void
|
||||
* */
|
||||
void printInorder(Node *root) {
|
||||
if (root == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
printInorder(root->left); /// recursive call to left subtree
|
||||
std::cout << root->data << " ";
|
||||
printInorder(root->right); /// recursive call to right subtree
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is used in test cases to quickly create BST containing
|
||||
* large data instead of hard coding it in code. For a given root, this will add
|
||||
* all the nodes containing data passes in data vector.
|
||||
* @param root Pointer to the root node.
|
||||
* @param data A vector containing integer values which are suppose to be
|
||||
* inserted as nodes in BST.
|
||||
* @returns Node pointer to the root node.
|
||||
* */
|
||||
Node *makeBST(Node *root, const std::vector<int64_t> &data) {
|
||||
for (int64_t values : data) {
|
||||
root = Insert(root, values);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inorder successor of a node is the next node in inorder traversal of
|
||||
* the Binary Tree. This function takes the root node and the data of the node
|
||||
* for which we have to find the inorder successor, and returns the inorder
|
||||
* successor node.
|
||||
* @details Search from the root node as we need to walk the tree starting from
|
||||
* the root node to the given node, by doing so, we are visiting every ancestor
|
||||
* of the given node. In order successor would be the deepest node in this path
|
||||
* for which given node is in left subtree. Time complexity O(h)
|
||||
* @param root A pointer to the root node of the BST
|
||||
* @param data The data (or the data of node) for which we have to find inorder
|
||||
* successor.
|
||||
* @returns Node pointer to the inorder successor node.
|
||||
* */
|
||||
Node *getInorderSuccessor(Node *root, int64_t data) {
|
||||
Node *current = getNode(root, data);
|
||||
if (current == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Case - 1
|
||||
if (current->right != nullptr) {
|
||||
return findMinNode(current->right);
|
||||
}
|
||||
// case - 2
|
||||
else {
|
||||
Node *successor = nullptr;
|
||||
Node *ancestor = root;
|
||||
|
||||
while (ancestor != current && ancestor != nullptr) {
|
||||
// This means my current node is in left of the root node
|
||||
if (current->data < ancestor->data) {
|
||||
successor = ancestor;
|
||||
ancestor = ancestor->left; // keep going left
|
||||
} else {
|
||||
ancestor = ancestor->right;
|
||||
}
|
||||
}
|
||||
return successor; // Nodes with maximum vales will not have a successor
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function clears the memory allocated to entire tree recursively.
|
||||
* Its just for clean up the memory and not relevant to the actual topic.
|
||||
* @param root Root node of the tree.
|
||||
* @returns void
|
||||
* */
|
||||
void deallocate(Node *rootNode) {
|
||||
if (rootNode == nullptr) {
|
||||
return;
|
||||
}
|
||||
deallocate(rootNode->left);
|
||||
deallocate(rootNode->right);
|
||||
delete (rootNode);
|
||||
}
|
||||
|
||||
} // namespace inorder_traversal_of_bst
|
||||
} // namespace operations_on_datastructures
|
||||
|
||||
/**
|
||||
* @brief class encapsulating the necessary test cases
|
||||
*/
|
||||
class TestCases {
|
||||
private:
|
||||
/**
|
||||
* @brief A function to print 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:
|
||||
/**
|
||||
* @brief Executes test cases
|
||||
* @returns void
|
||||
* */
|
||||
void runTests() {
|
||||
log("Running Tests...");
|
||||
|
||||
testCase_1();
|
||||
testCase_2();
|
||||
testCase_3();
|
||||
|
||||
log("Test Cases over!");
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case contains edge case, printing inorder successor of last
|
||||
* node.
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_1() {
|
||||
const operations_on_datastructures::inorder_traversal_of_bst::Node
|
||||
*expectedOutput = nullptr; ///< Expected output of this test
|
||||
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
log("This is test case 1 : ");
|
||||
log("Description:");
|
||||
log(" EDGE CASE : Printing inorder successor for last node in the "
|
||||
"BST, Output will be nullptr.");
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::Node *root =
|
||||
nullptr;
|
||||
std::vector<int64_t> node_data{
|
||||
20, 3, 5, 6, 2, 23, 45, 78, 21}; ///< Data to make nodes in BST
|
||||
|
||||
root = operations_on_datastructures::inorder_traversal_of_bst::makeBST(
|
||||
root,
|
||||
node_data); ///< Adding nodes to BST
|
||||
|
||||
std::cout << "Inorder sequence is : ";
|
||||
operations_on_datastructures::inorder_traversal_of_bst::printInorder(
|
||||
root); ///< Printing inorder to cross-verify.
|
||||
std::cout << std::endl;
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::Node
|
||||
*inorderSuccessor = operations_on_datastructures::
|
||||
inorder_traversal_of_bst::getInorderSuccessor(
|
||||
root, 78); ///< The inorder successor node for given data
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(inorderSuccessor == expectedOutput);
|
||||
log("Assertion check passed!");
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::deallocate(
|
||||
root); /// memory cleanup!
|
||||
|
||||
log("[PASS] : TEST CASE 1 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case which contains main list of 100 elements and sublist
|
||||
* of 20.
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_2() {
|
||||
const int expectedOutput = 21; ///< Expected output of this test
|
||||
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
log("This is test case 2 : ");
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::Node *root =
|
||||
nullptr;
|
||||
std::vector<int64_t> node_data{
|
||||
20, 3, 5, 6, 2, 23, 45, 78, 21}; ///< Data to make nodes in BST
|
||||
|
||||
root = operations_on_datastructures::inorder_traversal_of_bst::makeBST(
|
||||
root,
|
||||
node_data); ///< Adding nodes to BST
|
||||
|
||||
std::cout << "Inorder sequence is : ";
|
||||
operations_on_datastructures::inorder_traversal_of_bst::printInorder(
|
||||
root); ///< Printing inorder to cross-verify.
|
||||
std::cout << std::endl;
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::Node
|
||||
*inorderSuccessor = operations_on_datastructures::
|
||||
inorder_traversal_of_bst::getInorderSuccessor(
|
||||
root, 20); ///< The inorder successor node for given data
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(inorderSuccessor->data == expectedOutput);
|
||||
log("Assertion check passed!");
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::deallocate(
|
||||
root); /// memory cleanup!
|
||||
|
||||
log("[PASS] : TEST CASE 2 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case which contains main list of 50 elements and sublist
|
||||
* of 20.
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_3() {
|
||||
const int expectedOutput = 110; ///< Expected output of this test
|
||||
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
log("This is test case 3 : ");
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::Node *root =
|
||||
nullptr;
|
||||
std::vector<int64_t> node_data{
|
||||
89, 67, 32, 56, 90, 123, 120,
|
||||
110, 115, 6, 78, 7, 10}; ///< Data to make nodes in BST
|
||||
|
||||
root = operations_on_datastructures::inorder_traversal_of_bst::makeBST(
|
||||
root,
|
||||
node_data); ///< Adding nodes to BST
|
||||
|
||||
std::cout << "Inorder sequence is : ";
|
||||
operations_on_datastructures::inorder_traversal_of_bst::printInorder(
|
||||
root); ///< Printing inorder to cross-verify.
|
||||
std::cout << std::endl;
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::Node
|
||||
*inorderSuccessor = operations_on_datastructures::
|
||||
inorder_traversal_of_bst::getInorderSuccessor(
|
||||
root, 90); ///< The inorder successor node for given data
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(inorderSuccessor->data == expectedOutput);
|
||||
log("Assertion check passed!");
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::deallocate(
|
||||
root); /// memory cleanup!
|
||||
|
||||
log("[PASS] : TEST CASE 3 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
TestCases tc;
|
||||
tc.runTests();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @param argc commandline argument count (ignored)
|
||||
* @param argv commandline array of arguments (ignored)
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
test(); // run self-test implementations
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::Node *root =
|
||||
nullptr; ///< root node of the bst
|
||||
std::vector<int64_t> node_data{3, 4, 5,
|
||||
89, 1, 2}; ///< Data to add nodes in BST
|
||||
|
||||
int64_t targetElement = 4; ///< An element to find inorder successor for.
|
||||
root = operations_on_datastructures::inorder_traversal_of_bst::makeBST(
|
||||
root, node_data); ///< Making BST
|
||||
|
||||
operations_on_datastructures::inorder_traversal_of_bst::Node
|
||||
*inorderSuccessor = operations_on_datastructures::
|
||||
inorder_traversal_of_bst::getInorderSuccessor(root, targetElement);
|
||||
|
||||
std::cout << "In-order sequence is : ";
|
||||
operations_on_datastructures::inorder_traversal_of_bst::printInorder(root);
|
||||
std::cout << std::endl;
|
||||
|
||||
if (inorderSuccessor == nullptr) {
|
||||
std::cout << "Inorder successor for last node is NULL" << std::endl;
|
||||
} else {
|
||||
std::cout << "Target element is : " << targetElement << std::endl;
|
||||
std::cout << "Inorder successor for target element is : "
|
||||
<< inorderSuccessor->data << std::endl;
|
||||
}
|
||||
|
||||
deallocate(root); /// memory cleanup!
|
||||
|
||||
return 0;
|
||||
}
|
400
others/iterative_tree_traversals.cpp
Normal file
400
others/iterative_tree_traversals.cpp
Normal file
@ -0,0 +1,400 @@
|
||||
/**
|
||||
* @file
|
||||
* @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.
|
||||
*
|
||||
* ### 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.
|
||||
*
|
||||
* ### 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.
|
||||
*/
|
||||
#include <algorithm> /// for `reverse`
|
||||
#include <cassert> /// for `assert`
|
||||
#include <iostream> /// for I/O operations
|
||||
#include <stack> /// for `stack`
|
||||
#include <vector> /// for `vector`
|
||||
|
||||
/**
|
||||
* @namespace others
|
||||
* @brief Other algorithms
|
||||
*/
|
||||
namespace others {
|
||||
/**
|
||||
* @namespace iterative_tree_traversals
|
||||
* @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.
|
||||
};
|
||||
|
||||
/**
|
||||
* @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.
|
||||
};
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
Node *BinaryTree::createNewNode(int64_t data) {
|
||||
Node *node = new Node();
|
||||
node->data = data;
|
||||
node->left = node->right = nullptr;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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> result; ///< list of values, sorted in pre-order.
|
||||
|
||||
stack.push(root);
|
||||
|
||||
while (!stack.empty()) {
|
||||
result.push_back(stack.top()->data);
|
||||
Node *current = stack.top();
|
||||
stack.pop();
|
||||
|
||||
if (current->right) {
|
||||
stack.push(current->right);
|
||||
}
|
||||
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.
|
||||
* @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> result; ///< List of values, sorted in post-order.
|
||||
|
||||
stack.push(root);
|
||||
|
||||
while (!stack.empty()) {
|
||||
result.push_back(stack.top()->data);
|
||||
Node *current = stack.top();
|
||||
stack.pop();
|
||||
|
||||
if (current->left) {
|
||||
stack.push(current->left);
|
||||
}
|
||||
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.
|
||||
* @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::vector<int64_t> result; ///< List of values, sorted in in-order.
|
||||
|
||||
Node *current = root;
|
||||
|
||||
while (!stack.empty() || current) {
|
||||
while (current) {
|
||||
stack.push(current);
|
||||
current = current->left;
|
||||
}
|
||||
current = stack.top();
|
||||
stack.pop();
|
||||
result.push_back(current->data);
|
||||
current = current->right;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace iterative_tree_traversals
|
||||
} // namespace others
|
||||
|
||||
/**
|
||||
* @brief Test the computed preorder with the actual preorder.
|
||||
* @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) {
|
||||
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
|
||||
|
||||
// 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++) {
|
||||
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 << " ";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test the computed postorder with the actual postorder.
|
||||
* @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) {
|
||||
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.
|
||||
|
||||
// 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++) {
|
||||
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 << " ";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test the computed inorder with the actual inorder.
|
||||
* @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) {
|
||||
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.
|
||||
|
||||
// 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++) {
|
||||
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 << " ";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test the computed preorder with the actual preorder on negative value.
|
||||
* @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) {
|
||||
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
|
||||
|
||||
// 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++) {
|
||||
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 << " ";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
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.
|
||||
|
||||
// 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++) {
|
||||
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 << " ";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test the computed inorder with the actual inorder on negative value.
|
||||
* @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) {
|
||||
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.
|
||||
|
||||
// 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++) {
|
||||
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 << " ";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
// Creating a tree with the following structure,
|
||||
/*
|
||||
1
|
||||
/ \
|
||||
2 3
|
||||
/ \
|
||||
4 5
|
||||
*/
|
||||
|
||||
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;
|
||||
test1(binaryTree, root); // run preorder-iterative test
|
||||
std::cout << "\nPre-order test Passed!" << std::endl;
|
||||
|
||||
test2(binaryTree, root); // run postorder-iterative test
|
||||
std::cout << "\nPost-order test Passed!" << std::endl;
|
||||
|
||||
test3(binaryTree, root); // run inorder-iterative test
|
||||
std::cout << "\nIn-order test Passed!" << std::endl;
|
||||
|
||||
// Modifying tree for negative values.
|
||||
root->data = -1;
|
||||
root->left->data = -2;
|
||||
root->right->data = -3;
|
||||
root->left->left->data = -4;
|
||||
root->left->right->data = -5;
|
||||
|
||||
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;
|
||||
|
||||
test5(binaryTree, root); // run postorder-iterative test on negative values
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
96
search/floyd_cycle_detection_algo.cpp
Normal file
96
search/floyd_cycle_detection_algo.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Floyd's Cycle
|
||||
* Detection](https://en.wikipedia.org/wiki/Cycle_detection) algorithm
|
||||
* @details
|
||||
* Given an array of integers containing 'n + 1' integers, where each
|
||||
* integer is in the range [1, n] inclusive. If there is only one duplicate
|
||||
* number in the input array, this algorithm returns the duplicate number in
|
||||
* O(1) space and the time complexity is less than O(n^2) without modifying the
|
||||
* original array, otherwise, it returns -1.
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace search
|
||||
* @brief Search algorithms
|
||||
*/
|
||||
namespace search {
|
||||
/**
|
||||
* @namespace cycle_detection
|
||||
* @brief Functions for the [Floyd's Cycle
|
||||
* Detection](https://en.wikipedia.org/wiki/Cycle_detection) algorithm
|
||||
*/
|
||||
namespace cycle_detection {
|
||||
/**
|
||||
* @brief The main function implements search algorithm
|
||||
* @tparam T type of array
|
||||
* @param in_arr the input array
|
||||
* @param n size of array
|
||||
* @returns the duplicate number
|
||||
*/
|
||||
template <typename T>
|
||||
int32_t duplicateNumber(const std::vector<T> &in_arr, const uint32_t &n) {
|
||||
if (n == 0 || n == 1) { // to find duplicate in an array its size should be atleast 2
|
||||
return -1;
|
||||
}
|
||||
uint32_t tortoise = in_arr[0]; // variable tortoise is used for the longer
|
||||
// jumps in the array
|
||||
uint32_t hare = in_arr[0]; // variable hare is used for shorter jumps in the array
|
||||
do {
|
||||
tortoise = in_arr[tortoise];
|
||||
hare = in_arr[in_arr[hare]];
|
||||
} while (tortoise != hare);
|
||||
tortoise = in_arr[0];
|
||||
while (tortoise != hare) {
|
||||
tortoise = in_arr[tortoise];
|
||||
hare = in_arr[hare];
|
||||
}
|
||||
return tortoise;
|
||||
}
|
||||
} // namespace cycle_detection
|
||||
} // namespace search
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
// [3, 4, 8, 5, 9, 1, 2, 6, 7, 4] return 4
|
||||
std::vector<uint32_t> array1 = {3, 4, 8, 5, 9, 1, 2, 6, 7, 4};
|
||||
std::cout << "Test 1... ";
|
||||
assert(search::cycle_detection::duplicateNumber(array1, array1.size()) ==
|
||||
4); // here the duplicate number is 4
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 2nd test
|
||||
// [1, 2, 3, 4, 2] return 2
|
||||
std::vector<uint32_t> array2 = {1, 2, 3, 4, 2};
|
||||
std::cout << "Test 2... ";
|
||||
assert(search::cycle_detection::duplicateNumber(array2, array2.size()) ==
|
||||
2); // here the duplicate number is 2
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 3rd test
|
||||
// [] return -1
|
||||
std::vector<uint32_t> array3 = {};
|
||||
std::cout << "Test 3... ";
|
||||
assert(search::cycle_detection::duplicateNumber(array3, array3.size()) ==
|
||||
-1); // since the input array is empty no duplicate number exists in
|
||||
// this case
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
370
search/sublist_search.cpp
Normal file
370
search/sublist_search.cpp
Normal file
@ -0,0 +1,370 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Sublist Search
|
||||
* Algorithm](https://www.geeksforgeeks.org/sublist-search-search-a-linked-list-in-another-list)
|
||||
* @details
|
||||
*
|
||||
* ### Algorithm
|
||||
*
|
||||
* * Sublist search is used to detect a presence of one list in another list.
|
||||
* * Suppose we have a single-node list (let's say the first list), and we
|
||||
* want to ensure that the list is present in another list (let's say the
|
||||
* second list), then we can perform the sublist search to find it.
|
||||
*
|
||||
* * For instance, the first list contains these elements: 23 -> 30 -> 41,
|
||||
* and the second list contains these elements: 10 -> 15 -> 23 -> 30 -> 41
|
||||
* -> 49. At a glance, we see that the first list presents in the second list.
|
||||
*
|
||||
* ### Working
|
||||
*
|
||||
* * The sublist search algorithm works by comparing the first element
|
||||
* of the first list with the first element of the second list.
|
||||
* * If the two values don't match, it goes to the next element of the
|
||||
* second list. It does this until the two values match.
|
||||
*
|
||||
* @author [Nitin Sharma](https://github.com/foo290)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace search
|
||||
* @brief Searching algorithms
|
||||
*/
|
||||
namespace search {
|
||||
/**
|
||||
* @namespace sublist_search
|
||||
* @brief Functions for the [Sublist
|
||||
* Search](https://www.geeksforgeeks.org/sublist-search-search-a-linked-list-in-another-list)
|
||||
* implementation
|
||||
*/
|
||||
namespace sublist_search {
|
||||
/**
|
||||
* @brief A Node structure representing a single link Node in a linked list
|
||||
*/
|
||||
struct Node {
|
||||
uint32_t data = 0; ///< the key/value of the node
|
||||
Node *next{}; ///< pointer to the next node
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A simple function to print the linked list
|
||||
* @param start The head of the linked list
|
||||
* @returns void
|
||||
*/
|
||||
void printLinkedList(Node *start) {
|
||||
while (start != nullptr) {
|
||||
std::cout << "->" << start->data;
|
||||
start = start->next;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Give a vector of data,
|
||||
* it adds each element of vector in the linked list and return the address of
|
||||
* head pointer.
|
||||
* @param data A vector of "int" containing the data that is supposed to be
|
||||
* stored in nodes of linked list.
|
||||
* @returns Node* A head pointer to the linked list.
|
||||
*/
|
||||
Node *makeLinkedList(const std::vector<uint64_t> &data) {
|
||||
/// This is used in test cases for rapidly creating linked list with 100+
|
||||
/// elements, instead of hard-coding 100 elements in test cases.
|
||||
Node *head = nullptr;
|
||||
Node *tail = nullptr;
|
||||
for (int i : data) {
|
||||
Node *node = new Node;
|
||||
node->data = i;
|
||||
node->next = nullptr;
|
||||
if (head == nullptr) {
|
||||
head = node;
|
||||
tail = node;
|
||||
} else {
|
||||
tail->next = node;
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main searching function
|
||||
* @param sublist A linked list which is supposed to be searched in mainList.
|
||||
* @param mainList A linked list in which sublist will be searched.
|
||||
* @returns true if the sublist is found
|
||||
* @returns false if the sublist is NOT found
|
||||
*/
|
||||
bool sublistSearch(Node *sublist, Node *mainList) {
|
||||
if (sublist == nullptr || mainList == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Initialize target pointer to the head node of sublist.
|
||||
Node *target_ptr = sublist;
|
||||
|
||||
while (mainList != nullptr) {
|
||||
/// Initialize main pointer to the current node of main list.
|
||||
Node *main_ptr = mainList;
|
||||
|
||||
while (target_ptr != nullptr) {
|
||||
if (main_ptr == nullptr) {
|
||||
return false;
|
||||
|
||||
} else if (main_ptr->data == target_ptr->data) {
|
||||
/// If the data of target node and main node is equal then move
|
||||
/// to the next node of both lists.
|
||||
target_ptr = target_ptr->next;
|
||||
main_ptr = main_ptr->next;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target_ptr == nullptr) {
|
||||
/// Is target pointer becomes null that means the target list is
|
||||
/// been traversed without returning false. Which means the sublist
|
||||
/// has been found and return ture.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// set the target pointer again to stating point of target list.
|
||||
target_ptr = sublist;
|
||||
|
||||
/// set the main pointer to the next element of the main list and repeat
|
||||
/// the algo.
|
||||
mainList = mainList->next;
|
||||
}
|
||||
|
||||
/// If the main list is exhausted, means sublist does not found, return
|
||||
/// false
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace sublist_search
|
||||
} // namespace search
|
||||
|
||||
/**
|
||||
* @brief class encapsulating the necessary test cases
|
||||
*/
|
||||
class TestCases {
|
||||
private:
|
||||
/**
|
||||
* @brief A function to print 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:
|
||||
/**
|
||||
* @brief Executes test cases
|
||||
* @returns void
|
||||
* */
|
||||
void runTests() {
|
||||
log("Running Tests...");
|
||||
|
||||
testCase_1();
|
||||
testCase_2();
|
||||
testCase_3();
|
||||
|
||||
log("Test Cases over!");
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case contains edge case, Only contains one element.
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_1() {
|
||||
const bool expectedOutput = true; ///< Expected output of this test
|
||||
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
log("This is test case 1 for sublist search Algorithm : ");
|
||||
log("Description:");
|
||||
log(" EDGE CASE : Only contains one element");
|
||||
|
||||
std::vector<uint64_t> sublistData = {
|
||||
6}; ///< Data to make linked list which will be the sublist
|
||||
std::vector<uint64_t> mainlistData = {
|
||||
2, 5, 6, 7,
|
||||
8}; ///< Data to make linked list which will be the main list
|
||||
|
||||
search::sublist_search::Node *sublistLL =
|
||||
search::sublist_search::makeLinkedList(
|
||||
sublistData); ///< Sublist to be searched
|
||||
search::sublist_search::Node *mainlistLL =
|
||||
search::sublist_search::makeLinkedList(
|
||||
mainlistData); ///< Main list in which sublist is to be
|
||||
///< searched
|
||||
|
||||
bool exists = search::sublist_search::sublistSearch(
|
||||
sublistLL, mainlistLL); ///< boolean, if sublist exist or not
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(exists == expectedOutput);
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 1 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
|
||||
delete (sublistLL);
|
||||
delete (mainlistLL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case which contains main list of 100 elements and sublist
|
||||
* of 20.
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_2() {
|
||||
const bool expectedOutput = true; /// Expected output of this test
|
||||
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
log("This is test case 2 for sublist search Algorithm : ");
|
||||
log("Description:");
|
||||
log(" contains main list of 100 elements and sublist of 20");
|
||||
|
||||
std::vector<uint64_t> sublistData(
|
||||
20); ///< Data to make linked list which will be the sublist
|
||||
std::vector<uint64_t> mainlistData(
|
||||
100); ///< Main list in which sublist is to be searched
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
/// Inserts 100 elements in main list
|
||||
mainlistData[i] = i + 1;
|
||||
}
|
||||
|
||||
int temp = 0;
|
||||
for (int i = 45; i < 65; i++) {
|
||||
/// Inserts 20 elements in sublist
|
||||
sublistData[temp] = i + 1;
|
||||
temp++;
|
||||
}
|
||||
|
||||
search::sublist_search::Node *sublistLL =
|
||||
search::sublist_search::makeLinkedList(
|
||||
sublistData); ///< Sublist to be searched
|
||||
search::sublist_search::Node *mainlistLL =
|
||||
search::sublist_search::makeLinkedList(
|
||||
mainlistData); ///< Main list in which sublist is to be
|
||||
///< searched
|
||||
|
||||
bool exists = search::sublist_search::sublistSearch(
|
||||
sublistLL, mainlistLL); ///< boolean, if sublist exist or not
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(exists == expectedOutput);
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 2 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case which contains main list of 50 elements and sublist
|
||||
* of 20.
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_3() {
|
||||
const bool expectedOutput = false; ///< Expected output of this test
|
||||
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
log("This is test case 3 for sublist search Algorithm : ");
|
||||
log("Description:");
|
||||
log(" contains main list of 50 elements and sublist of 20");
|
||||
|
||||
std::vector<uint64_t> sublistData(20); ///< Sublist to be searched
|
||||
std::vector<uint64_t> mainlistData(
|
||||
50); ///< Main list in which sublist is to be searched
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
/// Inserts 100 elements in main list
|
||||
mainlistData.push_back(i + 1);
|
||||
}
|
||||
|
||||
for (int i = 45; i < 65; i++) {
|
||||
/// Inserts 20 elements in sublist
|
||||
sublistData.push_back(i + 1);
|
||||
}
|
||||
|
||||
search::sublist_search::Node *sublistLL =
|
||||
search::sublist_search::makeLinkedList(
|
||||
sublistData); ///< Sublist to be searched
|
||||
search::sublist_search::Node *mainlistLL =
|
||||
search::sublist_search::makeLinkedList(
|
||||
mainlistData); ///< Main list in which sublist is to be
|
||||
///< searched
|
||||
|
||||
bool exists = search::sublist_search::sublistSearch(
|
||||
sublistLL, mainlistLL); ///< boolean, if sublist exist or not
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(exists == expectedOutput);
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 3 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
TestCases tc;
|
||||
tc.runTests();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @param argc commandline argument count (ignored)
|
||||
* @param argv commandline array of arguments (ignored)
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
test(); // run self-test implementations
|
||||
|
||||
std::vector<uint64_t> mainlistData = {
|
||||
2, 5, 6, 7, 8}; ///< Main list in which sublist is to be searched
|
||||
std::vector<uint64_t> sublistData = {6, 8}; ///< Sublist to be searched
|
||||
|
||||
search::sublist_search::Node *mainlistLL =
|
||||
search::sublist_search::makeLinkedList(mainlistData);
|
||||
search::sublist_search::Node *sublistLL =
|
||||
search::sublist_search::makeLinkedList(
|
||||
sublistData); ///< Main list in which sublist is to be
|
||||
///< searched
|
||||
|
||||
bool exists = search::sublist_search::sublistSearch(
|
||||
sublistLL,
|
||||
mainlistLL); ///< boolean to check if the sublist exists or not
|
||||
|
||||
std::cout << "Sublist: " << std::endl;
|
||||
search::sublist_search::printLinkedList(sublistLL);
|
||||
|
||||
std::cout << "Main list: " << std::endl;
|
||||
search::sublist_search::printLinkedList(mainlistLL);
|
||||
std::cout << std::endl;
|
||||
|
||||
if (exists) {
|
||||
std::cout << "[TRUE] - sublist found in main list\n";
|
||||
} else {
|
||||
std::cout << "[FALSE] - sublist NOT found in main list\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -2,14 +2,12 @@
|
||||
* @file
|
||||
* @brief Implementation of [Cycle
|
||||
* sort](https://en.wikipedia.org/wiki/Cycle_sort) algorithm
|
||||
*
|
||||
* @details
|
||||
* Cycle Sort is a sorting algorithm that works in \f$O(n^2)\f$ time in best cas
|
||||
* and works in \f$O(n^2)\f$ in worst case. If a element is already at its
|
||||
* Cycle Sort is a sorting algorithm that works in \f$O(n^2)\f$ time in the best
|
||||
* case and works in \f$O(n^2)\f$ in worst case. If a element is already at its
|
||||
* correct position, do nothing. If a element is not at its correct position,
|
||||
* we then need to move it to its correct position by computing the correct
|
||||
* positions.Therefore, we should make sure the duplicate elements.
|
||||
*
|
||||
* @author [TsungHan Ho](https://github.com/dalaoqi)
|
||||
*/
|
||||
|
||||
@ -38,14 +36,14 @@ namespace cycle_sort {
|
||||
template <typename T>
|
||||
std::vector<T> cycleSort(const std::vector<T> &in_arr) {
|
||||
std::vector<T> arr(in_arr);
|
||||
for (size_t cycle_start = 0; cycle_start <= arr.size() - 1; cycle_start++) {
|
||||
for (int cycle_start = 0; cycle_start <= arr.size() - 1; cycle_start++) {
|
||||
// initialize item
|
||||
T item = arr[cycle_start];
|
||||
|
||||
// Count the number of elements smaller than item, this number is the
|
||||
// correct index of item.
|
||||
int pos = cycle_start;
|
||||
for (size_t i = cycle_start + 1; i < arr.size(); i++) {
|
||||
for (int i = cycle_start + 1; i < arr.size(); i++) {
|
||||
if (arr[i] < item) {
|
||||
pos++;
|
||||
}
|
||||
@ -58,8 +56,11 @@ std::vector<T> cycleSort(const std::vector<T> &in_arr) {
|
||||
|
||||
// duplicate elements
|
||||
while (item == arr[pos]) pos += 1;
|
||||
if (pos == cycle_start) {
|
||||
continue;
|
||||
} else {
|
||||
std::swap(item, arr[pos]);
|
||||
|
||||
}
|
||||
// Rest of the elements
|
||||
while (pos != cycle_start) {
|
||||
pos = cycle_start;
|
||||
@ -71,9 +72,13 @@ std::vector<T> cycleSort(const std::vector<T> &in_arr) {
|
||||
}
|
||||
// duplicate elements
|
||||
while (item == arr[pos]) pos += 1;
|
||||
if (item == arr[pos]) {
|
||||
continue;
|
||||
} else {
|
||||
std::swap(item, arr[pos]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
} // namespace cycle_sort
|
||||
@ -84,11 +89,11 @@ std::vector<T> cycleSort(const std::vector<T> &in_arr) {
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// [506, 48, 123, 79, 0, 362, 951, 500, 0] return [0, 0, 48, 79, 123, 362,
|
||||
// 500, 506, 951]
|
||||
std::vector<int> array1 = {506, 48, 123, 79, 0, 362, 951, 500, 0};
|
||||
// Test 1
|
||||
// [4, 3, 2, 1] return [1, 2, 3, 4]
|
||||
std::vector<uint32_t> array1 = {4, 3, 2, 1};
|
||||
std::cout << "Test 1... ";
|
||||
std::vector<int> arr1 = sorting::cycle_sort::cycleSort(array1);
|
||||
std::vector<uint32_t> arr1 = sorting::cycle_sort::cycleSort(array1);
|
||||
assert(std::is_sorted(std::begin(arr1), std::end(arr1)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
@ -98,6 +103,21 @@ static void test() {
|
||||
std::vector<double> arr2 = sorting::cycle_sort::cycleSort(array2);
|
||||
assert(std::is_sorted(std::begin(arr2), std::end(arr2)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// Test 3
|
||||
// [3, 3, 3, 3] return [3, 3, 3, 3]
|
||||
std::vector<uint32_t> array3 = {3, 3, 3, 3};
|
||||
std::cout << "Test 3... ";
|
||||
std::vector<uint32_t> arr3 = sorting::cycle_sort::cycleSort(array3);
|
||||
assert(std::is_sorted(std::begin(arr3), std::end(arr3)));
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// [9, 4, 6, 8, 14, 3] return [9, 4, 6, 8, 14, 3]
|
||||
std::vector<uint32_t> array4 = {3, 4, 6, 8, 9, 14};
|
||||
std::cout << "Test 4... ";
|
||||
std::vector<uint32_t> arr4 = sorting::cycle_sort::cycleSort(array4);
|
||||
assert(std::is_sorted(std::begin(arr4), std::end(arr4)));
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
339
sorting/random_pivot_quick_sort.cpp
Normal file
339
sorting/random_pivot_quick_sort.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
/**
|
||||
* @file
|
||||
* @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.
|
||||
*
|
||||
* ### 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.
|
||||
*
|
||||
* ### 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.
|
||||
*
|
||||
* ### 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.
|
||||
* * Return the partition index from the function.
|
||||
*
|
||||
* @author [Nitin Sharma](https://github.com/foo290)
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
} // namespace random_pivot_quick_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief a class containing the necessary test cases
|
||||
*/
|
||||
class TestCases {
|
||||
private:
|
||||
/**
|
||||
* @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:
|
||||
/**
|
||||
* @brief Executes test cases
|
||||
* @returns void
|
||||
* */
|
||||
void runTests() {
|
||||
log("Running Tests...");
|
||||
|
||||
testCase_1();
|
||||
testCase_2();
|
||||
testCase_3();
|
||||
|
||||
log("Test Cases over!");
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case with single input
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_1() {
|
||||
const int64_t inputSize = 1;
|
||||
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};
|
||||
|
||||
int64_t start = 0;
|
||||
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);
|
||||
log("Algorithm finished!");
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(std::is_sorted(sorted_arr.begin(), sorted_arr.end()));
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 1 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case with input array of length 500
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_2() {
|
||||
const int64_t inputSize = 500;
|
||||
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);
|
||||
|
||||
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);
|
||||
log("Algorithm finished!");
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(std::is_sorted(sorted_arr.begin(), sorted_arr.end()));
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 2 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A test case with array of length 1000.
|
||||
* @returns void
|
||||
* */
|
||||
void testCase_3() {
|
||||
const int64_t inputSize = 1000;
|
||||
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);
|
||||
|
||||
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);
|
||||
log("Algorithm finished!");
|
||||
|
||||
log("Checking assert expression...");
|
||||
assert(std::is_sorted(sorted_arr.begin(), sorted_arr.end()));
|
||||
log("Assertion check passed!");
|
||||
|
||||
log("[PASS] : TEST CASE 3 PASS!");
|
||||
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
"~");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
TestCases tc = TestCases();
|
||||
tc.runTests();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @param argc commandline argument count (ignored)
|
||||
* @param argv commandline array of arguments (ignored)
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
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::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::cout << "Sorted array is : " << std::endl;
|
||||
sorting::random_pivot_quick_sort::showArray(sorted_array);
|
||||
return 0;
|
||||
}
|
94
sorting/wave_sort.cpp
Normal file
94
sorting/wave_sort.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Wave
|
||||
* sort](https://www.geeksforgeeks.org/sort-array-wave-form-2/) algorithm
|
||||
* @details
|
||||
* Wave Sort is a sorting algorithm that works in \f$O(nlogn)\f$ time assuming
|
||||
* the sort function used works in \f$O(nlogn)\f$ time.
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::is_sorted, std::swap
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace sorting
|
||||
* @brief Sorting algorithms
|
||||
*/
|
||||
namespace sorting {
|
||||
/**
|
||||
* @namespace wave_sort
|
||||
* @brief Functions for the [Wave
|
||||
* sort](https://www.geeksforgeeks.org/sort-array-wave-form-2/) implementation
|
||||
*/
|
||||
namespace wave_sort {
|
||||
/**
|
||||
* @brief The main function implements that implements the Wave Sort algorithm
|
||||
* @tparam T type of array
|
||||
* @param in_arr array to be sorted
|
||||
* @returns arr the wave sorted array
|
||||
*/
|
||||
template <typename T>
|
||||
std::vector<T> waveSort(const std::vector<T> &in_arr, int64_t n) {
|
||||
std::vector<T> arr(in_arr);
|
||||
|
||||
for (int64_t i = 0; i < n; i++) {
|
||||
arr[i] = in_arr[i];
|
||||
}
|
||||
std::sort(arr.begin(), arr.end());
|
||||
for (int64_t i = 0; i < n - 1; i += 2) { // swap all the adjacent elements
|
||||
std::swap(arr[i], arr[i + 1]);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
} // namespace wave_sort
|
||||
} // namespace sorting
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// [10, 90, 49, 2, 1, 5, 23] return [2, 1, 10, 5, 49, 23, 90]
|
||||
std::vector<int64_t> array1 = {10, 90, 49, 2, 1, 5, 23};
|
||||
std::cout << "Test 1... ";
|
||||
std::vector<int64_t> arr1 = sorting::wave_sort::waveSort(array1, 7);
|
||||
const std::vector<int64_t> o1 = {2, 1, 10, 5, 49, 23, 90};
|
||||
assert(arr1 == o1);
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// [1, 3, 4, 2, 7, 8] return [2, 1, 4, 3, 8, 7]
|
||||
std::vector<int64_t> array2 = {1, 3, 4, 2, 7, 8};
|
||||
std::cout << "Test 2... ";
|
||||
std::vector<int64_t> arr2 = sorting::wave_sort::waveSort(array2, 6);
|
||||
const std::vector<int64_t> o2 = {2, 1, 4, 3, 8, 7};
|
||||
assert(arr2 == o2);
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// [3, 3, 3, 3] return [3, 3, 3, 3]
|
||||
std::vector<int64_t> array3 = {3, 3, 3, 3};
|
||||
std::cout << "Test 3... ";
|
||||
std::vector<int64_t> arr3 = sorting::wave_sort::waveSort(array3, 4);
|
||||
const std::vector<int64_t> o3 = {3, 3, 3, 3};
|
||||
assert(arr3 == o3);
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// [9, 4, 6, 8, 14, 3] return [4, 3, 8, 6, 14, 9]
|
||||
std::vector<int64_t> array4 = {9, 4, 6, 8, 14, 3};
|
||||
std::cout << "Test 4... ";
|
||||
std::vector<int64_t> arr4 = sorting::wave_sort::waveSort(array4, 6);
|
||||
const std::vector<int64_t> o4 = {4, 3, 8, 6, 14, 9};
|
||||
assert(arr4 == o4);
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user