├── .github ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml └── workflows │ └── c-cpp.yml ├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── _config.yml ├── cpp ├── CMakeLists.txt ├── Makefile ├── include │ ├── algorithm │ │ ├── backtracking │ │ │ ├── README.md │ │ │ └── n_queens.hpp │ │ ├── dynamic_programming │ │ │ ├── 0_1_knapsack.hpp │ │ │ ├── README.md │ │ │ ├── coin_change.hpp │ │ │ ├── kadane.hpp │ │ │ ├── longest_decreasing_subsequence.hpp │ │ │ ├── matrix_chain_multiplication.hpp │ │ │ ├── rod_cutting.hpp │ │ │ └── weighted_activity_selection.hpp │ │ ├── number_theory │ │ │ ├── binomial_coefficient.hpp │ │ │ ├── extended_euclidean.hpp │ │ │ ├── fast_exponentiation.hpp │ │ │ ├── fibonacci.hpp │ │ │ ├── fibonacci_efficient.hpp │ │ │ ├── greatest_common_divisor.hpp │ │ │ ├── perfect_number_check.hpp │ │ │ ├── primorial.hpp │ │ │ └── sieve_of_eratosthenes.hpp │ │ ├── searching │ │ │ ├── README.md │ │ │ ├── binary_search.hpp │ │ │ ├── linear_search.hpp │ │ │ └── ternary_search.hpp │ │ ├── sorting │ │ │ ├── README.md │ │ │ ├── bubble_sort.hpp │ │ │ ├── bucket_sort.hpp │ │ │ ├── comb_sort.hpp │ │ │ ├── counting_sort.hpp │ │ │ ├── heap_sort.hpp │ │ │ ├── insertion_sort.hpp │ │ │ ├── merge_sort.hpp │ │ │ ├── quick_sort.hpp │ │ │ ├── radix_sort.hpp │ │ │ ├── selection_sort.hpp │ │ │ ├── shell_sort.hpp │ │ │ └── utils.hpp │ │ └── string │ │ │ ├── edit_distance.hpp │ │ │ ├── heaps_algorithm.hpp │ │ │ ├── knuth_morris_pratt.hpp │ │ │ ├── longest_common_subsequence.hpp │ │ │ └── shunting_yard.hpp │ ├── data_structure │ │ ├── linked_list │ │ │ ├── doubly_linked_list.hpp │ │ │ └── singly_linked_list.hpp │ │ ├── queue │ │ │ └── queue.hpp │ │ ├── set │ │ │ └── disjoint_set.hpp │ │ ├── stack │ │ │ └── stack.hpp │ │ └── tree │ │ │ ├── README.md │ │ │ ├── binary_search_tree.hpp │ │ │ └── fenwick_tree.hpp │ └── third_party │ │ └── catch.hpp ├── scripts │ └── run_tests.sh └── test │ ├── algorithm │ ├── backtracking │ │ └── n_queens.cpp │ ├── dynamic_programming │ │ ├── 0_1_knapsack.cpp │ │ ├── coin_change.cpp │ │ ├── kadane.cpp │ │ ├── longest_decreasing_subsequence.cpp │ │ ├── matrix_chain_multiplication.cpp │ │ ├── rod_cutting.cpp │ │ └── weighted_activity_selection.cpp │ ├── number_theory │ │ ├── binomial_coefficient.cpp │ │ ├── extended_euclidean.cpp │ │ ├── fast_exponentiation.cpp │ │ ├── fibonacci.cpp │ │ ├── fibonacci_efficient.cpp │ │ ├── greatest_common_divisor.cpp │ │ ├── perfect_number_check.cpp │ │ ├── primorial.cpp │ │ └── sieve_of_eratosthenes.cpp │ ├── searching │ │ ├── binary_search.cpp │ │ ├── linear_search.cpp │ │ └── ternary_search.cpp │ ├── sorting │ │ └── sorting.cpp │ └── string │ │ ├── edit_distance.cpp │ │ ├── heaps_algorithm.cpp │ │ ├── knuth_morris_pratt.cpp │ │ ├── longest_common_subsequence.cpp │ │ └── shunting_yard.cpp │ ├── data_structure │ ├── linked_list │ │ ├── doubly_linked_list.cpp │ │ └── singly_linked_list.cpp │ ├── queue │ │ └── queue.cpp │ ├── set │ │ └── disjoint_set.cpp │ ├── stack │ │ └── stack.cpp │ └── tree │ │ ├── binary_search_tree.cpp │ │ └── fenwick_tree.cpp │ └── test_runner.cpp └── docs ├── CODE_OF_CONDUCT.md ├── CODING_GUIDELINES.md └── CONTRIBUTING.md /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | - [ ] Read the [contribution guidelines][contrib-guidelines] 8 | - [ ] Added [unit tests][unit-tests] (or unit tests have already been added) 9 | - [ ] Updated the [Contents][contents] 10 | 11 | 12 | 14 | 15 | 16 | 17 | [contrib-guidelines]: https://github.com/ProAlgos/ProAlgos-Cpp/blob/master/docs/CONTRIBUTING.md#contribution-guidelines 18 | [unit-tests]: https://github.com/ProAlgos/ProAlgos-Cpp/blob/master/docs/CONTRIBUTING.md#testing-code 19 | [contents]: https://github.com/ProAlgos/ProAlgos-Cpp/blob/master/README.md#contents 20 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 15 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - Bug 8 | - Easy 9 | - Good first issue 10 | - On hold 11 | - Pinned 12 | - 'Priority: high' 13 | - Review pending 14 | - Up for grabs 15 | # Label to use when marking an issue as stale 16 | staleLabel: Inactive 17 | # Comment to post when marking an issue as stale. Set to `false` to disable 18 | markComment: > 19 | This issue has been automatically marked as inactive because it has not had 20 | recent activity. It will be closed in 15 days if no further activity occurs. 21 | Thank you for your contributions. 22 | # Comment to post when closing a stale issue. Set to `false` to disable 23 | closeComment: false 24 | -------------------------------------------------------------------------------- /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: make 17 | run: cd cpp && make 18 | - name: make test 19 | run: cd cpp && make test 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries 2 | bin/ 3 | 4 | # Intermediate build files 5 | build/ 6 | 7 | # Files related to IDE and code editors 8 | .idea/ 9 | .vscode/ 10 | *.swp 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: cpp 3 | 4 | matrix: 5 | include: 6 | # Linux GCC 7 build 7 | - os: linux 8 | compiler: gcc 9 | addons: 10 | apt: 11 | sources: 12 | - ubuntu-toolchain-r-test 13 | packages: 14 | - g++-7 15 | env: 16 | - COMPILER='g++-7' 17 | 18 | # Linux GCC 8 build 19 | - os: linux 20 | compiler: gcc 21 | addons: 22 | apt: 23 | sources: 24 | - ubuntu-toolchain-r-test 25 | packages: 26 | - g++-8 27 | env: 28 | - COMPILER='g++-8' 29 | 30 | # Linux GCC 9 build 31 | - os: linux 32 | compiler: gcc 33 | addons: 34 | apt: 35 | sources: 36 | - ubuntu-toolchain-r-test 37 | packages: 38 | - g++-9 39 | env: 40 | - COMPILER='g++-9' 41 | 42 | # Linux Clang 6 build 43 | - os: linux 44 | compiler: clang 45 | addons: 46 | apt: 47 | packages: 48 | - clang-6.0 49 | env: 50 | - COMPILER='clang++-6.0' 51 | 52 | # Linux Clang 7 build 53 | - os: linux 54 | compiler: clang 55 | addons: 56 | apt: 57 | sources: 58 | - llvm-toolchain-xenial-7 59 | packages: 60 | - clang-7 61 | env: 62 | - COMPILER='clang++-7' 63 | 64 | # Linux Clang 8 build 65 | - os: linux 66 | compiler: clang 67 | addons: 68 | apt: 69 | sources: 70 | - llvm-toolchain-xenial-8 71 | packages: 72 | - clang-8 73 | env: 74 | - COMPILER='clang++-8' 75 | 76 | # macOS Xcode8 GCC build 77 | - os: osx 78 | osx_image: xcode8.3 79 | compiler: gcc 80 | env: 81 | - COMPILER='g++' 82 | 83 | # macOS Xcode9 GCC build 84 | - os: osx 85 | osx_image: xcode9.4 86 | compiler: gcc 87 | env: 88 | - COMPILER='g++' 89 | 90 | # macOS Xcode10 GCC build 91 | - os: osx 92 | osx_image: xcode10.2 93 | compiler: gcc 94 | env: 95 | - COMPILER='g++' 96 | 97 | # macOS Xcode8 Clang build 98 | - os: osx 99 | osx_image: xcode8.3 100 | compiler: clang 101 | env: 102 | - COMPILER='clang++' 103 | 104 | # macOS Xcode9 Clang build 105 | - os: osx 106 | osx_image: xcode9.4 107 | compiler: clang 108 | env: 109 | - COMPILER='clang++' 110 | 111 | # macOS Xcode10 Clang build 112 | - os: osx 113 | osx_image: xcode10.2 114 | compiler: clang 115 | env: 116 | - COMPILER='clang++' 117 | 118 | before_install: 119 | - export CXX=${COMPILER} 120 | 121 | script: 122 | - cd cpp 123 | - make 124 | - make test 125 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 - 2020 Syed Faheel Ahmad 4 | Copyright (c) 2018 - 2020 Alexander Montgomery Johnson 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | gems: 3 | - jemoji 4 | -------------------------------------------------------------------------------- /cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(ProAlgos-Cpp) 4 | 5 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 6 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 7 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 8 | 9 | include_directories(include) 10 | 11 | set(CMAKE_CXX_STANDARD 14) 12 | set(CMAKE_CXX_FLAGS "-g -O0 -Wall -Wextra -pedantic-errors") 13 | 14 | # Test runner 15 | add_library(test_runner STATIC 16 | test/test_runner.cpp) 17 | 18 | # ============================================================================ 19 | # Algorithms 20 | # ============================================================================ 21 | 22 | # ------------------- 23 | # Backtracking 24 | # ------------------- 25 | 26 | # N-queens 27 | add_executable(n_queens 28 | test/algorithm/backtracking/n_queens.cpp) 29 | target_link_libraries(n_queens test_runner) 30 | 31 | # ------------------- 32 | # Dynamic programming 33 | # ------------------- 34 | 35 | # Matrix chain multiplication 36 | add_executable(matrix_chain_multiplication 37 | test/algorithm/dynamic_programming/matrix_chain_multiplication.cpp) 38 | target_link_libraries(matrix_chain_multiplication test_runner) 39 | 40 | # 0-1 knapsack 41 | add_executable(0_1_knapsack 42 | test/algorithm/dynamic_programming/0_1_knapsack.cpp) 43 | target_link_libraries(0_1_knapsack test_runner) 44 | 45 | # Coin change 46 | add_executable(coin_change 47 | test/algorithm/dynamic_programming/coin_change.cpp) 48 | target_link_libraries(coin_change test_runner) 49 | 50 | # Kadane's 51 | add_executable(kadane 52 | test/algorithm/dynamic_programming/kadane.cpp) 53 | target_link_libraries(kadane test_runner) 54 | 55 | # Rod cutting 56 | add_executable(rod_cutting 57 | test/algorithm/dynamic_programming/rod_cutting.cpp) 58 | target_link_libraries(rod_cutting test_runner) 59 | 60 | # Weighted activity selection 61 | add_executable(weighted_activity_selection 62 | test/algorithm/dynamic_programming/weighted_activity_selection.cpp) 63 | target_link_libraries(weighted_activity_selection test_runner) 64 | 65 | # ------------- 66 | # Number theory 67 | # ------------- 68 | 69 | # Binomial coefficient 70 | add_executable(binomial_coefficient 71 | test/algorithm/number_theory/binomial_coefficient.cpp) 72 | target_link_libraries(binomial_coefficient test_runner) 73 | 74 | # Extended Euclidean 75 | add_executable(extended_euclidean 76 | test/algorithm/number_theory/extended_euclidean.cpp) 77 | target_link_libraries(extended_euclidean test_runner) 78 | 79 | # Fast exponentiation 80 | add_executable(fast_exponentiation 81 | test/algorithm/number_theory/fast_exponentiation.cpp) 82 | target_link_libraries(fast_exponentiation test_runner) 83 | 84 | # Fibonacci 85 | add_executable(fibonacci 86 | test/algorithm/number_theory/fibonacci.cpp) 87 | target_link_libraries(fibonacci test_runner) 88 | 89 | # Fibonacci efficient 90 | add_executable(fibonacci_efficient 91 | test/algorithm/number_theory/fibonacci_efficient.cpp) 92 | target_link_libraries(fibonacci_efficient test_runner) 93 | 94 | # Greatest common divisor 95 | add_executable(greatest_common_divisor 96 | test/algorithm/number_theory/greatest_common_divisor.cpp) 97 | target_link_libraries(greatest_common_divisor test_runner) 98 | 99 | # Perfect number check 100 | add_executable(perfect_number_check 101 | test/algorithm/number_theory/perfect_number_check.cpp) 102 | target_link_libraries(perfect_number_check test_runner) 103 | 104 | # Primorial 105 | add_executable(primorial 106 | test/algorithm/number_theory/primorial.cpp) 107 | target_link_libraries(primorial test_runner) 108 | 109 | # Sieve of Eratosthenes 110 | add_executable(sieve_of_eratosthenes 111 | test/algorithm/number_theory/sieve_of_eratosthenes.cpp) 112 | target_link_libraries(sieve_of_eratosthenes test_runner) 113 | 114 | # --------- 115 | # Searching 116 | # --------- 117 | 118 | # Binary search 119 | add_executable(binary_search 120 | test/algorithm/searching/binary_search.cpp) 121 | target_link_libraries(binary_search test_runner) 122 | 123 | # Linear search 124 | add_executable(linear_search 125 | test/algorithm/searching/linear_search.cpp) 126 | target_link_libraries(linear_search test_runner) 127 | 128 | # Ternary search 129 | add_executable(ternary_search 130 | test/algorithm/searching/ternary_search.cpp) 131 | target_link_libraries(ternary_search test_runner) 132 | 133 | # ------- 134 | # Sorting 135 | # ------- 136 | 137 | # Common sorting 138 | add_executable(sorting 139 | test/algorithm/sorting/sorting.cpp) 140 | target_link_libraries(sorting test_runner) 141 | 142 | # ------ 143 | # String 144 | # ------ 145 | 146 | # Edit distance 147 | add_executable(edit_distance 148 | test/algorithm/string/edit_distance.cpp) 149 | target_link_libraries(edit_distance test_runner) 150 | 151 | # Heap's 152 | add_executable(heaps_algorithm 153 | test/algorithm/string/heaps_algorithm.cpp) 154 | target_link_libraries(heaps_algorithm test_runner) 155 | 156 | # Knuth-Morris-Pratt 157 | add_executable(knuth_morris_pratt 158 | test/algorithm/string/knuth_morris_pratt.cpp) 159 | target_link_libraries(knuth_morris_pratt test_runner) 160 | 161 | # Longest common subsequence 162 | add_executable(longest_common_subsequence 163 | test/algorithm/string/longest_common_subsequence.cpp) 164 | target_link_libraries(longest_common_subsequence test_runner) 165 | 166 | # Shunting yard 167 | add_executable(shunting_yard 168 | test/algorithm/string/shunting_yard.cpp) 169 | target_link_libraries(shunting_yard test_runner) 170 | 171 | # ============================================================================ 172 | # Data structures 173 | # ============================================================================ 174 | 175 | # ----------- 176 | # Linked list 177 | # ----------- 178 | 179 | # Singly-linked list 180 | add_executable(singly_linked_list 181 | test/data_structure/linked_list/singly_linked_list.cpp) 182 | target_link_libraries(singly_linked_list test_runner) 183 | 184 | # Doubly-linked list 185 | add_executable(doubly_linked_list 186 | test/data_structure/linked_list/doubly_linked_list.cpp) 187 | target_link_libraries(doubly_linked_list test_runner) 188 | 189 | # ----- 190 | # Queue 191 | # ----- 192 | 193 | # Queue 194 | add_executable(queue 195 | test/data_structure/queue/queue.cpp) 196 | target_link_libraries(queue test_runner) 197 | 198 | # --- 199 | # Set 200 | # --- 201 | 202 | # Disjoint set 203 | add_executable(disjoint_set 204 | test/data_structure/set/disjoint_set.cpp) 205 | target_link_libraries(disjoint_set test_runner) 206 | 207 | # ----- 208 | # Stack 209 | # ----- 210 | 211 | # Stack 212 | add_executable(stack 213 | test/data_structure/stack/stack.cpp) 214 | target_link_libraries(stack test_runner) 215 | 216 | # ---- 217 | # Tree 218 | # ---- 219 | 220 | # Binary search tree 221 | add_executable(binary_search_tree 222 | test/data_structure/tree/binary_search_tree.cpp) 223 | target_link_libraries(binary_search_tree test_runner) 224 | 225 | add_executable(fenwick_tree 226 | test/data_structure/tree/fenwick_tree.cpp) 227 | target_link_libraries(fenwick_tree test_runner) 228 | 229 | -------------------------------------------------------------------------------- /cpp/Makefile: -------------------------------------------------------------------------------- 1 | # prevent printing of recipes 2 | .SILENT: 3 | 4 | # compile tests using CMake 5 | .PHONY: default 6 | default: dirs 7 | cd build && cmake .. && make 8 | 9 | # run tests 10 | .PHONY: test 11 | test: dirs 12 | scripts/run_tests.sh 13 | 14 | # create bin and build directories 15 | .PHONY: dirs 16 | dirs: 17 | mkdir -p bin build 18 | 19 | # clean build files 20 | .PHONY: clean 21 | clean: 22 | cd build && make clean 23 | -------------------------------------------------------------------------------- /cpp/include/algorithm/backtracking/README.md: -------------------------------------------------------------------------------- 1 | # Backtracking 2 | 3 | Backtracking is a general algorithm for finding all (or some) solutions to some computational problems, notably constraint satisfaction problems, that incrementally builds candidates to the solutions, and abandons each partial candidate ("backtracks") as soon as it determines that the candidate cannot possibly be completed to a valid solution. 4 | 5 | Backtracking can be applied only for problems which admit the concept of a "partial candidate solution" and a relatively quick test of whether it can possibly be completed to a valid solution. It is useless, for example, for locating a given value in an unordered table. When it is applicable, however, backtracking is often much faster than brute force enumeration of all complete candidates, since it can eliminate a large number of candidates with a single test. 6 | 7 | ### Contents 8 | 9 | 1. [N queens](#1-n-queens) 10 | 11 | --- 12 | 13 | ## 1. N queens 14 | 15 | The N queens puzzle is the problem of placing _N_ chess queens on an _N×N_ chessboard so that no two queens threaten each other. Thus, a solution requires that no two queens share the same row, column, or diagonal. 16 | 17 | Read more on [Wikipedia](https://en.wikipedia.org/wiki/Eight_queens_puzzle). 18 | 19 | ### Usage 20 | 21 | ```c++ 22 | NQueensSolver solver = NQueensSolver(16); // 16 queens are to be placed 23 | 24 | if (solver.can_place_queens()) { // there is at least 1 way to place the queens 25 | // get the number of solutions 26 | size_t num_solutions = solver.num_solutions(); 27 | 28 | // print the first solution 29 | solver.print_solution(); 30 | 31 | // print all solutions 32 | solver.print_all_solutions(); 33 | 34 | // get a solution as a 2D boolean vector 35 | Board one_solution = solver.get_solution(); 36 | 37 | // get all solutions as a vector of 2D boolean vectors 38 | std::vector all_solutions = solver.get_all_solutions(); 39 | } 40 | ``` 41 | 42 | **Note**: `Board` is a 2D boolean vector, a type alias for `std::vector>`. A cell that is `true` represents that a queen is placed there, and `false` represents an empty cell. 43 | 44 | ### Complexity 45 | 46 | Time | Space 47 | --------|------------------- 48 | _O(N!)_ | _O(N2)_ 49 | 50 | where N is the number of queens. 51 | -------------------------------------------------------------------------------- /cpp/include/algorithm/backtracking/n_queens.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | N queens problem 3 | ---------------- 4 | Find a way to place N non-attacking queens on an N×N chessboard. 5 | 6 | Time complexity 7 | --------------- 8 | O(N!), where N is the number of queens. 9 | 10 | Space complexity 11 | ---------------- 12 | O(N^2), where N is the number of queens. 13 | */ 14 | 15 | #ifndef N_QUEENS_HPP 16 | #define N_QUEENS_HPP 17 | 18 | #include 19 | #include 20 | 21 | typedef std::vector> Board; 22 | 23 | const int MAX_QUEENS = 40; 24 | 25 | 26 | /* 27 | NQueensSolver 28 | ------------ 29 | Wrapper class for solving the N-Queens problem. 30 | */ 31 | 32 | class NQueensSolver { 33 | size_t N; 34 | bool is_solved; 35 | std::vector solutions; 36 | 37 | public: 38 | NQueensSolver(const size_t); 39 | bool can_place_queens() const; 40 | size_t num_solutions() const; 41 | Board get_solution() const; 42 | std::vector get_solutions() const; 43 | void print_solution() const; 44 | void print_all_solutions() const; 45 | 46 | private: 47 | void solve(); 48 | bool place_queens(Board&, const size_t); 49 | bool is_safe(const Board&, const int, const int) const; 50 | void print_solution(const Board&) const; 51 | }; 52 | 53 | 54 | /* 55 | Constructor 56 | ----------- 57 | */ 58 | 59 | NQueensSolver::NQueensSolver(const size_t num_queens) { 60 | N = num_queens; 61 | is_solved = false; 62 | solve(); 63 | } 64 | 65 | 66 | /* 67 | ========================================================================== 68 | Public interface 69 | ========================================================================== 70 | */ 71 | 72 | 73 | /* 74 | can_place_queens 75 | ---------------- 76 | Returns whether it is possible to place N queens on an NxN chessboard. 77 | */ 78 | 79 | bool NQueensSolver::can_place_queens() const { 80 | return bool(solutions.size()); 81 | } 82 | 83 | 84 | /* 85 | num_solutions 86 | ------------- 87 | Returns the number of ways in which N queens can be placed on an NxN 88 | chessboard. 89 | */ 90 | 91 | size_t NQueensSolver::num_solutions() const { 92 | return solutions.size(); 93 | } 94 | 95 | 96 | /* 97 | get_solution 98 | ------------ 99 | Returns an NxN boolean matrix in which all N queens have been placed. 100 | The cells that are marked 'true' are where queens are placed, and all 101 | the other cells marked 'false' are empty. 102 | */ 103 | 104 | Board NQueensSolver::get_solution() const { 105 | return solutions[0]; 106 | } 107 | 108 | 109 | /* 110 | get_solutions 111 | ------------- 112 | Returns a list of NxN boolean matrices, all of which are valid solutions 113 | to the N-Queens problem. In each matrix, the cells that are marked 'true' 114 | are where queens are placed, and all the other cells marked 'false' are 115 | empty. 116 | */ 117 | 118 | std::vector NQueensSolver::get_solutions() const { 119 | return solutions; 120 | } 121 | 122 | 123 | /* 124 | print_solution 125 | -------------- 126 | Prints a solution for the N-Queens problem. 'Q' is printed for a queen, 127 | and '.' is printed for an empty cell. 128 | */ 129 | 130 | void NQueensSolver::print_solution() const { 131 | print_solution(solutions[0]); 132 | } 133 | 134 | 135 | /* 136 | print_all_solutions 137 | ------------------- 138 | Prints all possible solution for the N-Queens problem. 'Q' is printed for 139 | a queen, and '.' is printed for an empty cell. 140 | */ 141 | 142 | void NQueensSolver::print_all_solutions() const { 143 | for (const Board& board: solutions) { 144 | print_solution(board); 145 | std::cout << "\n"; 146 | } 147 | } 148 | 149 | 150 | /* 151 | ========================================================================== 152 | Private methods 153 | ========================================================================== 154 | */ 155 | 156 | 157 | /* 158 | solve 159 | ----- 160 | Calls the `place_queens` method that tries to place N queens on an NxN 161 | chessboard. 162 | */ 163 | 164 | void NQueensSolver::solve() { 165 | Board board(N, std::vector(N, false)); 166 | place_queens(board, 0); 167 | is_solved = true; 168 | } 169 | 170 | 171 | /* 172 | place_queens 173 | ------------ 174 | Tries to place the i-th queen on different rows along the (i-1)-th column, 175 | and if in that position the remaning queens can be successfully placed, it 176 | adds the arrangement to the list of solutions. 177 | */ 178 | 179 | bool NQueensSolver::place_queens(Board& board, const size_t col) { 180 | if (col == N) 181 | return true; // all N queens have been placed 182 | 183 | for (size_t row = 0; row < N; row++) { 184 | if (is_safe(board, row, col)) { 185 | board[row][col] = true; 186 | if (place_queens(board, col + 1)) 187 | solutions.push_back(board); 188 | board[row][col] = false; 189 | } 190 | } 191 | 192 | return false; 193 | } 194 | 195 | 196 | /* 197 | is_safe 198 | ------- 199 | Checks whether a queen that is being placed at the given row and column 200 | will be safe from being attacked by other queens that have already been 201 | placed on the board. 202 | */ 203 | 204 | bool NQueensSolver::is_safe(const Board& board, const int row, const int col) const { 205 | int r, c; 206 | // check along the column 207 | for (r = 0; r < N; r++) 208 | if (board[r][col]) 209 | return false; // queen will be attacked along the column 210 | 211 | // check along the row 212 | for (c = 0; c < col; c++) 213 | if (board[row][c]) 214 | return false; // queen will be attacked along the row 215 | 216 | // check diagonally 217 | for (c = col-1, r = row-1; c >= 0 && r >= 0; c--, r--) 218 | if (board[r][c]) 219 | return false; // queen will be attacked along the main diagonal 220 | for (c = col-1, r = row+1; c >= 0 && r < N; c--, r++) 221 | if (board[r][c]) 222 | return false; // queen will be attacked along the minor diagonal 223 | 224 | return true; // queen will be safe at this position 225 | } 226 | 227 | 228 | /* 229 | print_solution 230 | -------------- 231 | Prints a given solved board. 'Q' is printed for a queen, and '.' is printed 232 | for an empty cell. 233 | */ 234 | 235 | void NQueensSolver::print_solution(const Board& board) const { 236 | size_t row, col; 237 | for (row = 0; row < N; row++) { 238 | for (col = 0; col < N; col++) { 239 | if (board[row][col]) 240 | std::cout << 'Q'; 241 | else 242 | std::cout << '.'; 243 | std::cout << ' '; 244 | } 245 | std::cout << '\n'; 246 | } 247 | } 248 | 249 | #endif // N_QUEENS_HPP 250 | -------------------------------------------------------------------------------- /cpp/include/algorithm/dynamic_programming/0_1_knapsack.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | 0-1 Knapsack Problem 3 | -------------------- 4 | Given weights and values of n items, put these items in a knapsack 5 | of a fixed capacity to get the maximum total value in the knapsack. 6 | 7 | Time complexity 8 | --------------- 9 | O(N*C), where N is the number of items and C is the capacity of the knapsack. 10 | 11 | Space complexity 12 | ---------------- 13 | O(N*C), the variables same as time complexity. 14 | 15 | Author 16 | ------ 17 | Manas Gupta (@heisenberg-2505) 18 | */ 19 | 20 | #ifndef KNAPSACK_0_1_HPP 21 | #define KNAPSACK_0_1_HPP 22 | 23 | #include 24 | #include 25 | 26 | using std::vector; 27 | typedef long long LL; 28 | 29 | LL knapsack (LL capacity, LL numberOfItems, vector weights, vector values) { 30 | vector> maxItems (numberOfItems + 1, vector (capacity + 1)); 31 | for (LL i = 0; i <= numberOfItems; i++) { 32 | for (LL j = 0; j <= capacity; j++) { 33 | if (i == 0 || j == 0) { // Base case. 34 | maxItems[i][j] = 0; 35 | } else if (weights[i - 1] <= j) { // Two cases - if the element is included and if its not. 36 | maxItems[i][j] = std::max (values[i - 1] + maxItems[i - 1][j - weights[i - 1]], maxItems[i - 1][j]); 37 | } else { // If the weight of the current element is greater than the maximum weight. 38 | maxItems[i][j] = maxItems[i - 1][j]; 39 | } 40 | } 41 | } 42 | return maxItems[numberOfItems][capacity]; 43 | } 44 | 45 | #endif // KNAPSACK_0_1_HPP 46 | -------------------------------------------------------------------------------- /cpp/include/algorithm/dynamic_programming/coin_change.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Coin Change Algorithm 3 | --------------------- 4 | Given an unlimited amount of coins with different values, find the number of ways of making change for an given 5 | value using the coins. 6 | 7 | Time complexity 8 | --------------- 9 | O(M*N), where M is the number of coins with different values and N is the amount that we desired to change 10 | 11 | Space complexity 12 | ---------------- 13 | O(M*N), where M is the number of coins with different values and N is the amount that we desired to change 14 | */ 15 | 16 | #ifndef COIN_CHANGE_HPP 17 | #define COIN_CHANGE_HPP 18 | 19 | #include 20 | 21 | using std::vector; 22 | 23 | int coin_change(const vector& coin, int number_of_coins, int amount) 24 | { 25 | if (number_of_coins == 0 && amount == 0) { 26 | return 1; 27 | } else if (number_of_coins == 0) { 28 | return 0; 29 | } 30 | 31 | int i, j; 32 | 33 | // Make a matrix of size (amount+1)*number_of_coins to tabulate the computed values 34 | // table[i][j] represents no.of ways in which an 'i' can be made with just j type of coins available 35 | vector> table (amount + 1, vector(number_of_coins, 0)); 36 | 37 | int current_in; // Stores the number of ways in which the amount can be changed including the current coin value 38 | int current_out; // Stores the number of ways in which the amount can be changed excluding the current coin value 39 | 40 | for (j = 0; j < number_of_coins; j++) { 41 | table[0][j] = 1; 42 | } 43 | 44 | // i represents the amount whose change is required 45 | // j represents the coin values available 46 | for (i = 1; i <= amount; i++) { 47 | for (j = 0; j < number_of_coins; j++) { 48 | // If the the value of current coin is less than or equal to total amount whose change is required 49 | // include this coin 50 | if (i >= coin[j]) { 51 | current_in = table[i - coin[j]][j]; 52 | } else { 53 | current_in = 0; 54 | } 55 | 56 | 57 | if (j >= 1) { 58 | current_out = table[i][j - 1]; 59 | } else { 60 | current_out = 0; 61 | } 62 | 63 | table[i][j] = current_in + current_out; 64 | } 65 | } 66 | 67 | return table[amount][number_of_coins - 1]; 68 | } 69 | 70 | #endif // COIN_CHANGE_HPP 71 | -------------------------------------------------------------------------------- /cpp/include/algorithm/dynamic_programming/kadane.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Kadane's Algorithm 3 | ------------------ 4 | Used for finding the contiguous subarray within a one-dimensional array 5 | of integers which has the largest sum. 6 | 7 | Time complexity 8 | --------------- 9 | O(N), where N is the number of elements in the original array. 10 | 11 | Space complexity 12 | ---------------- 13 | O(1) 14 | */ 15 | 16 | #ifndef KADANE_HPP 17 | #define KADANE_HPP 18 | 19 | #include 20 | #include 21 | 22 | using std::tuple; 23 | using std::make_tuple; 24 | using std::vector; 25 | 26 | /* 27 | maximum_subarray 28 | --------------- 29 | Takes an array of integers as an argument and computes the maximum sum that 30 | can be computed from any (contiguous) subarray of that array. Uses Kadane's 31 | Algorithm, which employs dynamic programming. 32 | 33 | Return value 34 | ------------ 35 | tuple, in which int is the maximum subarray value and 36 | size_t to size_t represents the indices of the passed subarray that sum to 37 | that value. 38 | */ 39 | 40 | #define kadane maximum_subarray 41 | 42 | tuple maximum_subarray(const vector &values) 43 | { 44 | int maxSum, currentSum; 45 | size_t nextStart, start, end; 46 | 47 | maxSum = currentSum = values[0]; 48 | nextStart = start = end = 0; 49 | for (size_t i = 1; i < values.size(); i++) { 50 | currentSum += values[i]; 51 | 52 | if (currentSum < values[i]) { 53 | currentSum = values[i]; 54 | nextStart = i; 55 | } 56 | 57 | if (currentSum > maxSum) { 58 | maxSum = currentSum; 59 | start = nextStart; 60 | end = i; 61 | } 62 | } 63 | 64 | return make_tuple(maxSum, start, end); 65 | } 66 | 67 | #endif // KADANE_HPP 68 | -------------------------------------------------------------------------------- /cpp/include/algorithm/dynamic_programming/longest_decreasing_subsequence.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LONGEST_DECREASING_SUBSEQUENCE 2 | #define LONGEST_DECREASING_SUBSEQUENCE 3 | 4 | /* 5 | Longest Decreasing Subsequence 6 | --------------------- 7 | This algorithm finds the longest decreasing subsequence in a sequence of numbers 8 | 9 | Time complexity 10 | ---------------- 11 | O(n log(n)) where n is the number of elements in the initial list 12 | 13 | Space complexity 14 | --------------- 15 | O(n) 16 | 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | using std::vector; 23 | using std::cout; 24 | using std::endl; 25 | /* 26 | * Function finds the longest_decreasing_subsequence for a vector input 27 | */ 28 | int longest_decreasing_subsequence(vector& input, const bool to_show_state = false) { 29 | int elements = input.size(); //number of elements in the vector 30 | if (elements == 1 || elements == 0) { 31 | return elements; //base case 32 | } 33 | int array[elements]; //array to store the longest increasing subsequence at each location, this can then be used to backtrack and find what was the longest sequence 34 | int max = 0; //max represents current largest size 35 | 36 | for (int i = 0; i < elements; i++) { 37 | array[i] = 1; //default value 38 | } 39 | for (int i = 1; i < elements; i++) { 40 | for (int j = 0; j < i; j++) { 41 | if ((input[j] - input[i] > 0) && array[i] < array[j] + 1) { //if the value is greater than or less than and that element in the array has more elements in its subsequence 42 | array[i]++; 43 | } 44 | } 45 | } 46 | for (int i = 0; i < elements; i++) { //now we set the max to the highest value 47 | if (array[i] > max) { 48 | max = array[i]; 49 | } 50 | } 51 | if (to_show_state) { //if this is true print out the subsequence 52 | vector sub; //this vector will be populated with the ordered subsequence 53 | int counter = max; 54 | for (int i = elements - 1; i > -1; i--) { 55 | if (array[i] == counter) 56 | if (counter == max) { //the last value in the sequence will have the highest value 57 | sub.push_back(input.at(i)); 58 | counter--; 59 | } else if (input.at(i) - sub.at(sub.size() - 1) > 0) { 60 | sub.push_back(input.at(i)); 61 | counter--; 62 | } 63 | } 64 | for (int i = max-1; i > -1; i--) { 65 | cout << sub.at(i) << ", "; 66 | } 67 | 68 | cout << endl; 69 | } 70 | return max; 71 | } 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /cpp/include/algorithm/dynamic_programming/matrix_chain_multiplication.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Matrix chain multiplication 3 | --------------------------- 4 | Given a sequence of matrices, find the most efficient way to multiply these 5 | matrices, by deciding the sequence of the matrix multiplications involved. 6 | 7 | Time complexity 8 | --------------- 9 | O(N^3), where N is the number of matrices. 10 | 11 | Space complexity 12 | ---------------- 13 | O(N^2), where N is the number of matrices. 14 | */ 15 | 16 | #ifndef MATRIX_CHAIN_MULTIPLICATION_HPP 17 | #define MATRIX_CHAIN_MULTIPLICATION_HPP 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | typedef unsigned long long int ull; 24 | 25 | 26 | /* 27 | MatrixChainMultiplier 28 | --------------------- 29 | Wrapper class for solving the matrix chain multiplication problem. 30 | */ 31 | 32 | class MatrixChainMultiplier { 33 | std::vector matrix_sizes; 34 | std::vector> parentheses; 35 | std::string parenthesized_result; 36 | ull cost; 37 | 38 | public: 39 | MatrixChainMultiplier(); 40 | MatrixChainMultiplier(std::vector); 41 | ull optimal_cost(); 42 | std::string optimal_parenthesization(); 43 | 44 | private: 45 | ull find_optimal_cost(); 46 | void find_optimal_parenthesization(int, int, char&); 47 | }; 48 | 49 | 50 | /* 51 | Default constructor 52 | ------------------- 53 | */ 54 | 55 | MatrixChainMultiplier::MatrixChainMultiplier() { 56 | matrix_sizes = std::vector(); 57 | // parentheses[i][j] stores optimal break point in sub-expression from i to j 58 | parentheses = std::vector>(); 59 | parenthesized_result = ""; 60 | cost = 0; 61 | } 62 | 63 | 64 | /* 65 | Constructor 66 | ----------- 67 | Takes a vector of unsigned integers, where the `i`th integer corresponds 68 | to the number of columns of the `i-1`th matrix and the number of rows of 69 | the `i`th matrix. Except for the first and last integers, which correspond 70 | to the number of rows in the first matrix and the number of columns in the 71 | last matrix respectively. 72 | 73 | Eg. for a chain of matrices sized: 74 | 10x30, 30x20, 20x15, 15x35, 35x20, 20x40 75 | the dimension vector would be: 76 | {10, 30, 20, 15, 35, 20, 40} 77 | */ 78 | 79 | MatrixChainMultiplier::MatrixChainMultiplier(std::vector dimensions) { 80 | if (dimensions.size() < 4) { 81 | // for the minimum of 3 matrices, 4 dimension values are required 82 | std::invalid_argument("You need to provide at least 4 dimension values" 83 | ", as there need to be atleast 3 matrices."); 84 | } 85 | else if (dimensions.size() > 27) { 86 | // a maximum of 26 matrices are supported (27 dimension values) 87 | std::invalid_argument("You can only provide at most 27 dimension values" 88 | ", since the maximum number of matrices supported is 26."); 89 | } 90 | 91 | for (size_t dimension: dimensions) 92 | if (dimension == 0) { 93 | std::invalid_argument("A dimension is zero, which is not a valid" 94 | "value."); 95 | } 96 | 97 | matrix_sizes = dimensions; 98 | // parentheses[i][j] stores optimal break point in sub-expression from i to j 99 | parentheses = std::vector>(dimensions.size(), std::vector(dimensions.size(), 0)); 100 | parenthesized_result = ""; 101 | cost = 0; 102 | } 103 | 104 | 105 | /* 106 | ========================================================================== 107 | Public interface 108 | ========================================================================== 109 | */ 110 | 111 | 112 | /* 113 | optimal_cost 114 | ------------ 115 | Returns the optimal cost 116 | */ 117 | 118 | ull MatrixChainMultiplier::optimal_cost() { 119 | return cost ? cost : find_optimal_cost(); 120 | } 121 | 122 | 123 | /* 124 | optimal_parenthesization 125 | ------------------------ 126 | Returns a string that has the optimal parenthesization of matrix chain product. 127 | */ 128 | 129 | std::string MatrixChainMultiplier::optimal_parenthesization() { 130 | if (parenthesized_result == "") { 131 | char matrix_symbol = 'A'; // matrices are named as A, B, C, ... 132 | size_t start = 1, end = matrix_sizes.size() - 1; 133 | find_optimal_parenthesization(start, end, matrix_symbol); 134 | } 135 | 136 | return parenthesized_result; 137 | } 138 | 139 | 140 | /* 141 | ========================================================================== 142 | Private methods 143 | ========================================================================== 144 | */ 145 | 146 | 147 | /* 148 | find_optimal_cost 149 | ----------------- 150 | */ 151 | 152 | ull MatrixChainMultiplier::find_optimal_cost() { 153 | size_t num_matrices = matrix_sizes.size(); 154 | 155 | // mult_cost[i,j] is the minimum number of scalar multiplications 156 | // needed to compute the matrix: 157 | // A[i] x A[i+1] x ... x A[j] 158 | std::vector> mult_cost(num_matrices, std::vector(num_matrices, 0)); 159 | 160 | for (size_t chain_length = 2; chain_length < num_matrices; chain_length++) { 161 | for (size_t i = 1; i < num_matrices - chain_length + 1; i++) { 162 | size_t j = i + chain_length - 1; 163 | mult_cost[i][j] = INT_MAX; 164 | for (size_t k = i; k <= j - 1; k++) { 165 | ull cost = mult_cost[i][k] 166 | + mult_cost[k + 1][j] 167 | + matrix_sizes[i - 1] * matrix_sizes[k] * matrix_sizes[j]; 168 | if (cost < mult_cost[i][j]) { 169 | mult_cost[i][j] = cost; 170 | parentheses[i][j] = k; 171 | } 172 | } 173 | } 174 | } 175 | 176 | return mult_cost[1][num_matrices - 1]; 177 | } 178 | 179 | 180 | /* 181 | find_optimal_parenthesization 182 | ----------------------------- 183 | Returns a string that has the optimal parenthesization of matrix chain product. 184 | */ 185 | 186 | void MatrixChainMultiplier::find_optimal_parenthesization(int begin, int end, 187 | char& matrix_symbol) { 188 | if (begin == end) { // last matrix in the current segment 189 | parenthesized_result += matrix_symbol++; 190 | return; 191 | } 192 | 193 | parenthesized_result += '('; 194 | // recursively place the parentheses around the sub-expression 195 | // from `begin` to `parentheses[begin][end]` 196 | find_optimal_parenthesization(begin, parentheses[begin][end], matrix_symbol); 197 | // from `parentheses[begin][end] + 1` to `end` 198 | find_optimal_parenthesization(parentheses[begin][end] + 1, end, matrix_symbol); 199 | parenthesized_result += ')'; 200 | } 201 | 202 | #endif // MATRIX_CHAIN_MULTIPLICATION_HPP 203 | -------------------------------------------------------------------------------- /cpp/include/algorithm/dynamic_programming/rod_cutting.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Rod cutting problem 3 | -------------------- 4 | Given a rod of length N units and an array of prices 5 | that contains prices of all pieces of size smaller than N. 6 | Determine the maximum value obtainable by cutting up 7 | the rod and selling the pieces 8 | 9 | Time complexity 10 | --------------- 11 | O(N^2) 12 | 13 | Space complexity 14 | ---------------- 15 | O(N) 16 | 17 | Author 18 | ------ 19 | Nikolaus Fedurko (@B1Z0N) 20 | */ 21 | 22 | #ifndef ROD_CUTTING_HPP 23 | #define ROD_CUTTING_HPP 24 | 25 | #include 26 | 27 | /** 28 | * Recursive helper function 29 | */ 30 | std::size_t __rod_cutting( const std::vector& costs, std::vector& visited, std::size_t length) { 31 | // whole unit, can't delete 32 | if ( length == 1 ) { 33 | return visited[0]; 34 | } 35 | 36 | // try to sell it as is, not cutting 37 | std::size_t cost = costs[ length - 1 ]; 38 | std::size_t next_cost; 39 | 40 | /** 41 | * loop to check only half, 42 | * because other half is symmetric 43 | * try cutting 1, 2, 3 ... 44 | * and find optimal 45 | */ 46 | for ( std::size_t i = 1; i <= length / 2; i++ ) { 47 | // if we've already found - use it 48 | if ( visited[ length - i - 1 ] != -1 ) { 49 | next_cost = visited[ length - i - 1 ]; 50 | } 51 | // if no - go find it 52 | else { 53 | next_cost = __rod_cutting( costs, visited, length - i ); 54 | } 55 | 56 | // plus cost of the piece we are cutting 57 | next_cost += costs[ i - 1 ]; 58 | 59 | // assign maximal value 60 | if ( cost < next_cost ) { 61 | cost = next_cost; 62 | } 63 | } 64 | 65 | // don't forget to set this 66 | // as visited 67 | visited[length - 1] = cost; 68 | return cost; 69 | } 70 | 71 | /** 72 | * Solution function 73 | */ 74 | std::size_t rod_cutting( std::vector costs ) { 75 | // vector of already found optimal costs 76 | std::vector visited ( costs.size(), -1 ); 77 | // rod of length 1 is optimally sold at cost of itself 78 | visited[0] = costs[0]; 79 | 80 | return __rod_cutting( costs, visited, costs.size() ); 81 | } 82 | 83 | #endif // ROD_CUTTING_HPP 84 | -------------------------------------------------------------------------------- /cpp/include/algorithm/dynamic_programming/weighted_activity_selection.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Weighted activity selection problem 3 | -------------------- 4 | Given N activities where every activity is represented by 5 | following three elements of it. 6 | 7 | 1. Start Time 8 | 2. Finish Time 9 | 3. Weight or Value Associated 10 | 11 | Find the maximum weight subset of activities such that no two of them in the subset overlap. 12 | 13 | 14 | Time complexity 15 | --------------- 16 | O(N*lg(N)) 17 | 18 | Space complexity 19 | ---------------- 20 | O(N) 21 | 22 | Author 23 | ------ 24 | Nikolaus Fedurko (@B1Z0N) 25 | */ 26 | 27 | #ifndef WEIGHTED_ACTIVITY_SELECTION_HPP 28 | #define WEIGHTED_ACTIVITY_SELECTION_HPP 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | /** 36 | * Struct for single activity data 37 | */ 38 | struct Activity 39 | { 40 | std::time_t start; 41 | std::time_t end; 42 | std::size_t weight; 43 | }; 44 | 45 | /** 46 | * Find the index of right-most 47 | * non-overlaping activity 48 | * that is left to the query[ index ] 49 | * using binary search in O( lg(index) ) 50 | */ 51 | int left_activity_bsearch( const std::vector& quer, std::size_t index ) 52 | { 53 | int lo = 0, hi = index - 1; 54 | while ( lo <= hi ) { 55 | int mid = ( lo + hi ) / 2; 56 | 57 | // if it is non-overlapping 58 | if ( quer[ mid ].end <= quer[ index ].start ) { 59 | // if there are other non-overlapping activity 60 | // a bit to the right, then continue searching 61 | if ( quer[ mid + 1 ].end <= quer[ index ].start ) { 62 | lo = mid + 1; 63 | } 64 | // if it is right-most non-overlapping 65 | else { 66 | return mid; 67 | } 68 | } 69 | // if there are overlaps, in the middle 70 | // look to the left half 71 | else { 72 | hi = mid - 1; 73 | } 74 | } 75 | 76 | // if quer[ index ] has no non-overlapping activities 77 | // to the left of it 78 | return -1; 79 | } 80 | 81 | /** 82 | * Algorithm of solution 83 | */ 84 | int weighted_activity(const std::vector& start, 85 | const std::vector& end, 86 | const std::vector& weight) { 87 | std::vector quer; 88 | for ( std::size_t i = 0; i < start.size(); i++ ) { 89 | quer.push_back( { start[ i ], end[ i ], weight[ i ] } ); 90 | } 91 | 92 | // sort by end in ascending order 93 | std::sort( std::begin( quer ), std::end( quer ), 94 | [] (const Activity& fst, const Activity& snd) 95 | { 96 | return fst.end < snd.end; 97 | } 98 | ); 99 | 100 | // sol[ i ] stores solution to first i + 1 activities 101 | std::vector sol ( quer.size() ); 102 | // first solution is just it's single weight 103 | sol[0] = quer[0].weight; 104 | 105 | // find all solutions 106 | for ( std::size_t i = 1; i < quer.size(); i++ ) { 107 | std::size_t weight_with_current = quer[i].weight; 108 | 109 | // j - index of the problem needed to solve if 110 | // we want to include our i index in solution 111 | int j = left_activity_bsearch( quer, i ); 112 | 113 | // if there are consistent j on the left, 114 | // add max_weight of it's solution 115 | if ( j != -1 ) { 116 | weight_with_current += sol[j]; 117 | } 118 | 119 | // decide whether to include this i index into solution 120 | // depending on it's weights 121 | sol[ i ] = std::max( 122 | sol[ i - 1 ], // weight without current 123 | weight_with_current 124 | ); 125 | } 126 | 127 | // last index contains solution to whole problem 128 | return sol.back(); 129 | } 130 | 131 | #endif // WEIGHTED_ACTIVITY_SELECTION_HPP 132 | -------------------------------------------------------------------------------- /cpp/include/algorithm/number_theory/binomial_coefficient.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Binomial coefficient 3 | -------------------- 4 | For a set containing N unique elements, find the number of subsets containing 5 | K elements (a.k.a. "N choose K"). Alternatively, it is the coefficient of X^K 6 | in the binomial expansion of (1 + X)^N. 7 | 8 | This implementation uses a recurrence relation along with a dynamic programming 9 | approach to calculate the binomial coefficient C(N, K). 10 | 11 | Time complexity 12 | --------------- 13 | O(N * K), where N and K are as mentioned above. 14 | 15 | Space complexity 16 | ---------------- 17 | O(N * K), where N and K are as mentioned above. 18 | */ 19 | 20 | #ifndef BINOMIAL_COEFFICIENT_HPP 21 | #define BINOMIAL_COEFFICIENT_HPP 22 | 23 | #include 24 | 25 | using std::vector; 26 | 27 | typedef unsigned long long ULL; 28 | 29 | const ULL EMPTY = 0; 30 | 31 | /* 32 | calc_binomial_coefficient 33 | --------------------------- 34 | Uses the recurrence relation, 35 | C(n, k) = C(n - 1, k) + C(n - 1, k - 1), 36 | and a dynamic programming approach to find the binomial coefficient C(n, k). 37 | 38 | Return value 39 | ------------ 40 | C(n, k) modulo 2^64. (Due to limited range of ULL). 41 | 42 | Time complexity 43 | --------------- 44 | O(n * k). 45 | 46 | Space complexity 47 | ---------------- 48 | O(1). 49 | */ 50 | 51 | ULL calc_binomial_coefficient(int n, int k, vector>& cache) { 52 | // check if value has already been calculated 53 | if (cache[n][k] != EMPTY) { 54 | return cache[n][k]; 55 | } 56 | 57 | ULL result; 58 | if (n == k or k == 0) { 59 | result = 1; 60 | } else { 61 | result = calc_binomial_coefficient(n - 1, k, cache) + calc_binomial_coefficient(n - 1, k - 1, cache); 62 | } 63 | 64 | // result is stored in cache so that it isn't re-calculated when needed again 65 | cache[n][k] = result; 66 | return result; 67 | } 68 | 69 | 70 | /* 71 | binomial_coefficient 72 | -------------------- 73 | Creates a cache that is used by calc_binomial_coefficient to memoize the calculated 74 | coefficients, and returns the value of C(n, k). 75 | 76 | Return value 77 | ------------ 78 | C(n, k) modulo 2^64. (Due to limited range of ULL). 79 | 80 | Time complexity 81 | --------------- 82 | O(n * k). 83 | 84 | Space complexity 85 | ---------------- 86 | O(n * k). 87 | */ 88 | 89 | ULL binomial_coefficient(int n, int k) { 90 | if (n < k) { 91 | return 0; // no subsets of size k are possible 92 | } 93 | 94 | vector> cache; 95 | cache.resize(n + 1); 96 | 97 | // initialise all values in cache as EMPTY 98 | for (int i = 0; i <= n; i++) { 99 | cache[i].resize(k + 1, EMPTY); 100 | } 101 | 102 | return calc_binomial_coefficient(n, k, cache); 103 | } 104 | 105 | # endif // BINOMIAL_COEFFICIENT_HPP 106 | -------------------------------------------------------------------------------- /cpp/include/algorithm/number_theory/extended_euclidean.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Extended Euclidean algorithm 3 | ---------------------------- 4 | Given two non-negative numbers A and B as inputs, find M[0], M[1] such that: 5 | greatest_common_divisor(A, B) = M[0]*B + M[1]*B 6 | 7 | Time complexity 8 | --------------- 9 | O(log(k)), where k = min(a, b) is the smaller of the input integers a and b 10 | 11 | Space complexity 12 | ---------------- 13 | O(1). 14 | */ 15 | 16 | #ifndef EXTENDED_EUCLIDEAN_HPP 17 | #define EXTENDED_EUCLIDEAN_HPP 18 | 19 | #include 20 | 21 | using std::array; 22 | 23 | /* 24 | extended_euclidean 25 | ------------------ 26 | Uses the recurrence relation: 27 | greatest_common_divisor(a, b) = greatest_common_divisor(b, a % b) 28 | to find coefficients M[0] and M[1] such that: 29 | greatest_common_divisor(a, b) = (M[0] * a) + (M[1] * b) 30 | 31 | Loop invariant: greatest_common_divisor(a, b) is the same at the end of each 32 | iteration a = aM[0] * (original value of a) + aM[1] * (original value of b) 33 | The above statement holds for b and bM as well. 34 | 35 | Return value 36 | ------------ 37 | array M of length 2 which satisfies the equation above 38 | */ 39 | 40 | array extended_euclidean(int a, int b) { 41 | array aM = {{1, 0}}; 42 | array bM = {{0, 1}}; 43 | while (b != 0) { 44 | aM[0] -= (a/b) * bM[0]; 45 | aM[1] -= (a/b) * bM[1]; 46 | 47 | aM.swap(bM); 48 | 49 | int newA = b; 50 | b = a % b; 51 | a = newA; 52 | 53 | } 54 | return aM; 55 | } 56 | 57 | # endif // EXTENDED_EUCLIDEAN_HPP 58 | -------------------------------------------------------------------------------- /cpp/include/algorithm/number_theory/fast_exponentiation.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Fast exponentiation 3 | ------------------- 4 | Given the base (B) and exponent (E), this algorithm efficiently calculates the 5 | value of B^E using the method of exponentiation by squaring, i.e, it squares 6 | the base and halves the exponent in each step, until the exponent becomes 0. 7 | 8 | Time complexity 9 | --------------- 10 | O(log(E)), where E is the exponent. 11 | 12 | Space complexity 13 | ---------------- 14 | O(log(E)), where E is the exponent. 15 | */ 16 | 17 | #ifndef FAST_EXPONENTIATION_HPP 18 | #define FAST_EXPONENTIATION_HPP 19 | 20 | #include 21 | #include 22 | 23 | typedef unsigned long long ULL; 24 | 25 | /* 26 | digits_required 27 | --------------- 28 | Returns the number of digits in the result of B^E. 29 | */ 30 | 31 | ULL digits_required(const ULL& base, const ULL& exponent) { 32 | return floor(exponent * log10(base)) + 1; 33 | } 34 | 35 | /* 36 | square 37 | ------ 38 | Returns the square of the value passed. 39 | */ 40 | 41 | ULL square(const ULL& value) { 42 | return value * value; 43 | } 44 | 45 | /* 46 | fast_exp 47 | -------- 48 | Returns the value of the base raised to the exponent (B^E). 49 | The result is modulo the third parameter passed. 50 | 51 | NOTE: If the third parameter is not passed, it is assumed to be the maximum 52 | value of a 64-bit integer, and the exact value of the result is returned. 53 | In case the result cannot be contained in a 64-bit integer, the result is 54 | automatically modulo 10^9+7. 55 | */ 56 | 57 | ULL fast_exp(ULL base, ULL exponent, ULL mod = ULLONG_MAX) { 58 | if (exponent == 0) 59 | return 1; 60 | 61 | // if the result cannot be contained in a 64-bit integer, it will be 62 | // modulo 10^9+7 to prevent incorrect result due to integer overflow 63 | if (mod == ULLONG_MAX and digits_required(base, exponent) > 19) 64 | mod = 1000000007; 65 | 66 | if (exponent % 2) // the exponent is odd 67 | return (fast_exp(base, exponent-1, mod) * base) % mod; 68 | 69 | // the exponent is even 70 | return square(fast_exp(base, exponent/2, mod)) % mod; 71 | } 72 | 73 | #endif // FAST_EXPONENTIATION_HPP 74 | -------------------------------------------------------------------------------- /cpp/include/algorithm/number_theory/fibonacci.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Fibonacci number 3 | ----------------- 4 | Find the N-th Fibonacci number, given the value of N. The Fibonacci 5 | sequence is characterized by the fact that every number after the 6 | first two is the sum of the two preceding ones. 7 | 8 | Time complexity 9 | --------------- 10 | O(N), where N is the term of the Fibonacci sequence to calculate. 11 | 12 | Space complexity 13 | ---------------- 14 | O(1). 15 | */ 16 | 17 | #ifndef FIBONACCI_HPP 18 | #define FIBONACCI_HPP 19 | 20 | typedef unsigned long long int ULL; 21 | 22 | const int MAX_N = 93; // fibonacci(94) goes beyond the range of ULL 23 | 24 | 25 | ULL fibonacci(const int n) { 26 | if (n > MAX_N) 27 | return -1; 28 | if (n == 0 or n == 1) 29 | return n; // since F(0) = 0, and F(1) = 1 30 | 31 | ULL previous_to_previous = 0; // first term, or F(n-2) in general 32 | ULL previous = 1; // second term, or F(n-1) in general 33 | ULL fn; // F(n) 34 | for (int term = 2; term <= n; term++) { 35 | fn = previous + previous_to_previous; // F(n) = F(n-1) + F(n-2) 36 | previous_to_previous = previous; // F(n-1) becomes F(n-2) in the next step 37 | previous = fn; // F(n) becomes F(n-1) in the next step 38 | } 39 | 40 | return fn; 41 | } 42 | 43 | #endif // FIBONACCI_HPP 44 | -------------------------------------------------------------------------------- /cpp/include/algorithm/number_theory/fibonacci_efficient.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Fibonacci number 3 | ----------------- 4 | Find the N-th Fibonacci number, given the value of N. 5 | (The Fibonacci sequence is characterized by the fact that every number 6 | after the first two is the sum of the two preceding ones.) 7 | 8 | Time complexity 9 | --------------- 10 | O(log(N)), where N is the term of the Fibonacci sequence to calculate. 11 | 12 | Space complexity 13 | ---------------- 14 | O(1). 15 | */ 16 | 17 | #ifndef FIBONACCI_EFFICIENT_HPP 18 | #define FIBONACCI_EFFICIENT_HPP 19 | 20 | #include 21 | 22 | using std::vector; 23 | 24 | typedef unsigned long long int ULL; 25 | 26 | const int MAX_N = 93; // fibonacci(94) goes beyond the range of ULL 27 | 28 | 29 | // Product of two matrices. Their sizes must be [n, m] and [m, p] 30 | vector> matrix_product(const vector> &first_matrix, const vector> &second_matrix) { 31 | // Example: If First[n, m] and Second[m, p], then their product will be Product[n, p] 32 | vector> product_of_matrices(first_matrix.size(), vector (second_matrix[0].size())); 33 | 34 | for (size_t i = 0; i < first_matrix.size(); i++) // For previous example i:0..n-1 35 | for (size_t j = 0; j < second_matrix[0].size(); j++) // For previous example j:0..p-1 36 | for (size_t k = 0; k < second_matrix.size(); k++) // For previous example k:0..m-1 37 | product_of_matrices[i][j] += first_matrix[i][k] * second_matrix[k][j]; 38 | return product_of_matrices; 39 | } 40 | 41 | 42 | // Binary exponentiation (of matrix) 43 | vector> pow_matrix(const vector< vector > &matrix, const int n) { 44 | if (n == 1) 45 | return matrix; 46 | 47 | vector> tmp_matrix; 48 | vector> product_of_matrices; 49 | if (n % 2 == 0) { 50 | tmp_matrix = pow_matrix(matrix, n / 2); // a ^ n = a ^ (n / 2) * a ^ (n / 2) 51 | product_of_matrices = matrix_product(tmp_matrix, tmp_matrix); 52 | } 53 | else { 54 | tmp_matrix = pow_matrix(matrix, n - 1); // a ^ n = a ^ (n - 1) * a 55 | product_of_matrices = matrix_product(tmp_matrix, matrix); 56 | } 57 | return product_of_matrices; 58 | } 59 | 60 | 61 | ULL fibonacci(const int n) { 62 | if (n > MAX_N) 63 | return -1; 64 | 65 | if (n == 0 or n == 1) 66 | return n; // since F(0) = 0, and F(1) = 1 67 | if (n == 2) 68 | return 1; // F(2) = 1 69 | 70 | // recurrence formula (1 1) (F(n - 1)) ( F(n) ) 71 | // (1 0) * (F(n - 2)) = (F(n - 1)) 72 | vector> matrix = { 73 | {1, 1}, 74 | {1, 0} 75 | }; 76 | matrix = pow_matrix(matrix, n - 2); 77 | ULL fn = matrix[0][0] + matrix[0][1]; // F(n) 78 | 79 | return fn; 80 | } 81 | 82 | #endif // FIBONACCI_EFFICIENT_HPP 83 | -------------------------------------------------------------------------------- /cpp/include/algorithm/number_theory/greatest_common_divisor.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Euclid's greatest common divisor algorithm 3 | ------------------------------------------ 4 | The basic Euclidean algorithm is used to find the greatest common divisor of two 5 | numbers, a and b. The Euclidean algorithm is based on the principle that the greatest 6 | common divisor of two numbers does not change if the larger number is replaced by its 7 | difference with the smaller number. 8 | 9 | Time complexity 10 | --------------- 11 | O(log10(m)), where m = min(a, b) is the smaller of the input integers a and b 12 | 13 | Space complexity 14 | ---------------- 15 | O(1) 16 | */ 17 | 18 | /* 19 | greatest_common_divisor 20 | ----------------------- 21 | Returns the greatest common divisor of integers a and b. 22 | */ 23 | 24 | #ifndef GREATEST_COMMON_DIVISOR_HPP 25 | #define GREATEST_COMMON_DIVISOR_HPP 26 | 27 | int greatest_common_divisor(int a, int b) { 28 | a = abs(a); 29 | b = abs(b); 30 | 31 | if (a == 0) { 32 | return b; 33 | } 34 | 35 | return greatest_common_divisor(b % a, a); 36 | } 37 | 38 | #endif // GREATEST_COMMON_DIVISOR_HPP 39 | -------------------------------------------------------------------------------- /cpp/include/algorithm/number_theory/perfect_number_check.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Perfect number check 3 | -------------------- 4 | Checks whether the given number is perfect or not. 5 | A perfect number is one whose sum of divisors is equal to the number itself. 6 | 7 | Time complexity 8 | --------------- 9 | O(sqrt(N)), where N is the number being checked. 10 | 11 | Space complexity 12 | ---------------- 13 | O(1). 14 | */ 15 | 16 | #ifndef PERFECT_NUMBER_CHECK_HPP 17 | #define PERFECT_NUMBER_CHECK_HPP 18 | 19 | #include 20 | 21 | typedef unsigned long long ULL; 22 | 23 | bool is_perfect(ULL num) { 24 | ULL sum = 1; 25 | for (ULL divisor = 2; divisor <= sqrt(num); divisor++) { 26 | if (num % divisor == 0) 27 | sum += divisor + num/divisor; 28 | } 29 | 30 | if (sum == num) { 31 | return true; 32 | } 33 | return false; 34 | } 35 | 36 | #endif // PERFECT_NUMBER_CHECK_HPP 37 | -------------------------------------------------------------------------------- /cpp/include/algorithm/number_theory/primorial.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Primorial 3 | --------- 4 | Calculate the primorial Pn# for the prime number definition of primorial 5 | and n# for the natural number definition of primorial. 6 | Pn# is defined as the product of the first n primes. 7 | n# is defined as the product of all primes less than or equal to n. 8 | 9 | Time complexity 10 | --------------- 11 | O(N^2) where N is n for the natural definition and Pn for the prime 12 | definition. 13 | 14 | Space complexity 15 | ---------------- 16 | O(N) where N is n for the natural definition and Pn for the prime 17 | definition. 18 | */ 19 | 20 | #ifndef PRIMORIAL_HPP 21 | #define PRIMORIAL_HPP 22 | 23 | #include 24 | #include 25 | 26 | typedef unsigned long long int ULL; 27 | 28 | // primorial_natural(n) goes beyond the range of ULL where n > 52 29 | const unsigned int MAX_N_NATURAL = 52; 30 | 31 | // primorial(n) goes beyond the range of ULL where n > 15 32 | const unsigned int MAX_N = 15; 33 | 34 | // Computes the primorial defined by natural numbers: https://oeis.org/A034386 35 | // Returns 0 if n# is too big to fit in an ULL 36 | // Otherwise returns the primorial n#, where n# = the product of all primes ≤ n 37 | ULL primorial_natural(unsigned int n) { 38 | // Check for unsigned integer wraparound 39 | if (n > MAX_N_NATURAL) { 40 | return 0; 41 | } 42 | 43 | std::vector primes; 44 | 45 | ULL product = 1; 46 | 47 | for (unsigned int i = 2; i <= n; i++) { 48 | bool is_prime = true; 49 | for (auto it = primes.begin(); is_prime && it != primes.end(); it++) { 50 | if (i % *it == 0) { 51 | is_prime = false; 52 | } 53 | } 54 | if (is_prime) { 55 | product *= i; 56 | primes.push_back(i); 57 | } 58 | } 59 | 60 | return product; 61 | } 62 | 63 | // Computes the primorial defined by prime numbers: https://oeis.org/A002110 64 | // Returns 0 if Pn# is too big to fit in an ULL 65 | // Otherwise returns the primorial Pn#, where Pn# = the product of the first n primes 66 | ULL primorial(unsigned int n) { 67 | // Check for unsigned integer wraparound 68 | if (n > MAX_N) { 69 | return 0; 70 | } 71 | 72 | std::vector primes; 73 | 74 | ULL product = 1; 75 | 76 | for (unsigned int i = 2; primes.size() < n; i++) { 77 | bool is_prime = true; 78 | for (auto it = primes.begin(); is_prime && it != primes.end(); it++) { 79 | if (i % *it == 0) { 80 | is_prime = false; 81 | } 82 | } 83 | if (is_prime) { 84 | product *= i; 85 | primes.push_back(i); 86 | } 87 | } 88 | 89 | return product; 90 | } 91 | 92 | #endif // PRIMORIAL_HPP 93 | -------------------------------------------------------------------------------- /cpp/include/algorithm/number_theory/sieve_of_eratosthenes.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Sieve of Eratosthenes 3 | --------------------- 4 | Given a number N, find all prime numbers up to N (inclusive) using the simple 5 | Sieve of Eratosthenes method, which efficiently finds primes in the order of 6 | 10^7. (The efficiency limit is due to poor cache utilisation.) 7 | 8 | Time complexity 9 | --------------- 10 | O(N * log(log(N))), where N is the number up to which primes have to be found 11 | 12 | Space complexity 13 | ---------------- 14 | O(N), where N is the number up to which primes have to be found 15 | */ 16 | 17 | #ifndef SIEVE_OF_ERATOSTHENES_HPP 18 | #define SIEVE_OF_ERATOSTHENES_HPP 19 | 20 | #include 21 | #include 22 | 23 | using std::vector; 24 | 25 | // Determines primes up to primeLimit and returns list of primes in a vector 26 | vector getPrimes(const unsigned int &primeLimit) { 27 | // Check if larger than limit 28 | if (primeLimit > 10000000) { 29 | return vector({}); 30 | } 31 | 32 | vector boolPrimes(primeLimit + 1, true); // "sieve" to mark numbers as prime 33 | 34 | boolPrimes[0] = boolPrimes[1] = false; 35 | 36 | // Determine primes 37 | unsigned int multiple; 38 | for (unsigned int num = 2; num <= sqrt(primeLimit); num++) { 39 | // check if the number is prime 40 | if (boolPrimes[num]) { 41 | for (multiple = num * num; multiple <= primeLimit; multiple += num) 42 | { 43 | boolPrimes[multiple] = false; // mark its multiples as not prime 44 | } 45 | } 46 | } 47 | 48 | // Create output vector 49 | vector primes; 50 | for (unsigned int num = 2; num < boolPrimes.size(); num++) { 51 | if (boolPrimes[num]) { 52 | primes.push_back(num); 53 | } 54 | } 55 | 56 | return primes; 57 | } 58 | 59 | #endif // SIEVE_OF_ERATOSTHENES_HPP 60 | -------------------------------------------------------------------------------- /cpp/include/algorithm/searching/README.md: -------------------------------------------------------------------------------- 1 | # Searching 2 | Searching algorithms are designed to check for an element or retrieve an element from any data structure where it is stored. 3 | 4 | ### Contents 5 | 1. [Linear search](#1-linear-search) 6 | 2. [Binary search](#2-binary-search) 7 | 3. [Ternary search](#3-ternary-search) 8 | --- 9 | ## 1. Linear search 10 | In this algorithm the array is traversed sequentially and every element is checked until the element is found. 11 | 12 | ### Usage 13 | ``` c++ 14 | vector nums{1, 29, 6, 8, 5, 2, 0}; 15 | int index_found = linear_search(2, nums); 16 | std::cout << index_found << std::endl; // 5 17 | ``` 18 | ### Complexity 19 | 20 | Time | Space 21 | :--------:|:-------------------: 22 | _O(N)_ | _O(1)_ 23 | 24 | Where N is the number of elements in the array. 25 | 26 | ## 2. Binary search 27 | Search a sorted array by repeatedly dividing the search interval in half. Begin with an interval covering the whole array. If the value of the search key is less than the item in the middle of the interval, narrow the interval to the lower half. Otherwise narrow it to the upper half. Repeatedly check until the value is found or the interval is empty. The array must be sorted, if it is not, binary search won't work. 28 | 29 | ### Usage 30 | ``` c++ 31 | vector letters{'a', 'b', 'c', 'd', 'e'}; 32 | int index_found = binary_search('d', letters); 33 | std::cout << index_found << std::endl; // 3 34 | ``` 35 | 36 | ### Complexity 37 | Time | Space 38 | :--------:|:-------------------: 39 | _O(log(N))_ | _O(log(N))_ 40 | 41 | where N is the number of elements in the array. 42 | 43 | ## 3. Ternary search 44 | A ternary search algorithm is a technique in computer science for finding the minimum or maximum of a unimodal function. A ternary search determines either that the minimum or maximum cannot be in the first third of the domain or that it cannot be in the last third of the domain, then repeats on the remaining two thirds. A ternary search is an example of a divide and conquer algorithm. 45 | Array needs to be sorted to perform ternary search on it. 46 | 47 | ### Usage 48 | * **Search an element in a given array.** 49 | ``` c++ 50 | vector nums{1, 3, 4, 5, 8, 11, 20}; 51 | size_t index_found = ternary_search(4, nums); 52 | std::cout << index_found << std::endl; // 2 53 | ``` 54 | * **Given a function f(x) and an integral interval [a, b]** 55 | ```c++ 56 | int ascending_descending_func_int(int x) { 57 | return -(x - 2) * (x - 2); 58 | } 59 | int descending_ascending_func_int(int x) { 60 | return (x - 5) * (x - 5) * (x - 5) * (x - 5); 61 | } 62 | 63 | int main(int argc, const char *argv[]) { 64 | int maximum = ternary_search(&ascending_descending_func_int, 1, 7, ASCEND_THEN_DESCEND); 65 | 66 | int minimun = ternary_search(&descending_ascending_func_int, 2, 6, DESCEND_THEN_ASCEND); 67 | 68 | std::cout << maximum << std::endl; // 2 69 | std::cout << maximum << std::endl; // 5 70 | 71 | return 0; 72 | } 73 | ``` 74 | * **Given a function f(x) and an floating point interval [a, b]** 75 | ```c++ 76 | float ascending_descending_func_float(float x) { 77 | return -(x - 9.0f) * (x - 9.0f); 78 | } 79 | 80 | float descending_ascending_func_float(float x) { 81 | return (x - 0.5f) * (x - 0.5f) * (x - 0.5f) * (x - 0.5f); 82 | } 83 | 84 | int main(int argc, const char *argv[]) { 85 | float maximum = ternary_search(&ascending_descending_func_float, 8.0, 9.0, ASCEND_THEN_DESCEND, 10e-9); 86 | float minimum = ternary_search(&descending_ascending_func_float, 0.4, 0.5, DESCEND_THEN_ASCEND, 10e-9) 87 | 88 | std::cout << maximum << std::endl; // Approx(9.0); 89 | std::cout << minimum << std::endl; // Approx(0.5); 90 | 91 | return 0; 92 | } 93 | ``` 94 | 95 | ### Complexity 96 | Time | Space 97 | :--------:|:-------------------: 98 | _O(log3(N))_ | _O(1)_ 99 | 100 | where N is the number of elements in the array. 101 | -------------------------------------------------------------------------------- /cpp/include/algorithm/searching/binary_search.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Binary search 3 | ------------- 4 | A searching algorithm that finds the index of a target value within a 5 | sorted array using divide and conquer. 6 | 7 | Time complexity 8 | --------------- 9 | O(log(N)), where N is the number of elements in the array. 10 | 11 | Space complexity 12 | ---------------- 13 | O(1). 14 | */ 15 | 16 | #ifndef BINARY_SEARCH_HPP 17 | #define BINARY_SEARCH_HPP 18 | 19 | #include 20 | 21 | /* 22 | binary_search 23 | ------------- 24 | It compares the target value to the middle element of the array; if they 25 | are unequal, the half in which the target cannot lie is eliminated and the 26 | search continues on the remaining half until it is successful. If the search 27 | ends with the remaining half being empty, the target is not in the array. 28 | */ 29 | 30 | template 31 | int binary_search(const T& value, const std::vector& sorted_values, 32 | const int low, const int high) { 33 | int mid = low + (high - low) / 2; 34 | 35 | if (value == sorted_values[mid]) 36 | return mid; 37 | else if (low <= high) { 38 | if (value < sorted_values[mid]) { 39 | // value must be between indices low and mid-1, if exists 40 | return binary_search(value, sorted_values, low, mid - 1); 41 | } 42 | else if (value > sorted_values[mid]) { 43 | // value must be between indices mid+1 and high, if exists 44 | return binary_search(value, sorted_values, mid + 1, high); 45 | } 46 | } 47 | 48 | return -1; 49 | } 50 | 51 | 52 | /* 53 | binary_search 54 | ------------- 55 | Convenience function for binary search that requires minimal arguments. 56 | */ 57 | 58 | template 59 | int binary_search(const T& value, const std::vector& sorted_values) { 60 | if (sorted_values.size() == 0) 61 | return -1; 62 | 63 | return binary_search(value, sorted_values, 0, sorted_values.size() - 1); 64 | } 65 | 66 | #endif // BINARY_SEARCH_HPP 67 | -------------------------------------------------------------------------------- /cpp/include/algorithm/searching/linear_search.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Linear search 3 | ------------- 4 | A searching algorithm that finds the position of a target value within an 5 | array (sorted or otherwise). 6 | 7 | Time complexity 8 | --------------- 9 | O(N), where N is the number of elements in the array. 10 | 11 | Space complexity 12 | ---------------- 13 | O(1). 14 | */ 15 | 16 | #ifndef LINEAR_SEARCH_HPP 17 | #define LINEAR_SEARCH_HPP 18 | 19 | #include 20 | 21 | /* 22 | linear_search 23 | ------------- 24 | Returns the index where a given element is found in an array. If the 25 | element is not found, it returns -1. 26 | */ 27 | 28 | template 29 | int linear_search(const T& element, const std::vector& values) { 30 | for (size_t i = 0; i < values.size(); i++) 31 | if (values[i] == element) // it's a match! 32 | return i; // return the index at which it was found 33 | 34 | return -1; // no match is found 35 | } 36 | 37 | #endif // LINEAR_SEARCH_HPP 38 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/README.md: -------------------------------------------------------------------------------- 1 | # Sorting 2 | Sorting algorithms are designed to arrange data in a particular order. Sorting algoritms have a few properties: 3 | 4 | #### Stable and unstable sorting 5 | **Stable:** Identical elements remain in the same order as before sorting. 6 | **Unstable:** Identical elements may be sorted in any order. 7 | 8 | #### In-place and Not In-place Sorting 9 | **In-place**: Elements are sorted by modifying their order directly. 10 | **Not in-place**: An auxiliary data structure is used for sorting. 11 | 12 | ### Contents 13 | 1. [Bubble sort](#1-bubble-sort) 14 | 2. [Bucket sort](#2-bucket-sort) 15 | 3. [Comb sort](#3-comb-sort) 16 | 4. [Counting sort](#4-counting-sort) 17 | 5. [Heap sort](#5-heap-sort) 18 | 6. [Insertion sort](#6-insertion-sort) 19 | 7. [Merge sort](#7-merge-sort) 20 | 8. [Quick sort](#8-quick-sort) 21 | 9. [Radix sort](#9-radix-sort) 22 | 10. [Selection sort](#10-selection-sort) 23 | 11. [Shell sort](#11-shell-sort) 24 | 25 | --- 26 | 27 | ## 1. Bubble sort 28 | A simple algorithm which repeatedly compares pairs of adjacent elements and swaps their positions if they are in the wrong order. Also known as sinking sort. 29 | 30 | ### Usage 31 | ``` c++ 32 | vector arr{1, 8, 5, 12, 3}; 33 | bubble_sort(arr, -1, true); 34 | ``` 35 | ### Complexity 36 | 37 | Time | Space 38 | :--------:|:-------------------: 39 | _O(N^2)_ | _O(1)_ 40 | 41 | Where N is the number of elements in the array. 42 | 43 | ## 2. Bucket sort 44 | A sorting algorithm that works by dividing elements into different buckets, and then sorting the buckets individually. Each bucket is then sorted individually by using a different sorting algorithm. Insertion sort is used in this implementation, but other algorithms can be used. 45 | 46 | ### Usage 47 | ``` c++ 48 | vector arr{1, 8, 5, 12, 3}; 49 | bucket_sort(arr, -1, true); 50 | ``` 51 | ### Complexity 52 | 53 | Time | Space 54 | :--------:|:-------------------: 55 | _O(N + N^2 / K+K)_ | _O(N)_ 56 | 57 | Where N is the number of elements, and K is the number of buckets 58 | 59 | ## 3. Comb sort 60 | A sorting algorithm designed to improve upon bubble sort by eliminating small values that start near the end of the list. 61 | 62 | ### Usage 63 | ``` c++ 64 | vector arr{1, 8, 5, 12, 3}; 65 | comb_sort(arr, -1, true); 66 | ``` 67 | ### Complexity 68 | 69 | Time | Space 70 | :--------:|:-------------------: 71 | _O(N^2 / 2^p)_ | _O(1)_ 72 | 73 | Where N is the number of elements, and p is the number of increments 74 | 75 | ## 4. Counting sort 76 | An integer sorting algorithm that operates by counting the number of objects that have each distinct key value, and using arithmetic on those counts to determine the positions of each key value in the output sequence. This is a stable and comparision based algorithm. 77 | 78 | ### Usage 79 | ``` c++ 80 | vector arr{1, 8, 5, 12, 3}; 81 | couting_sort(arr, -1, true); 82 | ``` 83 | ### Complexity 84 | 85 | Time | Space 86 | :--------:|:-------------------: 87 | _O(N + R)_ | _O(N + K)_ 88 | 89 | Where N is the number of elements, R is the range of input and K the size of the frequency array. 90 | 91 | ## 5. Heap sort 92 | A comparison-based sorting algorithm that uses an array-implemented heap to sort a list of integers. 93 | 94 | ### Usage 95 | ``` c++ 96 | vector arr{1, 8, 5, 12, 3}; 97 | heap_sort(arr, -1, true); 98 | ``` 99 | ### Complexity 100 | 101 | Time | Space 102 | :--------:|:-------------------: 103 | _O(N * log(N))_ | _O(1)_ 104 | 105 | Where N is the number of elements 106 | 107 | ## 6. Insertion sort 108 | An in-place, comparison based sorting algorithm that builds the final sorted list one item at a time. This is a recursive algorithm more efficient for small data sets than most other quadratic-time algorithms. 109 | 110 | ### Usage 111 | ``` c++ 112 | vector arr{1, 8, 5, 12, 3}; 113 | insertion_sort(arr, -1, true); 114 | ``` 115 | ### Complexity 116 | 117 | Time | Space 118 | :--------:|:-------------------: 119 | _O(N^2)_ | _O(1)_ 120 | 121 | Where N is the number of elements in the array. 122 | 123 | ## 7. Merge sort 124 | An algorithm that uses the concept 'divide and conquer'. This is a not in-place sorting algorithm and is efficient. 125 | 126 | ### Usage 127 | ``` c++ 128 | vector arr{1, 8, 5, 12, 3}; 129 | merge_sort(arr, -1, true); 130 | ``` 131 | ### Complexity 132 | 133 | Time | Space 134 | :--------:|:-------------------: 135 | _O(N * log(N))_ | _O(1)_ 136 | 137 | Where N is the number of elements. 138 | 139 | ## 8. Quick sort 140 | An efficient sorting algorithm that uses the concept of 'divide and conquer'. This is a recursive algorithm. 141 | 142 | ### Usage 143 | ``` c++ 144 | vector arr{1, 8, 5, 12, 3}; 145 | quick_sort(arr, -1, true); 146 | ``` 147 | ### Complexity 148 | 149 | Time | Space 150 | :--------:|:-------------------: 151 | Absolute case:_O(N^2)_ | _O(1)_ 152 | Expected case:_O(N * log(N)_ | _O(1)_ 153 | 154 | Where N is the number of elements. 155 | 156 | ## 9. Radix sort 157 | Least significant digit radix sort is an efficient, non-comparative, integer sorting algorithm that sorts data with integer keys by grouping keys by the individual digits which share the same significant position and value. Note that this implementation of radix sort can be used to sort positive integers only. 158 | 159 | ### Usage 160 | ``` c++ 161 | vector arr{1, 8, 5, 12, 3}; 162 | radix_sort(arr, -1, true); 163 | ``` 164 | ### Complexity 165 | 166 | Time | Space 167 | :--------:|:-------------------: 168 | _O(N)_ | _O(N)_ 169 | 170 | Where N is the number of keys 171 | 172 | ## 10. Selection sort 173 | A simple in-place comparison-based sorting algorithm. This sorts a list by finding the smallest or largest element (depending on the sorting order) from the unsorted sublist and swapping it with the leftmost unsorted element, then moving the sublist boundary one element to the right. 174 | 175 | ### Usage 176 | ``` c++ 177 | vector arr{1, 8, 5, 12, 3}; 178 | selection_sort(arr, -1, true); 179 | ``` 180 | ### Complexity 181 | 182 | Time | Space 183 | :--------:|:-------------------: 184 | _O(N^2)_ | _O(1)_ 185 | 186 | Where N is the number of elements in the array. 187 | 188 | ## 11. Shell sort 189 | An in-place comparison sort which starts by sorting pairs of elements far apart from each other, then progressively reducing the gap between elements to be compared. The time complexity depends on the gap sequence, which is _floor(N / 2^K)_ in this implementation. 190 | 191 | ### Usage 192 | ``` c++ 193 | vector arr{1, 8, 5, 12, 3}; 194 | shell_sort(arr, -1, true); 195 | ``` 196 | ### Complexity 197 | 198 | Time | Space 199 | :--------:|:-------------------: 200 | _O(N^2)_ | _O(1)_ 201 | 202 | Where N is the number of elements 203 | 204 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/bubble_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Bubble sort 3 | ----------- 4 | A simple sorting algorithm that repeatedly compares pairs of adjacent 5 | elements and swaps their positions if they are in the wrong order. 6 | Also known as sinking sort. 7 | 8 | Time complexity 9 | --------------- 10 | O(N^2), where N is the number of elements. 11 | 12 | Space complexity 13 | ---------------- 14 | O(1). 15 | */ 16 | 17 | #ifndef BUBBLE_SORT_HPP 18 | #define BUBBLE_SORT_HPP 19 | 20 | #include 21 | #include "utils.hpp" 22 | 23 | using std::vector; 24 | 25 | void bubble_sort(vector& values, const int order = 1, const bool to_show_state = false) { 26 | bool swapped; 27 | size_t i, j; 28 | 29 | for (i = 0; i < values.size() - 1; i++) { 30 | swapped = false; 31 | for (j = 0; i + j < values.size() - 1; j++) { 32 | // 'order' is -1 for descending, so the inequality is reversed: 33 | if (order * values[j] > order * values[j+1]) { 34 | swap(values[j], values[j+1]); 35 | swapped = true; 36 | 37 | if (to_show_state) 38 | display_state(values); 39 | } 40 | } 41 | if (!swapped) 42 | break; 43 | } 44 | } 45 | 46 | #endif // BUBBLE_SORT_HPP 47 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/bucket_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Bucket sort 3 | ---------------------- 4 | Bucket sort, or bin sort, is an integer sorting algorithm that works by 5 | distributing the elements of an array into a number of buckets. Each 6 | is then sorted individually using a different sorting algorithm. 7 | Insertion sort is used in this implementation, but other sorting 8 | algorithms can be used, too. 9 | 10 | This is a linear sorting algorithm for evenly distributed items. 11 | 12 | Time complexity 13 | --------------- 14 | O(N ^ 2) worst case 15 | O(N + N^2 / k + k) average case when k is the number of buckets, 16 | which is O(n) if K ~ N 17 | 18 | Space complexity 19 | ---------------- 20 | O(N) 21 | */ 22 | 23 | #ifndef BUCKET_SORT_HPP 24 | #define BUCKET_SORT_HPP 25 | 26 | #include 27 | #include 28 | #include "utils.hpp" 29 | #include "insertion_sort.hpp" 30 | 31 | using std::vector; 32 | using std::list; 33 | 34 | void bucket_sort(vector& values, const int order = 1, const bool to_show_state = false) { 35 | 36 | if (values.empty()) { 37 | return; 38 | } 39 | 40 | auto max_value = values[0], min_value = values[0]; 41 | int negative_count = 0, positive_count = 0; 42 | 43 | for (int i : values) { 44 | max_value = std::max(max_value, i); 45 | min_value = std::min(min_value, i); 46 | negative_count += i < 0; 47 | positive_count += i >= 0; 48 | } 49 | 50 | // The number of negative buckets will be the number of negative elements 51 | vector> negative_buckets(negative_count); 52 | 53 | // The number of positive buckets will be the number of positive elements 54 | vector> positive_buckets(positive_count); 55 | 56 | // Insert the items into their appropriate bucket 57 | for (float i : values) { 58 | if (i > 0) { 59 | // As the bucket index grows, elements get larger 60 | float bucket_index = (positive_buckets.size() * i / max_value) - 1; 61 | positive_buckets[static_cast(bucket_index)].push_back(i); 62 | 63 | } else if (i < 0) { 64 | // As the bucket index grows, elements get smaller 65 | float bucket_index = (negative_buckets.size() * i / min_value) - 1; 66 | negative_buckets[static_cast(bucket_index)].push_back(i); 67 | 68 | } else { 69 | // Special case for 0 70 | positive_buckets[0].push_back(i); 71 | } 72 | }; 73 | 74 | values.clear(); 75 | 76 | auto sort_buckets_and_unify = [&](auto it_start, auto it_end) { 77 | for_each(it_start, it_end,[&](auto bucket) { 78 | 79 | // Sort each bucket individually using internal file insertion_sort.hpp 80 | // Note that other sorting algorithms can also be used 81 | vector sorted(bucket.size()); 82 | sorted.assign(begin(bucket), end(bucket)); 83 | insertion_sort(sorted, order, false); 84 | 85 | // Insert the sorted bucket result into the original values vector 86 | values.insert(end(values), begin(sorted), end(sorted)); 87 | 88 | if (to_show_state) { 89 | display_state(values); 90 | } 91 | }); 92 | }; 93 | 94 | if (order == 1) { 95 | // 1 means ascending, so we should start from the smallest negative 96 | // element and end with the largest positive element 97 | sort_buckets_and_unify(rbegin(negative_buckets), rend(negative_buckets)); 98 | sort_buckets_and_unify(begin(positive_buckets), end(positive_buckets)); 99 | } else { 100 | // -1 means descending, so we should start from the largest positive 101 | // element and end with the smallest negative element 102 | sort_buckets_and_unify(rbegin(positive_buckets), rend(positive_buckets)); 103 | sort_buckets_and_unify(begin(negative_buckets), end(negative_buckets)); 104 | } 105 | } 106 | 107 | #endif // BUCKET_SORT_HPP 108 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/comb_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Comb Sort by Cole Severson 3 | --------- 4 | A sorting algorithm designed to improve upon bubble sort by by eliminating small values that start near the end of 5 | the list. 6 | 7 | Time Complexity 8 | --------------- 9 | O(N^2), worst case where N is the number of elements 10 | O(N^2/2^p), average case where p is the number of increments and N is the number of elements 11 | 12 | Space Complexity 13 | ---------------- 14 | O(1) 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include "./utils.hpp" 21 | 22 | unsigned int get_next_gap(unsigned int gap) { 23 | double shrink_factor = 1.3; // approximation of optimal factor 24 | gap = floor(gap / shrink_factor); 25 | 26 | // Prevent gap from dropping below 1 27 | if (gap < 1) { 28 | gap = 1; 29 | } 30 | return gap; 31 | } 32 | 33 | void comb_sort (vector& input, const int order = 1, const bool to_show_state = false) { 34 | unsigned int gap = input.size(); 35 | bool swapped = true; 36 | 37 | // Continue while gap is larger than one or there was a swap on previous iteration 38 | while (gap > 1 || swapped) { 39 | gap = get_next_gap(gap); 40 | swapped = false; 41 | for (int i = 0; i + gap < input.size(); i++) { 42 | if (order * input[i] > order * input[i+gap]) { 43 | swap(input[i], input[i+gap]); 44 | swapped = true; 45 | } 46 | if (to_show_state) { 47 | display_state(input); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/counting_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Counting sort (stable) 3 | ---------------------- 4 | An integer sorting algorithm that operates by counting the number of objects 5 | that have each distinct key value, and using arithmetic on those counts to 6 | determine the positions of each key value in the output sequence. 7 | 8 | Time complexity 9 | --------------- 10 | O(N + R), where N is the number of elements and R is the range of input. 11 | 12 | Space complexity 13 | ---------------- 14 | O(N + K), where N is the number of elements and K the size of the frequency array. 15 | */ 16 | 17 | #ifndef COUNTING_SORT_HPP 18 | #define COUNTING_SORT_HPP 19 | 20 | #include 21 | #include "utils.hpp" 22 | 23 | using std::vector; 24 | 25 | void counting_sort(vector& values, const int order = 1, const bool to_show_state = false) { 26 | int min_value = values[0]; 27 | int max_value = values[0]; 28 | 29 | // Find minimum and maximum values in input vector 30 | for (int value: values) { 31 | if (value < min_value) { 32 | min_value = value; 33 | } 34 | else if (value > max_value) { 35 | max_value = value; 36 | } 37 | } 38 | 39 | // Calculate unique values in input vector 40 | const int unique_values = max_value - min_value + 1; 41 | 42 | // Calculate frequencies of each unique value in input vector 43 | // freq[0] is number of min_value occurrences and so on 44 | vector freq(unique_values, 0); 45 | for (int value: values) { 46 | ++freq[value - min_value]; 47 | } 48 | 49 | // Start and end indices, for calculating cumulative frequency 50 | long start = 1; 51 | long end = freq.size(); 52 | 53 | // If order is reversed, the indices are reversed too 54 | if (order == -1) { // 'order' is -1 for descending, 1 for ascending 55 | start = freq.size() - 2; 56 | end = -1; 57 | } 58 | 59 | // Calculate cumulative frequency: 60 | // freq[i] will now be the number of elements in the sorted array that are 61 | // less than or equal to value[i] 62 | for (long i = start; i != end; i += order) { 63 | freq[i] += freq[i - order]; 64 | } 65 | 66 | // Place values in sorted order by iterating input vector in reversed order, 67 | // to maintain sorting stability 68 | vector sorted(values.size()); 69 | int value; 70 | for (auto iter = values.rbegin(); iter != values.rend(); ++iter) { 71 | value = *iter; 72 | sorted[freq[value - min_value] - 1] = value; 73 | --freq[value - min_value]; 74 | 75 | if (to_show_state) { 76 | display_state(sorted); 77 | } 78 | } 79 | 80 | values.assign(sorted.begin(), sorted.end()); 81 | } 82 | 83 | #endif // COUNTING_SORT_HPP 84 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/heap_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Heap sort 3 | --------- 4 | A comparison-based sorting algorithm that uses an array-implemented heap to 5 | sort a list of integers. 6 | 7 | Time complexity 8 | --------------- 9 | O(N * log(N)), where N is the number of elements. 10 | 11 | Space complexity 12 | ---------------- 13 | O(1). 14 | */ 15 | 16 | #ifndef HEAP_SORT_HPP 17 | #define HEAP_SORT_HPP 18 | 19 | #include 20 | #include "utils.hpp" 21 | 22 | using std::vector; 23 | 24 | /* 25 | heapify 26 | ------- 27 | Creates a max heap from a vector of integers. 28 | */ 29 | void heapify(vector& heap, int parent, const int last) { 30 | int child = parent*2 + 1; 31 | while (child <= last) { // travel down the children 32 | if (child + 1 <= last and heap[child + 1] > heap[child]) { 33 | child++; // child is now the larger of its siblings 34 | } 35 | 36 | if (heap[parent] < heap[child]) { 37 | swap(heap[parent], heap[child]); // if the parent is smaller, swap it with its child 38 | } 39 | 40 | parent = child; 41 | child = parent*2 + 1; 42 | } 43 | } 44 | 45 | /* 46 | sort 47 | ---- 48 | Removes the largest element, replaces it with the last element, and calls 49 | heapify to recreate the max heap. 50 | */ 51 | void sort(vector &heap, const int size, const bool to_show_state = false) { 52 | if (to_show_state) { 53 | cout << "\nPerforming heap sort on the heap...\n"; 54 | } 55 | 56 | int last = size - 1; 57 | while (last >= 0) { 58 | swap(heap[0], heap[last]); 59 | last--; 60 | heapify(heap, 0, last); 61 | 62 | if (to_show_state) { 63 | display_state(heap); 64 | } 65 | } 66 | } 67 | 68 | /* 69 | make_heap 70 | --------- 71 | Makes an ordered heap by heapifying from highest indexed non-leaf node (curr_node) 72 | to the top node (heap[0]). 73 | */ 74 | void make_heap(vector& heap, const int size, const bool to_show_state = false) { 75 | if (to_show_state) 76 | cout << "\nMaking initial heap...\n"; 77 | 78 | for (int curr_node = size/2 - 1; curr_node >= 0; curr_node--) { 79 | heapify(heap, curr_node, size - 1); //last_element = heap_size - 1 80 | 81 | if (to_show_state) { 82 | display_state(heap); 83 | } 84 | } 85 | 86 | if (to_show_state) { 87 | cout << "Initial heap has been made.\n"; 88 | } 89 | } 90 | 91 | /* 92 | heap_sort 93 | --------- 94 | Combines the sorting and heapifying functionality into one function 95 | */ 96 | void heap_sort(vector& values, const int order = 1, const bool to_show_state = false) { 97 | size_t size = values.size(); 98 | make_heap(values, size, to_show_state); 99 | sort(values, size, to_show_state); 100 | 101 | // Reverse for descending, if necessary 102 | if (order == -1) { 103 | reverse(values.begin(), values.end()); 104 | } 105 | } 106 | 107 | #endif // HEAP_SORT_HPP 108 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/insertion_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Insertion sort 3 | -------------- 4 | A simple sorting algorithm that builds the final sorted list of value one item at a time. 5 | It is more efficient than most other quadratic-time algorithms. 6 | 7 | Time complexity 8 | --------------- 9 | O(N^2), where N is the number of elements. 10 | 11 | Space complexity 12 | ---------------- 13 | O(1). 14 | */ 15 | 16 | #ifndef INSERTION_SORT_HPP 17 | #define INSERTION_SORT_HPP 18 | 19 | #include 20 | #include "utils.hpp" 21 | 22 | using std::vector; 23 | 24 | /* 25 | Insertion sort 26 | -------------- 27 | Builds a sorted list by finding elements based on their value and placing them in the sorted list. 28 | */ 29 | void insertion_sort(vector& values, const int order = 1, const bool to_show_state = false) { 30 | size_t i, j; 31 | int currentValue; 32 | 33 | for (i = 1; i < values.size(); i++) { 34 | j = i; 35 | currentValue = values[j]; 36 | 37 | // 'order' is -1 for descending, so the inequality is reversed: 38 | while (j > 0 && (order * values[j-1] > order * currentValue)) { 39 | values[j] = values[j-1]; 40 | j--; 41 | } 42 | values[j] = currentValue; 43 | 44 | if (to_show_state) { 45 | display_state(values); 46 | } 47 | } 48 | } 49 | 50 | #endif // INSERTION_SORT_HPP 51 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/merge_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Merge sort 3 | ---------- 4 | An efficient, comparison-based, divide and conquer sorting algorithm. 5 | It divides input array into two halves, recursively calls itself for the two halves and 6 | then merges the two sorted halves. 7 | 8 | Time complexity 9 | --------------- 10 | O(N * log(N)), where N is the number of elements. 11 | 12 | Space complexity 13 | ---------------- 14 | O(N), where N is the number of elements. 15 | This space is used for merging two halves of the array. 16 | */ 17 | 18 | #ifndef MERGE_SORT_HPP 19 | #define MERGE_SORT_HPP 20 | 21 | #include 22 | #include "utils.hpp" 23 | 24 | using std::vector; 25 | 26 | // Merge sorted halves 27 | void merge(vector& values, const size_t start, const size_t end, const int order = 1) { 28 | size_t mid = (start + end) / 2; 29 | size_t index1 = start; 30 | size_t index2 = mid + 1; 31 | 32 | vector temp_vect(end - start + 1); 33 | for (int& next_val: temp_vect) { 34 | if (index1 > mid) { 35 | // First part has ended, copy from the second part 36 | next_val = values[index2++]; 37 | } 38 | else if (index2 > end) { 39 | // Second part has ended, copy from the first part 40 | next_val = values[index1++]; 41 | } 42 | else { 43 | // Copy the value that's next in order 44 | // 'order' is -1 for descending, so the inequality is reversed: 45 | if (order * values[index1] < order * values[index2]) { 46 | next_val = values[index1++]; 47 | } 48 | else { 49 | next_val = values[index2++]; 50 | } 51 | } 52 | } 53 | 54 | size_t s = start; 55 | for (int sorted_value: temp_vect) 56 | values[s++] = sorted_value; 57 | } 58 | 59 | // Carry out merge sort 60 | void merge_sort_range(vector& values, const size_t start, const size_t end, 61 | const int order = 1, const bool to_show_state = false) { 62 | if (start < end) { 63 | size_t mid = (start + end) / 2; 64 | 65 | merge_sort_range(values, start, mid, order, to_show_state); 66 | merge_sort_range(values, mid + 1, end, order, to_show_state); 67 | 68 | merge(values, start, end, order); 69 | 70 | if (to_show_state) { 71 | display_state(values); 72 | } 73 | } 74 | } 75 | 76 | // Wrapper function 77 | void merge_sort(vector& values, const int order = 1, const bool to_show_state = false) { 78 | size_t size = values.size(); 79 | merge_sort_range(values, 0, size - 1, order, to_show_state); 80 | } 81 | 82 | #endif // MERGE_SORT_HPP 83 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/quick_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Quick sort 3 | ---------- 4 | An efficient, comparison-based, in-place, divide and conquer sorting algorithm. 5 | It picks an element as pivot, partitions the given array around the picked 6 | pivot and then recursively calls itself on those partitions. 7 | 8 | Time complexity 9 | --------------- 10 | Absolute worst case: O(N^2) 11 | Expected worst case: O(N * log(N)) 12 | where N is the number of elements. 13 | 14 | Space complexity 15 | ---------------- 16 | O(1). 17 | */ 18 | 19 | #ifndef QUICK_SORT_HPP 20 | #define QUICK_SORT_HPP 21 | 22 | #include // rand(), srand() 23 | #include // time() 24 | #include 25 | #include "utils.hpp" 26 | 27 | using std::vector; 28 | 29 | // Partition set based on pivot 30 | size_t partition(vector& values, const size_t start, const size_t end, const int order = 1) { 31 | // Choose a random index between start & end 32 | size_t random_index = start + (rand() % (end - start + 1)); 33 | 34 | // Swap the value there with the first value in given range 35 | swap(values[random_index], values[start]); 36 | 37 | // Make that value the pivot element 38 | int pivot = values[start]; 39 | 40 | size_t i = start + 1; 41 | for (size_t j = start + 1; j <= end; j++) { 42 | // Place elements which are less than the pivot on one side, 43 | // and those which are greater on the other 44 | if (order * values[j] < order * pivot) { 45 | swap(values[i], values[j]); 46 | i++; 47 | } 48 | } 49 | 50 | // Place the pivot in its proper place 51 | swap(values[start], values[i-1]); 52 | 53 | return i-1; // pivot's index 54 | } 55 | 56 | // Carry out quick sort algorithm 57 | void quick_sort_internal(vector& values, const int start, const int end, const int order = 1, 58 | const bool to_show_state = false) { 59 | if (start < end) { 60 | size_t pivot_index = partition(values, start, end, order); 61 | 62 | // Sort values to the left of pivot 63 | quick_sort_internal(values, start, pivot_index-1, order, to_show_state); 64 | 65 | // Sort values to the right of pivot 66 | quick_sort_internal(values, pivot_index+1, end, order, to_show_state); 67 | 68 | if (to_show_state) { 69 | display_state(values); 70 | } 71 | } 72 | } 73 | 74 | // Wrapper function 75 | void quick_sort(vector& values, const int order = 1, const bool to_show_state = false) { 76 | srand(time(0)); // seed PRNG 77 | size_t size = values.size(); 78 | quick_sort_internal(values, 0, size - 1, order, to_show_state); 79 | } 80 | 81 | #endif // QUICK_SORT_HPP 82 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/radix_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Radix sort 3 | ---------- 4 | Least significant digit radix sort is an efficient, non-comparative, integer 5 | sorting algorithm that sorts data with integer keys by grouping keys by the 6 | individual digits which share the same significant position and value. 7 | 8 | NOTE: This implementation of radix sort can be used to sort positive integers 9 | only. 10 | */ 11 | 12 | #ifndef RADIX_SORT_HPP 13 | #define RADIX_SORT_HPP 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "utils.hpp" 20 | 21 | using std::vector; 22 | using std::array; 23 | 24 | /* 25 | count_sort 26 | ---------- 27 | Performs count sort on the elements passed by radix_sort. 28 | 29 | Time complexity 30 | --------------- 31 | O(N), where N is the number of keys. 32 | 33 | Space complexity 34 | ---------------- 35 | O(N), where N is the number of keys. 36 | */ 37 | void count_sort(vector& values, const int extractor, const int mult_factor, 38 | const int add_factor, const bool to_show_state = false) { 39 | array counter{0}; 40 | vector output(values.size()); 41 | 42 | auto get_digit = [&] (const int value) { 43 | return add_factor + (mult_factor * ((value / extractor) % 10)); 44 | }; 45 | 46 | for (int value: values) { 47 | counter[get_digit(value)]++; 48 | } 49 | for (int i = 1; i < 10; i++) { 50 | counter[i] += counter[i - 1]; 51 | } 52 | for (int i = values.size() - 1; i >= 0; i--) { 53 | output[counter[get_digit(values[i])] - 1] = values[i]; 54 | counter[get_digit(values[i])]--; 55 | } 56 | 57 | values = output; 58 | 59 | if (to_show_state) { 60 | display_state(values); 61 | } 62 | } 63 | 64 | /* 65 | max_in_vector 66 | ------------- 67 | Returns the maximum value in a vector. 68 | */ 69 | int max_in_vector(const vector& values) { 70 | return *max_element(values.begin(), values.end()); 71 | } 72 | 73 | /* 74 | radix_sort_internal 75 | ------------------- 76 | Performs least significant digit radix sort, making use of count_sort. 77 | 78 | Time complexity 79 | --------------- 80 | O(N), where N is the number of keys. 81 | 82 | Space complexity 83 | ---------------- 84 | O(N), where N is the number of keys. 85 | */ 86 | void radix_sort_internal(vector& values, const int mult_factor, const int add_factor, 87 | const bool to_show_state = false) { 88 | int max_value = max_in_vector(values); 89 | 90 | // On each iteration of the following loop, extractor helps in getting the 91 | // next significant digit, which is (value / extractor) mod 10 92 | for (int extractor = 1; max_value / extractor > 0; extractor *= 10) { 93 | count_sort(values, extractor, to_show_state, mult_factor, add_factor); 94 | } 95 | } 96 | 97 | // Wrapper function 98 | void radix_sort(vector& values, const int order = 1, const bool to_show_state = false) { 99 | // The following factors depend on the sorting order 100 | int mult_factor = 1; 101 | int add_factor = 0; 102 | if (order == -1) { 103 | mult_factor = -1; 104 | add_factor = 9; 105 | } 106 | 107 | radix_sort_internal(values, mult_factor, add_factor, to_show_state); 108 | } 109 | 110 | #endif // RADIX_SORT_HPP 111 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/selection_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Selection sort 3 | -------------- 4 | A simple in-place comparision-based sorting algorithm. 5 | It sorts a list by finding the smallest / largest element (depending on the 6 | sorting order) from the unsorted sublist and swapping it with the leftmost 7 | unsorted element, moving the sublist boundary one element to the right. 8 | 9 | Time complexity 10 | --------------- 11 | O(N^2), where N is the number of elements. 12 | 13 | Space complexity 14 | ---------------- 15 | O(1). 16 | */ 17 | 18 | #ifndef SELECTION_SORT_HPP 19 | #define SELECTION_SORT_HPP 20 | 21 | #include 22 | #include "utils.hpp" 23 | 24 | using std::vector; 25 | 26 | void selection_sort(vector& values, const int order = 1, const bool to_show_state = false) { 27 | size_t current_extreme_index; // index of either the current minimum or maximum value, depending on the order 28 | size_t i, j; 29 | for (i = 0; i < values.size() - 1; i++) { 30 | current_extreme_index = i; 31 | j = i + 1; 32 | while (j < values.size()) { 33 | // 'order' is -1 for descending, so the inequality is reversed: 34 | if (order * values[j] < order * values[current_extreme_index]) { 35 | current_extreme_index = j; 36 | } 37 | j++; 38 | } 39 | swap(values[i], values[current_extreme_index]); 40 | 41 | if (to_show_state) { 42 | display_state(values); 43 | } 44 | } 45 | } 46 | 47 | #endif // SELECTION_SORT_HPP 48 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/shell_sort.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Shell sort 3 | ---------- 4 | An in-place comparison sort which starts by sorting pairs of elements far 5 | apart from each other, then progressively reducing the gap between elements 6 | to be compared. The time complexity depends on the gap sequence, which is 7 | floor(N / 2^K) in this implementation. 8 | 9 | Time complexity 10 | --------------- 11 | O(N^2), where N is the number of elements. 12 | 13 | Space complexity 14 | ---------------- 15 | O(1). 16 | */ 17 | 18 | #ifndef SHELL_SORT_HPP 19 | #define SHELL_SORT_HPP 20 | 21 | #include 22 | #include "utils.hpp" 23 | 24 | using std::vector; 25 | 26 | void shell_sort(vector& values, const int order = 1, const bool to_show_state = false) { 27 | size_t size = values.size(); 28 | 29 | // gap sequence is n/2, n/4, n/8, ..., 1 30 | for (size_t gap = size / 2; gap > 0; gap /= 2) { 31 | for (size_t i = gap; i < size; i++) { 32 | int temp = values[i]; 33 | size_t j = i; 34 | while (j >= gap and values[j - gap] * order > temp * order) { 35 | values[j] = values[j - gap]; 36 | j -= gap; 37 | } 38 | values[j] = temp; 39 | 40 | if (to_show_state) { 41 | display_state(values); 42 | } 43 | } 44 | } 45 | } 46 | 47 | #endif // SHELL_SORT_HPP 48 | -------------------------------------------------------------------------------- /cpp/include/algorithm/sorting/utils.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Various utility functions (for input, output etc.) 3 | used in programs that implement sorting algorithms 4 | */ 5 | 6 | #ifndef UTILS_HPP 7 | #define UTILS_HPP 8 | 9 | #include // swap, min, max, reverse 10 | #include // exit 11 | #include 12 | #include 13 | 14 | #define EXIT_INPUT_SIZE_IS_ZERO 2 // exit code for when input size is 0 15 | 16 | using std::cin; 17 | using std::cout; 18 | using std::string; 19 | using std::swap; 20 | using std::vector; 21 | 22 | /* 23 | Input utils 24 | ----------- 25 | get_input_size 26 | get_input_values 27 | get_order 28 | get_whether_to_show_state 29 | */ 30 | 31 | void get_input_size(size_t& size) { 32 | cout << "Enter the input size : "; 33 | cin >> size; 34 | 35 | if ((int) size < 0) { 36 | cout << "Invalid input size! Try again.\n"; 37 | get_input_size(size); 38 | } else if (size == 0) { 39 | cout << "Nothing to sort here.\n"; 40 | exit(EXIT_INPUT_SIZE_IS_ZERO); 41 | } 42 | } 43 | 44 | void get_input_values(vector& values, const size_t& size) { 45 | cout << "\nEnter " << size << " integers :\n"; 46 | for (int& val: values) 47 | cin >> val; 48 | cin.ignore(); 49 | } 50 | 51 | void get_order(int& order, string& orderText ) { 52 | cout << "\nSorting order?\n"; 53 | cout << "[A]scending / [d]escending : "; 54 | getline(cin, orderText); 55 | 56 | if (orderText[0] == 'd' or orderText[0] == 'D') { 57 | order = -1; 58 | orderText = "descending"; 59 | } else { // ascending order by default 60 | order = 1; 61 | orderText = "ascending"; 62 | } 63 | } 64 | 65 | void get_whether_to_show_state(bool& toShowState) { 66 | string answer; 67 | cout << "\nShow state of values after each iteration?\n"; 68 | cout << "[y]es / [N]o : "; 69 | getline(cin, answer); 70 | 71 | toShowState = false; // by default, don't show state 72 | if (answer[0] == 'y' or answer[0] == 'Y') // unless user asks for it 73 | toShowState = true; 74 | } 75 | 76 | /* 77 | Output utils 78 | ------------ 79 | display_state 80 | */ 81 | 82 | void display_state(const vector& values) { 83 | for (const int& val: values) 84 | cout << val << ' '; 85 | cout << '\n'; 86 | } 87 | 88 | #endif // UTILS_HPP 89 | -------------------------------------------------------------------------------- /cpp/include/algorithm/string/edit_distance.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Edit distance 3 | ------------- 4 | This algorithm finds the minimum number of edits which are required 5 | to convert string1 to string2. Edit here means either insert, remove 6 | or replace. The algorithm implemented here uses dynamic programming. 7 | 8 | Time complexity 9 | --------------- 10 | O(M*N), where M and N are the lengths of the two strings. 11 | 12 | Space complexity 13 | ---------------- 14 | O(M*N), where M and N are the lengths of the two strings. 15 | */ 16 | 17 | #ifndef EDIT_DISTANCE_HPP 18 | #define EDIT_DISTANCE_HPP 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | /* 26 | get_edit_distance 27 | ----------------- 28 | This function takes arguments as two strings : str1,str2 . Then it finds 29 | the minimum number of edits required to change str1 to str2. 30 | */ 31 | 32 | int get_edit_distance (std::string str1, std::string str2) { 33 | int length1 = str1.length(); //length of str1 34 | int length2 = str2.length(); //length of str2 35 | std::vector> dp (length1 + 1, std::vector (length2 + 1)); 36 | int temp = 0; 37 | 38 | for (int i = 0; i <= length1; i++) { 39 | for (int j = 0; j <= length2; j++) { 40 | if (i == 0) { // str1 is empty 41 | dp[i][j] = j; // insert all characters of str2 42 | } 43 | else if (j == 0) { // str2 is empty 44 | dp[i][j] = i; // remove all characters of str1 45 | } 46 | else if (str1[i-1] == str2[j-1]) { // the last characters are same 47 | dp[i][j] = dp[i-1][j-1]; // ignore it and recur for remaining string 48 | } 49 | else { 50 | // check for minimum when last character is different. 51 | // operations are: insert, remove and replace 52 | if (dp[i-1][j] < dp[i][j-1]) { 53 | temp = dp[i-1][j]; 54 | } 55 | else { 56 | temp = dp[i][j-1]; 57 | } 58 | if (dp[i-1][j-1] < temp) { 59 | dp[i][j] = 1 + dp[i-1][j-1]; 60 | } 61 | else { 62 | dp[i][j] = 1 + temp ; 63 | } 64 | } 65 | } 66 | } 67 | 68 | return dp[length1][length2]; // the edit distance 69 | } 70 | 71 | #endif // EDIT_DISTANCE_HPP 72 | -------------------------------------------------------------------------------- /cpp/include/algorithm/string/heaps_algorithm.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Heap's Algorithm 3 | ---------------- 4 | 5 | This algorithm generates all possible permutations of a collection of n elements. 6 | The algorithm minimizes movement: it generates each permutation from the previous 7 | one by interchanging a single pair of elements, while the other n-2 remain undisturbed. 8 | 9 | Time Complexity 10 | --------------- 11 | O(N!), where N is the number of elements in the collection 12 | 13 | Space Complexity 14 | ---------------- 15 | O(N), where N is the number of elements in the collection 16 | 17 | */ 18 | 19 | #ifndef HEAPS_ALGORITHM_HPP 20 | #define HEAPS_ALGORITHM_HPP 21 | 22 | #include 23 | 24 | using std::string; 25 | using std::vector; 26 | using std::swap; 27 | 28 | vector heaps_algorithm(unsigned int number_of_elements, string& collection, vector& permutations) { 29 | 30 | if (number_of_elements == 1 || collection.empty()) { 31 | permutations.push_back(collection); 32 | } 33 | 34 | else { 35 | 36 | /* Generate permutations with i-th element unaltered 37 | * Initially number_of_elements == length of input string */ 38 | heaps_algorithm(number_of_elements - 1, collection, permutations); 39 | 40 | /* Generate permutations where the i-th element is swapped 41 | * with each i-1 initial elements */ 42 | for (unsigned int i = 0; i < number_of_elements - 1; i++) { 43 | 44 | /* The swap choice depends on the parity of 45 | * number_of_elements within each recursive call */ 46 | if (number_of_elements % 2 == 0) { 47 | swap(collection[i], collection[number_of_elements - 1]); // zero-indexed, the i-th is at i-1 48 | 49 | } else { 50 | swap(collection[0], collection[number_of_elements - 1]); 51 | } 52 | 53 | /* This second recursive call exists to avoid additional swaps at each level 54 | * The algorithm would work without it, but wouldn't be the way B.R. Heap designed it */ 55 | heaps_algorithm(number_of_elements - 1, collection, permutations); 56 | } 57 | } 58 | return permutations; 59 | } 60 | 61 | #endif //HEAPS_ALGORITHM_HPP 62 | -------------------------------------------------------------------------------- /cpp/include/algorithm/string/knuth_morris_pratt.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Knuth-Morris-Pratt (KMP) algorithm 3 | ---------------------------------- 4 | A string searching algorithm that searches for a given "pattern" in a "text". 5 | It uses the fact that when a mismatch occurs, one can jump further in the text 6 | than a naive algorithm would (i.e. 1 step). The KMP algorithm can jump up to 7 | all the length of the search pattern. 8 | 9 | Time complexity 10 | --------------- 11 | O(N + M), where N is the pattern size and M is the text size. 12 | 13 | Space complexity 14 | ---------------- 15 | O(N), where N is the pattern size. 16 | */ 17 | 18 | #ifndef KNUTH_MORRIS_PRATT_HPP 19 | #define KNUTH_MORRIS_PRATT_HPP 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | using std::vector; 26 | using std::string; 27 | 28 | 29 | vector preprocess(string pattern) { 30 | // Table of partial matches (to know where to jump in case of a mismatch) 31 | vector table(pattern.length(), -1); 32 | size_t i = 0; 33 | int j = -1; 34 | 35 | // Look for matches 36 | while (i < pattern.length()) { 37 | // Reset j with table if mismatch is found 38 | while (j >= 0 and pattern[i] != pattern[j]) { 39 | j = table[j]; // reset j with the table 40 | } 41 | 42 | i++, j++; // advance both counters when there's a match, or when j is reset 43 | table[i] = j; // set the index to jump to 44 | } 45 | 46 | return table; 47 | } 48 | 49 | vector search(string pattern, string text) { 50 | vector table = preprocess(pattern); // get the table of partial matches 51 | 52 | vector indices(0); // starting indices of text where the complete pattern is found 53 | size_t i = 0; 54 | int j = 0; 55 | 56 | // Iterate over the entire text 57 | while (i < text.length()) { 58 | // Reset j with table if mismatch is found 59 | while (j >= 0 and text[i] != pattern[j]) { 60 | j = table[j]; // reset j with the table 61 | } 62 | 63 | i++, j++; // advance both counters when there's a match, or when j is reset 64 | 65 | if ((size_t) j == pattern.length()) { // when the complete pattern is found, 66 | indices.push_back(i - j); // save the starting index, and 67 | j = table[j]; // jump to the next index of a partial match 68 | } 69 | } 70 | 71 | return indices; 72 | } 73 | 74 | #endif // KNUTH_MORRIS_PRATT_HPP 75 | -------------------------------------------------------------------------------- /cpp/include/algorithm/string/longest_common_subsequence.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Longest Common Subsequence Algorithm 3 | ------------------------------------ 4 | Given two strings, find their longest common subsequence. Note 5 | that this differs from the longest common subsequence algorithm: 6 | unlike substrings, subsequences are not required to occupy 7 | consecutive positions within the original sequences. This is a 8 | classic dynamic programming algorithm for string processing. 9 | 10 | Time complexity 11 | ---------------- 12 | O(M*N), where M and N are the lengths of the two strings. 13 | 14 | Space complexity 15 | ---------------- 16 | O(M*N), where M and N are the lengths of the two strings. 17 | */ 18 | 19 | #ifndef LONGEST_COMMON_SUBSEQUENCE_HPP 20 | #define LONGEST_COMMON_SUBSEQUENCE_HPP 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | using std::vector; 27 | using std::string; 28 | using std::max; 29 | 30 | vector> calc_lcs(const string& s1, const string& s2) { 31 | // M+1 by N+1 lengths matrix 32 | vector> lengths(s1.length()+1, vector(s2.length()+1, 0)); 33 | 34 | for (size_t i = 1; i < s1.length() + 1; i++) { 35 | for (size_t j = 1; j < s2.length() + 1; j++) { 36 | // When the characters match, add 1 37 | if (s1[i - 1] == s2[j - 1]) { 38 | lengths[i][j] = lengths[i - 1][j - 1] + 1; 39 | } 40 | // Pick the maximum neighbor 41 | else { 42 | lengths[i][j] = max(lengths[i - 1][j], lengths[i][j - 1]); 43 | } 44 | } 45 | } 46 | 47 | return lengths; 48 | } 49 | 50 | string get_lcs(const string& s1, const string& s2) { 51 | vector> lengths = calc_lcs(s1, s2); 52 | 53 | size_t i = lengths.size() - 1; 54 | size_t j = lengths[0].size() - 1; 55 | 56 | string lcs; 57 | while (i != 0 and j != 0) { 58 | if (s1[i - 1] == s2[j - 1]) { // if there's a match 59 | lcs += s1[i - 1]; // save the character 60 | i--, j--; 61 | } else if (lengths[i - 1][j] > lengths[i][j - 1]) { 62 | i--; // move to the left 63 | } else { 64 | j--; // move to the right 65 | } 66 | } 67 | 68 | return string(lcs.rbegin(), lcs.rend()); // return the reversed string 69 | } 70 | 71 | #endif // LONGEST_COMMON_SUBSEQUENCE_HPP 72 | -------------------------------------------------------------------------------- /cpp/include/algorithm/string/shunting_yard.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Shunting Yard 3 | ---------------------------------------------- 4 | Converting an infix arithmetic string to a post-fix one, A.K.A. Reverse Polish Notation. 5 | This implementation does not implement functions and solely focuses on simple arithmetic of consisting of [-,+,*,/,^] 6 | 7 | Time complexity 8 | --------------- 9 | O(N*M*P) where N is the size of input vector, i.e. equations, 10 | M is the size of the greatest string in the vector, 11 | and P is maximum number of operators in the string 12 | 13 | Space complexity 14 | ---------------- 15 | O(N+P) = O(N) : where N is the size of input vector, i.e. equations, 16 | and P is maximum number of operators in the string, i.e. stack operations. 17 | */ 18 | 19 | #ifndef SHUNTING_YARD_HPP 20 | #define SHUNTING_YARD_HPP 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | using std::string; 30 | 31 | class OperatorOperations { 32 | public: 33 | static std::vector to_reverse_polish(const std::vector &); 34 | 35 | static std::unordered_map operator_precedence; 36 | static std::unordered_map operator_association; 37 | }; 38 | 39 | std::unordered_map OperatorOperations::operator_precedence{{'-', 2}, 40 | {'+', 2}, 41 | {'*', 3}, 42 | {'/', 3}, 43 | {'^', 4}}; 44 | std::unordered_map OperatorOperations::operator_association{{'-', "left"}, 45 | {'+', "left"}, 46 | {'*', "left"}, 47 | {'/', "left"}, 48 | {'^', "right"}}; 49 | 50 | std::vector OperatorOperations::to_reverse_polish(const std::vector &equations) { 51 | string equation; 52 | string temporary_string; 53 | std::vector postfixed_equations; 54 | postfixed_equations.reserve(equations.size()); 55 | std::stack operators; 56 | for (int i = 0; i <= (int) equations.size() - 1; i++) { 57 | equation = equations[i]; 58 | temporary_string = ""; 59 | for (int j = 0; j <= (int) equation.length() - 1; j++) { 60 | if (isalnum(equation[j])) { 61 | temporary_string.push_back(equation[j]); 62 | } else if (isblank(equation[j])) { 63 | // do nothing 64 | } else if (equation[j] != '(' && equation[j] != ')' && 65 | operator_precedence.find(equation[j]) == operator_precedence.end()) { 66 | temporary_string.push_back(equation[j]); 67 | } else { 68 | if (equation[j] == '(') { 69 | operators.push(equation[j]); 70 | } else { 71 | if (equation[j] == ')') { 72 | while (operators.top() != '(') { 73 | temporary_string.push_back(operators.top()); 74 | operators.pop(); 75 | } 76 | operators.pop(); 77 | } else { 78 | if (operators.empty()) { 79 | operators.push(equation[j]); 80 | } else { 81 | while (!operators.empty() && (operators.top() != '(') && 82 | (OperatorOperations::operator_precedence[operators.top()] > 83 | OperatorOperations::operator_precedence[equation[j]] || 84 | (OperatorOperations::operator_precedence[operators.top()] == 85 | OperatorOperations::operator_precedence[equation[j]] && 86 | OperatorOperations::operator_association[operators.top()] == "left"))) { 87 | temporary_string.push_back(operators.top()); 88 | operators.pop(); 89 | } 90 | operators.push(equation[j]); 91 | } 92 | } 93 | } 94 | } 95 | } 96 | while (!operators.empty()) { 97 | temporary_string.push_back(operators.top()); 98 | operators.pop(); 99 | } 100 | postfixed_equations.push_back(temporary_string); 101 | } 102 | return postfixed_equations; 103 | } 104 | 105 | #endif // SHUNTING_YARD_HPP 106 | -------------------------------------------------------------------------------- /cpp/include/data_structure/queue/queue.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Queue 3 | ----- 4 | A data structure which has the First In First Out (FIFO) property i.e. the 5 | first element to be added to the queue is also the first element to be 6 | removed. Elements are added at the back (tail) and removed from the 7 | front (head). Only the top element can be accessed at any given time. Hence, 8 | there is no random access. All member functions have O(1) time complexity. 9 | */ 10 | 11 | #ifndef QUEUE_HPP 12 | #define QUEUE_HPP 13 | 14 | #include "data_structure/linked_list/singly_linked_list.hpp" 15 | 16 | template 17 | class Queue { 18 | private: 19 | size_t size; 20 | Node* head; 21 | Node* tail; 22 | 23 | public: 24 | Queue(); 25 | void push(const T &item); 26 | void pop(); 27 | T top(); 28 | size_t length(); 29 | bool isEmpty(); 30 | }; 31 | 32 | /* 33 | Constructor 34 | ----------- 35 | */ 36 | template 37 | Queue::Queue() : size {0}, head {nullptr}, tail {nullptr} {} 38 | 39 | /* 40 | Adds an item to the end of the queue 41 | */ 42 | template 43 | void Queue::push(const T &item) { 44 | Node* temp = new Node(item, head); 45 | if (tail) 46 | tail->set_next(temp); 47 | tail = temp; 48 | if (!head) 49 | head = tail; 50 | ++size; 51 | } 52 | 53 | /* 54 | Removes an item from the top of the queue 55 | */ 56 | template 57 | void Queue::pop() { 58 | Node* temp = head; 59 | head = temp->get_next(); 60 | temp->set_next(nullptr); 61 | if (!head) 62 | tail = nullptr; 63 | delete temp; 64 | --size; 65 | } 66 | 67 | /* 68 | Returns the top element of the queue 69 | */ 70 | template 71 | T Queue::top() { 72 | return head->get_value(); 73 | } 74 | 75 | /* 76 | Returns the size of the queue 77 | */ 78 | template 79 | size_t Queue::length() { 80 | return size; 81 | } 82 | 83 | /* 84 | Returns true if queue is empty 85 | */ 86 | template 87 | bool Queue::isEmpty() { 88 | return size == 0; 89 | } 90 | 91 | #endif /* QUEUE_HPP */ 92 | -------------------------------------------------------------------------------- /cpp/include/data_structure/set/disjoint_set.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Disjoint-set 3 | ------------ 4 | A disjoint-set data structure (also called a union–find data structure or 5 | merge–find set) keeps track of a set of elements partitioned into a number 6 | of disjoint (non-overlapping) subsets. 7 | */ 8 | 9 | #ifndef DISJOINT_SET_HPP 10 | #define DISJOINT_SET_HPP 11 | 12 | #include 13 | #include 14 | 15 | struct Element { 16 | int parent; 17 | int rank; 18 | }; 19 | 20 | 21 | /* 22 | DisjointSet 23 | ----------- 24 | Class implementing the disjoint-set data structure. 25 | */ 26 | 27 | class DisjointSet { 28 | std::vector set; 29 | 30 | public: 31 | DisjointSet(size_t); 32 | 33 | int find(int); 34 | void join(int, int); 35 | 36 | size_t size() const; 37 | }; 38 | 39 | 40 | /* 41 | Constructor 42 | ----------- 43 | */ 44 | 45 | DisjointSet::DisjointSet(size_t num_nodes) { 46 | set.resize(num_nodes); 47 | 48 | // initially all elements are parents of themselves, with rank 0 49 | for (size_t element = 0; element < set.size(); element++) { 50 | set[element].parent = element; 51 | set[element].rank = 0; 52 | } 53 | } 54 | 55 | 56 | /* 57 | find 58 | ---- 59 | Returns the representative (root) element of the given element, while also 60 | performing path compression - making the representative the parent of all 61 | elements in the "path". 62 | 63 | Time complexity 64 | --------------- 65 | log*(N), where N is the number of elements in the disjoint-set. 66 | 67 | Space complexity 68 | ---------------- 69 | O(1). 70 | */ 71 | 72 | int DisjointSet::find(int x) { 73 | // recursively travel to the representative element while also performing 74 | // path compression 75 | if (set[x].parent != x) 76 | set[x].parent = find(set[x].parent); 77 | 78 | return set[x].parent; 79 | } 80 | 81 | 82 | /* 83 | join 84 | ---- 85 | Joins the subsets to which the given elements belong to, depending on the 86 | rank of their representative elements. 87 | 88 | Time complexity 89 | --------------- 90 | log*(N), where N is the number of elements in the disjoint-set. 91 | 92 | Space complexity 93 | ---------------- 94 | O(1). 95 | */ 96 | 97 | void DisjointSet::join(int x, int y) { 98 | // find the representatives (roots) of the given elements 99 | int x_root = find(x); 100 | int y_root = find(y); 101 | 102 | if (x_root == y_root) // if x and y are already in the same set 103 | return; // nothing to do 104 | 105 | // otherwise, join them depending on their representative's rank 106 | if (set[x_root].rank < set[y_root].rank) // if x's rank is less than y's 107 | set[x_root].parent = y_root; // join x's root to y's 108 | else { // if y's rank is less than (or equal to) x's 109 | set[y_root].parent = x_root; // join y's root to x's 110 | 111 | if (set[x_root].rank == set[y_root].rank) // if the ranks are equal 112 | ++set[x_root].rank; // increase the rank of x's representative 113 | } 114 | } 115 | 116 | 117 | /* 118 | size 119 | ---- 120 | Returns the number of elements in the set. 121 | */ 122 | 123 | size_t DisjointSet::size() const { 124 | return set.size(); 125 | } 126 | 127 | #endif // DISJOINT_SET_HPP 128 | -------------------------------------------------------------------------------- /cpp/include/data_structure/stack/stack.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Stack 3 | ----- 4 | A data structure which has the Last In First Out (LIFO) property. Elements are added 5 | and removed from the top (head). Only the top element can be accessed at any given time. 6 | Hence, there is no random access. All member functions have O(1) time complexity. 7 | */ 8 | 9 | #ifndef STACK_HPP 10 | #define STACK_HPP 11 | 12 | #include "data_structure/linked_list/singly_linked_list.hpp" 13 | 14 | template 15 | class Stack { 16 | private: 17 | size_t size; 18 | Node* head; 19 | 20 | public: 21 | Stack(); 22 | void push(const T &item); 23 | void pop(); 24 | T top(); 25 | size_t length(); 26 | bool isEmpty(); 27 | }; 28 | 29 | /* 30 | Constructor 31 | ----------- 32 | */ 33 | template 34 | Stack::Stack() : size {0}, head {nullptr} {} 35 | 36 | /* 37 | Adds an item to the top of the stack 38 | */ 39 | template 40 | void Stack::push(const T &item) { 41 | Node* temp = new Node(item, head); 42 | head = temp; 43 | ++size; 44 | } 45 | 46 | /* 47 | Removes an item from the top of the stack 48 | */ 49 | template 50 | void Stack::pop() { 51 | Node* temp = head; 52 | head = temp->get_next(); 53 | temp->set_next(nullptr); 54 | delete temp; 55 | --size; 56 | } 57 | 58 | /* 59 | Returns the top element of the stack 60 | */ 61 | template 62 | T Stack::top() { 63 | return head->get_value(); 64 | } 65 | 66 | /* 67 | Returns the size of the stack 68 | */ 69 | template 70 | size_t Stack::length() { 71 | return size; 72 | } 73 | 74 | /* 75 | Returns true if stack is empty 76 | */ 77 | template 78 | bool Stack::isEmpty() { 79 | return size == 0; 80 | } 81 | 82 | #endif /* STACK_HPP */ 83 | -------------------------------------------------------------------------------- /cpp/include/data_structure/tree/README.md: -------------------------------------------------------------------------------- 1 | # Tree 2 | Trees are a group of data structures that are named this way because of how they look when conceptually drawn or because of how the different elements connect to each other. Trees are used to solve a variety of different problems, such as storing data so that it quickly searched for later, allowing prefix sums to be calculated quickly, or to store data in a hierarchical structure. 3 | 4 | ### Contents 5 | 6 | 1. [Fenwick tree](#1-fenwick-tree) 7 | 8 | --- 9 | 10 | ## 1. Fenwick tree 11 | A fenwick tree offers a more equitable tradeoff between updating an array of prefix sums and calculating prefix sums. Both the update operation and the calculate operation are implemented with the time complexity of O(log n). That can be compared to the naive implementation where the calculate operation is O(1), and the update operation is O(n). 12 | 13 | ### Usage 14 | 15 | ```c++ 16 | vector original_array{10, 3, 15, 12, 5}; 17 | 18 | FenwickTree tree(original_array); 19 | 20 | // calculate the sum from index 0 -> 2 21 | tree.calculate_prefix_sum(2) 22 | 23 | // add 3 to the value located at index = 2 24 | tree.update_tree(3, 2); 25 | 26 | // add -3 to the value located at index = 2 27 | tree.update_tree(-3, 2); 28 | ``` 29 | 30 | ### Complexity 31 | Operation | Time | Space 32 | ----------- | ------------ |------------------- 33 | _Update_ | _O(log N)_ | _O(N)_ 34 | _Calculate_ | _O(log N)_ | _O(N)_ 35 | 36 | Where N is the number of elements in the original array. 37 | -------------------------------------------------------------------------------- /cpp/include/data_structure/tree/fenwick_tree.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Fenwick Tree 3 | ------------ 4 | A fenwick tree is conceptually a tree, but it is implemented as a flat array 5 | that allows the quick calculations prefix sums in an array. It accomplishes this by 6 | storing sums according to the binary representations of the indexes. For practical 7 | purposes the fenwick tree is indexed starting at 1. 8 | Below is a more in-depth explanation of how the tree is constructed. 9 | ............................... 10 | start of sum end of sum 11 | (index - 2^r + 1) -> index 12 | ............................... 13 | Where r is the last significant bit of the binary representation of index. 14 | For example: 15 | index = 6, 110 (in binary) 16 | r = 1 17 | (6 - 2^1 + 1) -> 6 18 | 5 -> 6 19 | 20 | So the sum of the value stored a 5 through 6 will be stored at index 6. Now 21 | remember the index is incremented by one from the original array. So at 22 | index = 6, of the fenwick tree, the sum of 4 through 5, of the original array 23 | will be stored. 24 | 25 | This set up allows any prefix sum to be calculated in at most log(n) operations, 26 | where n is the number of elements in the original array. To update the tree 27 | it takes at most log(n) operations as well. 28 | */ 29 | 30 | #ifndef FENWICK_TREE_HPP 31 | #define FENWICK_TREE_HPP 32 | 33 | #include 34 | 35 | using std::vector; 36 | 37 | class FenwickTree { 38 | private: 39 | vector tree; 40 | 41 | int max_index; 42 | 43 | public: 44 | FenwickTree(vector original_array); 45 | 46 | void update_tree(int index, int value); 47 | 48 | int calculate_prefix_sum(int index); 49 | }; 50 | 51 | /* 52 | Constructor 53 | ----------- 54 | This creates the initial fenwick tree out of the original array. It goes 55 | though each element in the array passed to the function and calls the update 56 | function on that value and index. 57 | 58 | Time complexity 59 | --------------- 60 | Average case : O(nlog(n)), where n is the number of elements in the original array 61 | Worst case : O(nlog(n)) 62 | 63 | Space complexity 64 | ---------------- 65 | O(n) 66 | */ 67 | FenwickTree::FenwickTree(vector original_array){ 68 | max_index = original_array.size(); 69 | if (max_index == 0) { 70 | return; 71 | } 72 | tree.insert(tree.begin(), max_index + 1, 0); 73 | 74 | for (int i = 0;i < max_index;i++) { 75 | update_tree(i, original_array[i]); 76 | } 77 | } 78 | 79 | /* 80 | Update tree 81 | ----------- 82 | This function adds a specified int, value, to all the elements in the fenwick 83 | tree such that the prefix sums will still be correct. To start with the index 84 | will be incremented so that it is correct for the fenwick tree. 85 | 86 | Next we enter the while loop where the entered value will be added to the index 87 | entered. The next line updates the index to the next index by using 88 | two's complement and the bitwise AND operator. An example below is included for 89 | a clearer explanation. In brackets is the decimal number and the binary number 90 | is without brackets. 91 | ....................... 92 | index = 0110 (6) 93 | 94 | Calculating the two's complement 95 | -index = 1001 96 | 1 97 | ---- 98 | 1010 99 | so: (index & -index) = (0110 & 1010) = 0010 (2) 100 | 101 | therefore: index += (index & -index) -> index = 6 + 2 = 8 102 | ....................... 103 | 104 | Time complexity 105 | --------------- 106 | Worst case : O(log n), where n is the number of elements in the fenwick tree 107 | 108 | Space complexity 109 | ---------------- 110 | O(n) 111 | */ 112 | void FenwickTree::update_tree(int index, int value){ 113 | if (max_index == 0){ 114 | return; 115 | } 116 | index = index + 1; 117 | 118 | while (index <= max_index) { 119 | tree[index] += value; 120 | index += (index & -index); 121 | } 122 | } 123 | 124 | /* 125 | Calculate prefix sum 126 | -------------------- 127 | This will calculate the prefix sum that would occur at a given index in the 128 | original array. The value for the sum is initialized to 0 and the value for the 129 | index is incremented by one to start off with. In the while loop the value at 130 | the current index is added to the sum, and the index is moved to the next index. 131 | The new index is found in a similar manner to how the new index was found in 132 | the update_tree function except in this function we subtract the result of 133 | (index & -index) instead of adding it to the current index. 134 | 135 | Time complexity 136 | --------------- 137 | Worst case: O(log n), where n is the number of elements in the fenwick tree 138 | 139 | Space complexity 140 | ---------------- 141 | O(n) 142 | */ 143 | int FenwickTree::calculate_prefix_sum(int index){ 144 | if (max_index == 0){ 145 | return 0; 146 | } 147 | int sum = 0; 148 | index = index + 1; 149 | 150 | while (index > 0) { 151 | sum = sum + tree[index]; 152 | 153 | index -= (index & -index); 154 | } 155 | 156 | return sum; 157 | } 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /cpp/scripts/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exit_code=0 4 | 5 | for test in $(ls bin) 6 | do 7 | printf '\n%s:\n' ${test} 8 | time bin/${test} 9 | if [ $? != 0 ] # test failed 10 | then 11 | exit_code=1 12 | fi 13 | done 14 | 15 | exit ${exit_code} 16 | -------------------------------------------------------------------------------- /cpp/test/algorithm/backtracking/n_queens.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/backtracking/n_queens.hpp" 3 | 4 | TEST_CASE("Base cases", "[backtracking][n_queens]") { 5 | // N = 0 (cannot place) 6 | NQueensSolver b0(0); 7 | REQUIRE(b0.can_place_queens() == false); 8 | 9 | // N = 1 (can place) 10 | NQueensSolver b1(1); 11 | REQUIRE(b1.can_place_queens() == true); 12 | REQUIRE(b1.num_solutions() == 1); 13 | Board b1_sln {{true}}; 14 | REQUIRE(b1.get_solution() == b1_sln); 15 | std::vector b1_slns {{{true}}}; 16 | REQUIRE(b1.get_solutions() == b1_slns); 17 | } 18 | 19 | TEST_CASE("Unplaceable cases", "[backtracking][n_queens]") { 20 | // N = 2 21 | NQueensSolver b2(2); 22 | REQUIRE(b2.can_place_queens() == false); 23 | 24 | // N = 3 25 | NQueensSolver b3(3); 26 | REQUIRE(b3.can_place_queens() == false); 27 | } 28 | 29 | TEST_CASE("Placeable cases", "[backtracking][n_queens]") { 30 | // N = 4 31 | NQueensSolver b4(4); 32 | REQUIRE(b4.can_place_queens() == true); 33 | REQUIRE(b4.num_solutions() == 2); 34 | Board b4_sln1 { 35 | {false, true, false, false}, 36 | {false, false, false, true}, 37 | {true, false, false, false}, 38 | {false, false, true, false} 39 | }; 40 | Board b4_sln2 { 41 | {false, false, true, false}, 42 | {true, false, false, false}, 43 | {false, false, false, true}, 44 | {false, true, false, false} 45 | }; 46 | using Catch::Matchers::VectorContains; 47 | REQUIRE_THAT(b4.get_solutions(), VectorContains(b4_sln1)); 48 | REQUIRE_THAT(b4.get_solutions(), VectorContains(b4_sln2)); 49 | 50 | // N = 9 51 | NQueensSolver b9(9); 52 | REQUIRE(b9.can_place_queens() == true); 53 | REQUIRE(b9.num_solutions() == 352); 54 | 55 | // N = 11 56 | NQueensSolver b11(11); 57 | REQUIRE(b11.can_place_queens() == true); 58 | REQUIRE(b11.num_solutions() == 2680); 59 | } 60 | -------------------------------------------------------------------------------- /cpp/test/algorithm/dynamic_programming/0_1_knapsack.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/dynamic_programming/0_1_knapsack.hpp" 3 | using std::vector; 4 | 5 | TEST_CASE("Base Cases", "[knapsack]") { 6 | REQUIRE(knapsack(10, 3, vector({11, 21, 31}), vector({1, 2, 3})) == 0); 7 | } 8 | TEST_CASE("Simple Cases", "[knapsack]") { 9 | REQUIRE(knapsack(50, 3, vector({10, 20, 30}), vector({60, 200, 220})) == 420); 10 | REQUIRE(knapsack(4, 5, vector({1, 2, 3, 2, 2}), vector({8, 4, 0, 5, 3})) == 13); 11 | REQUIRE(knapsack(4, 5, vector({1, 2, 3, 2, 2}), vector({11, 22, 11, 23, 24})) == 47); 12 | } 13 | -------------------------------------------------------------------------------- /cpp/test/algorithm/dynamic_programming/coin_change.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "third_party/catch.hpp" 3 | #include "algorithm/dynamic_programming/coin_change.hpp" 4 | 5 | using std::vector; 6 | 7 | TEST_CASE("Base Cases", "[coin_change]") { 8 | REQUIRE(coin_change(vector({}), 0, 0) == 1); 9 | REQUIRE(coin_change(vector({}), 0, 3) == 0); 10 | REQUIRE(coin_change(vector({1}), 1, 0) == 1); 11 | REQUIRE(coin_change(vector({7}), 1, 7) == 1); 12 | } 13 | 14 | TEST_CASE("Simple Cases", "[coin_change]") { 15 | REQUIRE(coin_change(vector({2,5,3,6}), 4, 10) == 5); 16 | REQUIRE(coin_change(vector({5,25,50}), 3, 1000) == 441); 17 | REQUIRE(coin_change(vector({5,10,25,50}), 4, 3) == 0); 18 | REQUIRE(coin_change(vector({1,14,23,45}), 4, 234) == 239); 19 | REQUIRE(coin_change(vector({1,3,5,7,11,13}), 6, 121) == 30447); 20 | REQUIRE(coin_change(vector({4,5,6}), 3, 7) == 0); 21 | REQUIRE(coin_change(vector({1,1,1}), 3, 123) == 7750); 22 | REQUIRE(coin_change(vector({1,1,2,2,4,4}), 6, 37) == 21032); 23 | REQUIRE(coin_change(vector({4,5,6}), 3, 7) == 0); 24 | REQUIRE(coin_change(vector({2,4,8,16,32,64,128,256,512,1024}), 10, 1000) == 26338428); 25 | } 26 | -------------------------------------------------------------------------------- /cpp/test/algorithm/dynamic_programming/kadane.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/dynamic_programming/kadane.hpp" 3 | 4 | #include 5 | #include 6 | 7 | using std::tuple; 8 | using std::vector; 9 | 10 | TEST_CASE("Base case", "[dynamic_programming][maximum_subarray][kadane]") { 11 | vector a_vector = { 0 }; 12 | tuple a_tuple = make_tuple(0, 0, 0); 13 | REQUIRE(maximum_subarray(a_vector) == a_tuple); 14 | } 15 | 16 | TEST_CASE("Normal cases", "[dynamic_programming][maximum_subarray][kadane]") { 17 | vector a_vector = { 1, 2, 3 }; 18 | tuple a_tuple = make_tuple(6, 0, 2); 19 | REQUIRE(maximum_subarray(a_vector) == a_tuple); 20 | 21 | vector b_vector = { 1, -2, 3 }; 22 | tuple b_tuple = make_tuple(3, 2, 2); 23 | REQUIRE(maximum_subarray(b_vector) == b_tuple); 24 | 25 | vector c_vector = { 0, -1, 12, 14, -32, 11, 17 }; 26 | tuple c_tuple = make_tuple(28, 5, 6); 27 | REQUIRE(maximum_subarray(c_vector) == c_tuple); 28 | 29 | vector d_vector = { 19, 2, 13, -99, -1, 14, 33, 211, -33, 17 }; 30 | tuple d_tuple = make_tuple(258, 5, 7); 31 | REQUIRE(maximum_subarray(d_vector) == d_tuple); 32 | } 33 | 34 | TEST_CASE("Aliased case", "[dynamic_programming][maximum_subarray][kadane][alias]") { 35 | vector a_vector = {1, 2, 3}; 36 | tuple a_tuple = make_tuple(6, 0, 2); 37 | REQUIRE(kadane(a_vector) == a_tuple); 38 | } 39 | -------------------------------------------------------------------------------- /cpp/test/algorithm/dynamic_programming/longest_decreasing_subsequence.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "include/algorithms/dynamic_programming/longest_decreasing_subsequence.hpp" 3 | 4 | using std::vector; 5 | 6 | TEST_CASE("Base cases", "[longest_decreasing_subsequence]") { 7 | REQUIRE(longest_decreasing_subsequence(vector({}) == 0); 8 | REQUIRE(longest_decreasing_subsequence(vector({1}) == 1); 9 | REQUIRE(longest_decreasing_subsequence(vector({11}) == 1); 10 | } 11 | 12 | TEST_CASE("Test cases", "[longest_decreasing_subsequence]") { 13 | REQUIRE(longest_decreasing_subsequence(vector({1,2,3,4,0}) == 2); 14 | REQUIRE(longest_decreasing_subsequence(vector({10,12,11,9,8,5,6,2}) == 7); 15 | REQUIRE(longest_decreasing_subsequence(vector({1,2,3,4,5,6,7,8,9,10}) == 1); 16 | } 17 | -------------------------------------------------------------------------------- /cpp/test/algorithm/dynamic_programming/matrix_chain_multiplication.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/dynamic_programming/matrix_chain_multiplication.hpp" 3 | 4 | 5 | TEST_CASE("Base cases", "[matrix_chain_multiplication]") { 6 | MatrixChainMultiplier chain_multiplier; 7 | 8 | try { 9 | chain_multiplier = MatrixChainMultiplier({1}); 10 | } 11 | catch (const std::invalid_argument& e) { 12 | CHECK(e.what() == std::string("You need to provide at least 4 dimension" 13 | "values, as there need to be atleast 3 matrices.")); 14 | } 15 | 16 | try { 17 | chain_multiplier = MatrixChainMultiplier({20, 30}); 18 | } 19 | catch (const std::invalid_argument& e) { 20 | CHECK(e.what() == std::string("You need to provide at least 4 dimension" 21 | "values, as there need to be atleast 3 matrices.")); 22 | } 23 | 24 | try { 25 | chain_multiplier = MatrixChainMultiplier({10, 20, 30}); 26 | } 27 | catch (const std::invalid_argument& e) { 28 | CHECK(e.what() == std::string("You need to provide at least 4 dimension" 29 | "values, as there need to be atleast 3 matrices.")); 30 | } 31 | 32 | chain_multiplier = MatrixChainMultiplier({1, 2, 3, 4}); 33 | REQUIRE(chain_multiplier.optimal_cost() == 18); 34 | REQUIRE(chain_multiplier.optimal_parenthesization() == "((AB)C)"); 35 | } 36 | 37 | TEST_CASE("Normal cases", "[matrix_chain_multiplication]") { 38 | MatrixChainMultiplier chain_multiplier; 39 | 40 | chain_multiplier = MatrixChainMultiplier({100, 20, 50, 90}); 41 | REQUIRE(chain_multiplier.optimal_cost() == 270000); 42 | REQUIRE(chain_multiplier.optimal_parenthesization() == "(A(BC))"); 43 | 44 | chain_multiplier = MatrixChainMultiplier({40, 30, 20, 10, 30}); 45 | REQUIRE(chain_multiplier.optimal_cost() == 30000); 46 | REQUIRE(chain_multiplier.optimal_parenthesization() == "((A(BC))D)"); 47 | 48 | chain_multiplier = MatrixChainMultiplier({20, 30, 50, 70, 40, 30, 100, 30, 55, 20}); 49 | REQUIRE(chain_multiplier.optimal_cost() == 333000); 50 | REQUIRE(chain_multiplier.optimal_parenthesization() == "(A(B(C(D(E((FG)(HI)))))))"); 51 | 52 | chain_multiplier = MatrixChainMultiplier({30, 35, 15, 5, 10, 20, 25}); 53 | REQUIRE(chain_multiplier.optimal_cost() == 15125); 54 | REQUIRE(chain_multiplier.optimal_parenthesization() == "((A(BC))((DE)F))"); 55 | } 56 | -------------------------------------------------------------------------------- /cpp/test/algorithm/dynamic_programming/rod_cutting.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/dynamic_programming/rod_cutting.hpp" 3 | 4 | TEST_CASE("Base cases", "[rod_cutting]") { 5 | REQUIRE(rod_cutting( { 20 } ) == 20); 6 | REQUIRE(rod_cutting( { 2, 3 } ) == 4); 7 | REQUIRE(rod_cutting( { 1, 2, 3, 4, 10 } ) == 10); 8 | } 9 | 10 | TEST_CASE("Simple cases", "[rod_cutting]") { 11 | REQUIRE(rod_cutting( { 1, 5, 8, 9, 10, 17, 17, 20 } ) == 22); 12 | REQUIRE(rod_cutting( { 3, 5, 8, 9, 10, 17, 17, 20 } ) == 24); 13 | } 14 | 15 | TEST_CASE("Large cases", "[rod_cutting]") { 16 | REQUIRE(rod_cutting( { 72, 92, 88, 7, 27, 37, 6, 6, 9, 43, 4, 45, 58, 43, 44, 69, 69, 17 | 5, 51, 49, 71, 26, 26, 34, 91, 61, 95, 68, 60, 62, 17, 90, 63, 5, 13, 52, 51, 56, 18 | 92, 18, 53, 59, 18, 75, 44, 52, 71, 3, 50, 2 } ) == 3600); 19 | REQUIRE(rod_cutting( { 1, 45, 59, 94, 24, 42, 71, 20, 46, 55, 6, 81, 95, 79, 21, 73, 20 | 7, 63, 2, 87, 36, 38, 4, 4, 6, 81, 97, 53, 97, 68, 88, 78, 24, 7, 4, 22, 73, 88, 21 | 71, 3, 34, 44, 31, 79, 54, 82, 55, 7, 56, 50 } ) == 1173); 22 | REQUIRE(rod_cutting( { 97, 76, 69, 52, 13, 67, 22, 30, 44, 29, 7, 35, 2, 15, 13, 59, 23 | 86, 95, 47, 44, 66, 58, 45, 93, 49, 94, 100, 74, 9, 72, 59, 19, 46, 64, 98, 25, 24 | 25, 87, 66, 6, 53, 92, 4, 18, 93, 35, 62, 32, 68, 19 } ) == 4850); 25 | } 26 | -------------------------------------------------------------------------------- /cpp/test/algorithm/dynamic_programming/weighted_activity_selection.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/dynamic_programming/weighted_activity_selection.hpp" 3 | 4 | TEST_CASE("Base cases", "[weighted_activity]") { 5 | REQUIRE(weighted_activity( { 1 }, { 2 }, { 3 } ) == 3); 6 | REQUIRE(weighted_activity( { 1 }, { 1 }, { 4 } ) == 4); 7 | REQUIRE(weighted_activity( { 1, 3 }, { 3, 5 }, { 1, 2 } ) == 3); 8 | REQUIRE(weighted_activity( { 1, 3 }, { 4, 5 }, { 4, 5 } ) == 5); 9 | REQUIRE(weighted_activity( { 1, 3 }, { 4, 5 }, { 5, 4 } ) == 5); 10 | } 11 | 12 | TEST_CASE("Medium cases", "[weighted_activity]") { 13 | REQUIRE(weighted_activity( { 1, 3, 6, 2}, 14 | { 2, 5, 19, 100 }, 15 | { 50, 20, 100, 200 } ) == 250); 16 | REQUIRE(weighted_activity( { 5, 3, 10, 8, 3, 8, 8, 8, 10, 10 }, 17 | { 6, 5, 11, 9, 9, 9,10, 9, 11, 11 }, 18 | { 10, 4, 10, 5, 8, 5, 4, 3, 2, 1 } ) == 29); 19 | REQUIRE(weighted_activity( { 70, 92, 100, 53, 72, 42, 6 }, 20 | { 212, 202, 252, 151, 351, 241, 277 }, 21 | { 177, 122, 313, 17, 396, 197, 403 } ) == 403); 22 | REQUIRE(weighted_activity( { 186, 33, 109, 99, 133, 96, 188, 40, 60, 42, 199, 194 }, 23 | { 307, 128, 297, 395, 384, 186, 264, 151, 264, 288, 389, 338 }, 24 | { 378, 70, 470, 16, 463, 24, 341, 444, 367, 366, 227, 195 } ) == 822); 25 | } 26 | -------------------------------------------------------------------------------- /cpp/test/algorithm/number_theory/binomial_coefficient.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/number_theory/binomial_coefficient.hpp" 3 | 4 | TEST_CASE("Base cases", "[binomial_coefficient]") { 5 | REQUIRE(binomial_coefficient(0, 0) == 1); 6 | REQUIRE(binomial_coefficient(0, 1) == 0); 7 | REQUIRE(binomial_coefficient(1, 0) == 1); 8 | REQUIRE(binomial_coefficient(1, 1) == 1); 9 | 10 | REQUIRE(binomial_coefficient(0, 729) == 0); 11 | REQUIRE(binomial_coefficient(729, 0) == 1); 12 | REQUIRE(binomial_coefficient(729, 729) == 1); 13 | REQUIRE(binomial_coefficient(729, 1234567) == 0); 14 | } 15 | 16 | TEST_CASE("Normal cases", "[binomial_coefficient]") { 17 | REQUIRE(binomial_coefficient(10, 2) == 45); 18 | REQUIRE(binomial_coefficient(40, 20) == 137846528820L); 19 | REQUIRE(binomial_coefficient(50, 35) == 2250829575120L); 20 | REQUIRE(binomial_coefficient(100, 97) == 161700); 21 | REQUIRE(binomial_coefficient(200, 10) == 22451004309013280UL); 22 | } 23 | 24 | TEST_CASE("Overflow cases", "[binomial_coefficient]") { 25 | REQUIRE(binomial_coefficient(100, 50) == 1184508333840160104UL); 26 | REQUIRE(binomial_coefficient(128, 70) == 14909021253410748352UL); 27 | } 28 | -------------------------------------------------------------------------------- /cpp/test/algorithm/number_theory/extended_euclidean.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/number_theory/extended_euclidean.hpp" 3 | 4 | TEST_CASE("Base cases", "[number_theory][extended_euclidean]") { 5 | std::array a {{1, 0}}; 6 | REQUIRE(extended_euclidean(0, 0) == a); 7 | std::array b {{1, 0}}; 8 | REQUIRE(extended_euclidean(1, 0) == b); 9 | std::array c {{0, 1}}; 10 | REQUIRE(extended_euclidean(0, 1) == c); 11 | std::array d {{0, 1}}; 12 | REQUIRE(extended_euclidean(1, 1) == d); 13 | } 14 | 15 | TEST_CASE("Positive cases", "[number_theory][extended_euclidean]") { 16 | std::array a {{1, -1}}; 17 | REQUIRE(extended_euclidean(180, 150) == a); 18 | std::array b {{-28, 3}}; 19 | REQUIRE(extended_euclidean(16, 150) == b); 20 | std::array c {{11, -6}}; 21 | REQUIRE(extended_euclidean(17, 31) == c); 22 | std::array d {{-91, 27}}; 23 | REQUIRE(extended_euclidean(170, 573) == d); 24 | } 25 | 26 | TEST_CASE("Negative cases", "[number_theory][extended_euclidean]") { 27 | std::array a {{15, 1}}; 28 | REQUIRE(extended_euclidean(-3, 44) == a); 29 | std::array b {{71, 5}}; 30 | REQUIRE(extended_euclidean(14, -199) == b); 31 | std::array c {{-7, 17}}; 32 | REQUIRE(extended_euclidean(-441, -182) == c); 33 | } 34 | -------------------------------------------------------------------------------- /cpp/test/algorithm/number_theory/fast_exponentiation.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/number_theory/fast_exponentiation.hpp" 3 | 4 | TEST_CASE("Base cases", "[fast_exp]") { 5 | // fast_exp(0, 0) is undefined 6 | REQUIRE(fast_exp(0, 1) == 0); 7 | REQUIRE(fast_exp(1, 0) == 1); 8 | REQUIRE(fast_exp(1, 1) == 1); 9 | } 10 | 11 | TEST_CASE("Normal cases", "[fast_exp]") { 12 | REQUIRE(fast_exp(2, 2) == 4); 13 | REQUIRE(fast_exp(2, 4) == 16); 14 | REQUIRE(fast_exp(3, 4) == 81); 15 | REQUIRE(fast_exp(6, 7) == 279936); 16 | REQUIRE(fast_exp(7, 9) == 40353607); 17 | REQUIRE(fast_exp(27, 8) == 282429536481); 18 | REQUIRE(fast_exp(15, 10) == 576650390625); 19 | REQUIRE(fast_exp(1543, 5) == 8746405945515943U); 20 | 21 | } 22 | 23 | TEST_CASE("Automatic modulo cases", "[fast_exp]") { 24 | REQUIRE(fast_exp(10, 99) == 22673271); 25 | REQUIRE(fast_exp(2, 100) == 976371285); 26 | REQUIRE(fast_exp(256, 128) == 812734592); 27 | REQUIRE(fast_exp(1366, 768) == 85977610); 28 | } 29 | -------------------------------------------------------------------------------- /cpp/test/algorithm/number_theory/fibonacci.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/number_theory/fibonacci.hpp" 3 | 4 | TEST_CASE("Base cases", "[fibonacci]") { 5 | REQUIRE(fibonacci(0) == 0); 6 | REQUIRE(fibonacci(1) == 1); 7 | } 8 | 9 | TEST_CASE("Normal cases", "[fibonacci]") { 10 | REQUIRE(fibonacci(2) == 1); 11 | REQUIRE(fibonacci(7) == 13); 12 | REQUIRE(fibonacci(15) == 610); 13 | REQUIRE(fibonacci(18) == 2584); 14 | REQUIRE(fibonacci(23) == 28657); 15 | REQUIRE(fibonacci(50) == 12586269025); 16 | REQUIRE(fibonacci(93) == 12200160415121876738U); 17 | } 18 | 19 | TEST_CASE("Overflow cases", "[fibonacci]") { 20 | REQUIRE(fibonacci(94) == -1); 21 | REQUIRE(fibonacci(1500) == -1); 22 | } -------------------------------------------------------------------------------- /cpp/test/algorithm/number_theory/fibonacci_efficient.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/number_theory/fibonacci_efficient.hpp" 3 | 4 | TEST_CASE("Base cases", "[fibonacci]") { 5 | REQUIRE(fibonacci(0) == 0); 6 | REQUIRE(fibonacci(1) == 1); 7 | } 8 | 9 | TEST_CASE("Normal cases", "[fibonacci]") { 10 | REQUIRE(fibonacci(2) == 1); 11 | REQUIRE(fibonacci(7) == 13); 12 | REQUIRE(fibonacci(15) == 610); 13 | REQUIRE(fibonacci(18) == 2584); 14 | REQUIRE(fibonacci(23) == 28657); 15 | REQUIRE(fibonacci(50) == 12586269025); 16 | REQUIRE(fibonacci(93) == 12200160415121876738U); 17 | } 18 | 19 | TEST_CASE("Overflow cases", "[fibonacci]") { 20 | REQUIRE(fibonacci(94) == -1); 21 | REQUIRE(fibonacci(1500) == -1); 22 | } 23 | -------------------------------------------------------------------------------- /cpp/test/algorithm/number_theory/greatest_common_divisor.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/number_theory/greatest_common_divisor.hpp" 3 | 4 | TEST_CASE("Base cases", "[number_theory][greatest_common_divisor]") { 5 | REQUIRE(greatest_common_divisor(0, 1) == 1); 6 | REQUIRE(greatest_common_divisor(1, 0) == 1); 7 | REQUIRE(greatest_common_divisor(0, 3) == 3); 8 | REQUIRE(greatest_common_divisor(3, 0) == 3); 9 | } 10 | 11 | TEST_CASE("Prime cases", "[number_theory][greatest_common_divisor]") { 12 | REQUIRE(greatest_common_divisor(2, 17) == 1); 13 | REQUIRE(greatest_common_divisor(6, 53) == 1); 14 | REQUIRE(greatest_common_divisor(11, 4) == 1); 15 | REQUIRE(greatest_common_divisor(107, 18) == 1); 16 | } 17 | 18 | TEST_CASE("Positive cases", "[number_theory][greatest_common_divisor]") { 19 | REQUIRE(greatest_common_divisor(2, 5) == 1); 20 | REQUIRE(greatest_common_divisor(3, 6) == 3); 21 | REQUIRE(greatest_common_divisor(14, 21) == 7); 22 | REQUIRE(greatest_common_divisor(122, 256) == 2); 23 | REQUIRE(greatest_common_divisor(1448, 20932) == 4); 24 | } 25 | 26 | TEST_CASE("Negative cases", "[number_theory][greatest_common_divisor]") { 27 | REQUIRE(greatest_common_divisor(-2, 6) == 2); 28 | REQUIRE(greatest_common_divisor(-30, -69) == 3); 29 | REQUIRE(greatest_common_divisor(36, -144) == 36); 30 | } 31 | -------------------------------------------------------------------------------- /cpp/test/algorithm/number_theory/perfect_number_check.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/number_theory/perfect_number_check.hpp" 3 | 4 | TEST_CASE("Normal cases"){ 5 | REQUIRE(is_perfect(1) == true); 6 | REQUIRE(is_perfect(2) == false); 7 | REQUIRE(is_perfect(6) == true); 8 | REQUIRE(is_perfect(28) == true); 9 | REQUIRE(is_perfect(49) == false); 10 | REQUIRE(is_perfect(495) == false); 11 | REQUIRE(is_perfect(496) == true); 12 | REQUIRE(is_perfect(8128) == true); 13 | } 14 | -------------------------------------------------------------------------------- /cpp/test/algorithm/number_theory/primorial.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/number_theory/primorial.hpp" 3 | 4 | TEST_CASE("Base cases", "[primorial]") { 5 | // primorial 6 | REQUIRE(primorial(0) == 1); 7 | REQUIRE(primorial(1) == 2); 8 | REQUIRE(primorial(2) == 6); 9 | 10 | // primorial_natural 11 | REQUIRE(primorial_natural(0) == 1); 12 | REQUIRE(primorial_natural(1) == 1); 13 | REQUIRE(primorial_natural(2) == 2); 14 | } 15 | 16 | TEST_CASE("Edge cases", "[primorial]") { 17 | // primorial 18 | // MAX_N = 15 19 | REQUIRE(primorial(MAX_N) == 614889782588491410); 20 | REQUIRE(primorial(MAX_N + 1) == 0); 21 | REQUIRE(primorial(UINT_MAX) == 0); 22 | 23 | // primorial_natural 24 | // MAX_N_NATURAL = 52 25 | REQUIRE(primorial_natural(MAX_N_NATURAL) == 614889782588491410); 26 | REQUIRE(primorial_natural(MAX_N_NATURAL + 1) == 0); 27 | REQUIRE(primorial_natural(UINT_MAX) == 0); 28 | } 29 | 30 | TEST_CASE("Normal cases", "[primorial]") { 31 | // primorial 32 | REQUIRE(primorial(4) == 210); 33 | REQUIRE(primorial(11) == 200560490130); 34 | REQUIRE(primorial(14) == 13082761331670030); 35 | 36 | // primorial_natural 37 | REQUIRE(primorial_natural(9) == 210); 38 | REQUIRE(primorial_natural(19) == 9699690); 39 | REQUIRE(primorial_natural(46) == 13082761331670030); 40 | } 41 | -------------------------------------------------------------------------------- /cpp/test/algorithm/number_theory/sieve_of_eratosthenes.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/number_theory/sieve_of_eratosthenes.hpp" 3 | 4 | TEST_CASE("Base cases", "[number_theory][sieve_of_eratosthenes]") { 5 | REQUIRE(getPrimes(0) == vector({})); // empty vector 6 | REQUIRE(getPrimes(1) == vector({})); // empty vector 7 | } 8 | 9 | TEST_CASE("Normal cases", "[number_theory][sieve_of_eratosthenes]") { 10 | REQUIRE(getPrimes(2) == vector({2})); 11 | REQUIRE(getPrimes(10) == vector({2,3,5,7})); 12 | REQUIRE(getPrimes(17) == vector({2,3,5,7,11,13,17})); 13 | vector primes_under_10000({ 14 | 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149, 15 | 151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307, 16 | 311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467, 17 | 479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653, 18 | 659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853, 19 | 857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997,1009,1013,1019,1021,1031, 20 | 1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187, 21 | 1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327, 22 | 1361,1367,1373,1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499, 23 | 1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619,1621,1627,1637,1657,1663, 24 | 1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801,1811,1823,1831,1847, 25 | 1861,1867,1871,1873,1877,1879,1889,1901,1907,1913,1931,1933,1949,1951,1973,1979,1987,1993,1997,1999,2003,2011, 26 | 2017,2027,2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153,2161,2179, 27 | 2203,2207,2213,2221,2237,2239,2243,2251,2267,2269,2273,2281,2287,2293,2297,2309,2311,2333,2339,2341,2347,2351, 28 | 2357,2371,2377,2381,2383,2389,2393,2399,2411,2417,2423,2437,2441,2447,2459,2467,2473,2477,2503,2521,2531,2539, 29 | 2543,2549,2551,2557,2579,2591,2593,2609,2617,2621,2633,2647,2657,2659,2663,2671,2677,2683,2687,2689,2693,2699, 30 | 2707,2711,2713,2719,2729,2731,2741,2749,2753,2767,2777,2789,2791,2797,2801,2803,2819,2833,2837,2843,2851,2857, 31 | 2861,2879,2887,2897,2903,2909,2917,2927,2939,2953,2957,2963,2969,2971,2999,3001,3011,3019,3023,3037,3041,3049, 32 | 3061,3067,3079,3083,3089,3109,3119,3121,3137,3163,3167,3169,3181,3187,3191,3203,3209,3217,3221,3229,3251,3253, 33 | 3257,3259,3271,3299,3301,3307,3313,3319,3323,3329,3331,3343,3347,3359,3361,3371,3373,3389,3391,3407,3413,3433, 34 | 3449,3457,3461,3463,3467,3469,3491,3499,3511,3517,3527,3529,3533,3539,3541,3547,3557,3559,3571,3581,3583,3593, 35 | 3607,3613,3617,3623,3631,3637,3643,3659,3671,3673,3677,3691,3697,3701,3709,3719,3727,3733,3739,3761,3767,3769, 36 | 3779,3793,3797,3803,3821,3823,3833,3847,3851,3853,3863,3877,3881,3889,3907,3911,3917,3919,3923,3929,3931,3943, 37 | 3947,3967,3989,4001,4003,4007,4013,4019,4021,4027,4049,4051,4057,4073,4079,4091,4093,4099,4111,4127,4129,4133, 38 | 4139,4153,4157,4159,4177,4201,4211,4217,4219,4229,4231,4241,4243,4253,4259,4261,4271,4273,4283,4289,4297,4327, 39 | 4337,4339,4349,4357,4363,4373,4391,4397,4409,4421,4423,4441,4447,4451,4457,4463,4481,4483,4493,4507,4513,4517, 40 | 4519,4523,4547,4549,4561,4567,4583,4591,4597,4603,4621,4637,4639,4643,4649,4651,4657,4663,4673,4679,4691,4703, 41 | 4721,4723,4729,4733,4751,4759,4783,4787,4789,4793,4799,4801,4813,4817,4831,4861,4871,4877,4889,4903,4909,4919, 42 | 4931,4933,4937,4943,4951,4957,4967,4969,4973,4987,4993,4999,5003,5009,5011,5021,5023,5039,5051,5059,5077,5081, 43 | 5087,5099,5101,5107,5113,5119,5147,5153,5167,5171,5179,5189,5197,5209,5227,5231,5233,5237,5261,5273,5279,5281, 44 | 5297,5303,5309,5323,5333,5347,5351,5381,5387,5393,5399,5407,5413,5417,5419,5431,5437,5441,5443,5449,5471,5477, 45 | 5479,5483,5501,5503,5507,5519,5521,5527,5531,5557,5563,5569,5573,5581,5591,5623,5639,5641,5647,5651,5653,5657, 46 | 5659,5669,5683,5689,5693,5701,5711,5717,5737,5741,5743,5749,5779,5783,5791,5801,5807,5813,5821,5827,5839,5843, 47 | 5849,5851,5857,5861,5867,5869,5879,5881,5897,5903,5923,5927,5939,5953,5981,5987,6007,6011,6029,6037,6043,6047, 48 | 6053,6067,6073,6079,6089,6091,6101,6113,6121,6131,6133,6143,6151,6163,6173,6197,6199,6203,6211,6217,6221,6229, 49 | 6247,6257,6263,6269,6271,6277,6287,6299,6301,6311,6317,6323,6329,6337,6343,6353,6359,6361,6367,6373,6379,6389, 50 | 6397,6421,6427,6449,6451,6469,6473,6481,6491,6521,6529,6547,6551,6553,6563,6569,6571,6577,6581,6599,6607,6619, 51 | 6637,6653,6659,6661,6673,6679,6689,6691,6701,6703,6709,6719,6733,6737,6761,6763,6779,6781,6791,6793,6803,6823, 52 | 6827,6829,6833,6841,6857,6863,6869,6871,6883,6899,6907,6911,6917,6947,6949,6959,6961,6967,6971,6977,6983,6991, 53 | 6997,7001,7013,7019,7027,7039,7043,7057,7069,7079,7103,7109,7121,7127,7129,7151,7159,7177,7187,7193,7207,7211, 54 | 7213,7219,7229,7237,7243,7247,7253,7283,7297,7307,7309,7321,7331,7333,7349,7351,7369,7393,7411,7417,7433,7451, 55 | 7457,7459,7477,7481,7487,7489,7499,7507,7517,7523,7529,7537,7541,7547,7549,7559,7561,7573,7577,7583,7589,7591, 56 | 7603,7607,7621,7639,7643,7649,7669,7673,7681,7687,7691,7699,7703,7717,7723,7727,7741,7753,7757,7759,7789,7793, 57 | 7817,7823,7829,7841,7853,7867,7873,7877,7879,7883,7901,7907,7919,7927,7933,7937,7949,7951,7963,7993,8009,8011, 58 | 8017,8039,8053,8059,8069,8081,8087,8089,8093,8101,8111,8117,8123,8147,8161,8167,8171,8179,8191,8209,8219,8221, 59 | 8231,8233,8237,8243,8263,8269,8273,8287,8291,8293,8297,8311,8317,8329,8353,8363,8369,8377,8387,8389,8419,8423, 60 | 8429,8431,8443,8447,8461,8467,8501,8513,8521,8527,8537,8539,8543,8563,8573,8581,8597,8599,8609,8623,8627,8629, 61 | 8641,8647,8663,8669,8677,8681,8689,8693,8699,8707,8713,8719,8731,8737,8741,8747,8753,8761,8779,8783,8803,8807, 62 | 8819,8821,8831,8837,8839,8849,8861,8863,8867,8887,8893,8923,8929,8933,8941,8951,8963,8969,8971,8999,9001,9007, 63 | 9011,9013,9029,9041,9043,9049,9059,9067,9091,9103,9109,9127,9133,9137,9151,9157,9161,9173,9181,9187,9199,9203, 64 | 9209,9221,9227,9239,9241,9257,9277,9281,9283,9293,9311,9319,9323,9337,9341,9343,9349,9371,9377,9391,9397,9403, 65 | 9413,9419,9421,9431,9433,9437,9439,9461,9463,9467,9473,9479,9491,9497,9511,9521,9533,9539,9547,9551,9587,9601, 66 | 9613,9619,9623,9629,9631,9643,9649,9661,9677,9679,9689,9697,9719,9721,9733,9739,9743,9749,9767,9769,9781,9787, 67 | 9791,9803,9811,9817,9829,9833,9839,9851,9857,9859,9871,9883,9887,9901,9907,9923,9929,9931,9941,9949,9967,9973 68 | }); 69 | REQUIRE(getPrimes(10000) == primes_under_10000); 70 | } 71 | -------------------------------------------------------------------------------- /cpp/test/algorithm/searching/binary_search.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/searching/binary_search.hpp" 3 | 4 | using std::vector; 5 | using std::string; 6 | 7 | TEST_CASE("Base cases", "[searching][binary_search]") { 8 | REQUIRE(binary_search(0, vector()) == -1); 9 | REQUIRE(binary_search(1, vector({1})) == 0); 10 | REQUIRE(binary_search(5, vector({0})) == -1); 11 | } 12 | 13 | TEST_CASE("Integer cases", "[searching][binary_search]") { 14 | REQUIRE(binary_search(33, vector({-5, 2, 7, 25, 33, 77, 88, 102})) == 4); 15 | REQUIRE(binary_search(-99, vector({-99, -88, -53, -3, -1})) == 0); 16 | REQUIRE(binary_search(25, vector({1, 6, 8, 13, 17, 21, 25})) == 6); 17 | REQUIRE(binary_search(4, vector({0, 5, 9, 44, 67})) == -1); 18 | } 19 | 20 | TEST_CASE("Mixed cases", "[searching][binary_search]") { 21 | REQUIRE(binary_search('d', vector({'a', 'b', 'c', 'd', 'e'})) == 3); 22 | REQUIRE(binary_search(string("2"), vector({"1", "2", "3", "4", "5"})) == 1); 23 | REQUIRE(binary_search(2.8, vector({0.1, 0.15, 0.3, 1.1, 2.3, 2.8, 3.14})) == 5); 24 | } 25 | -------------------------------------------------------------------------------- /cpp/test/algorithm/searching/linear_search.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/searching/linear_search.hpp" 3 | 4 | using std::vector; 5 | using std::string; 6 | 7 | TEST_CASE("Base cases", "[searching][linear_search]") { 8 | REQUIRE(linear_search(0, vector()) == -1); 9 | REQUIRE(linear_search(1, vector({1})) == 0); 10 | REQUIRE(linear_search(5, vector({0})) == -1); 11 | } 12 | 13 | TEST_CASE("Integer cases", "[searching][linear_search]") { 14 | REQUIRE(linear_search(5, vector({0, -5, 25, 8, 5, 2, 6, 3})) == 4); 15 | REQUIRE(linear_search(-15, vector({9, -15, 0, 3, 5})) == 1); 16 | REQUIRE(linear_search(0, vector({1, 29, 6, 8, 5, 2, 0})) == 6); 17 | REQUIRE(linear_search(-0, vector({0, -5, 25, 8, 5, 2, 6, 3})) == 0); 18 | REQUIRE(linear_search(0, vector({1, 29, 6, 8, 5, 2})) == -1); 19 | } 20 | 21 | 22 | TEST_CASE("Mixed cases", "[searching][linear_search]") { 23 | REQUIRE(linear_search('a', vector({'1', 'f', 'A', 'X', 'a'})) == 4); 24 | REQUIRE(linear_search(string("/"), vector({"1", "/", "*", "-", "0"})) == 1); 25 | REQUIRE(linear_search(1.25, vector({0.0, 6.15, 0.3, 1.25, 4})) == 3); 26 | } 27 | -------------------------------------------------------------------------------- /cpp/test/algorithm/searching/ternary_search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "third_party/catch.hpp" 4 | #include "algorithm/searching/ternary_search.hpp" 5 | 6 | using std::vector; 7 | 8 | /* 9 | TODO: refactor 10 | */ 11 | 12 | unsigned int cur = 0; 13 | unsigned int a = 13674324, b = 1233; 14 | 15 | unsigned int nextRand24() { 16 | cur = cur * a + b; 17 | return cur >> 8; 18 | } 19 | 20 | vector nextRandUnimodal(int size, const bool pattern) { 21 | vector res; 22 | res.clear(); 23 | int prev = nextRand24() % 1000; 24 | if (!pattern) prev *= -1; 25 | res.push_back(prev); 26 | int md; 27 | bool was = false; 28 | if (!pattern) md = 1; else md = -1; 29 | for (int i = 0; i < size; i++) { 30 | int del = (nextRand24() % 15) * md; 31 | prev += del; 32 | res.push_back(prev); 33 | if (i > size / 2 + (int)nextRand24() % 15 && !was) { 34 | md *= -1; 35 | was = true; 36 | } 37 | } 38 | return res; 39 | } 40 | 41 | size_t get_expected_index(const vector& values, const bool pattern) { 42 | int val; 43 | size_t expected_index = 0; 44 | if (!pattern) { 45 | val = std::numeric_limits::min(); 46 | for (size_t i = 0; i < values.size(); i++) { 47 | if (val < values[i]){ 48 | val = values[i]; 49 | expected_index = i; 50 | } 51 | } 52 | } else { 53 | val = std::numeric_limits::max(); 54 | for (size_t i = 0; i < values.size(); i++) { 55 | if (val > values[i]){ 56 | val = values[i]; 57 | expected_index = i; 58 | } 59 | } 60 | } 61 | return expected_index; 62 | } 63 | 64 | 65 | int ascending_descending_func_int(int x) { 66 | return -(x - 2) * (x - 2); 67 | } 68 | 69 | int descending_ascending_func_int(int x) { 70 | return (x - 5) * (x - 5) * (x - 5) * (x - 5); 71 | } 72 | 73 | float ascending_descending_func_float(float x) { 74 | return -(x - 9.0f) * (x - 9.0f); 75 | } 76 | 77 | float descending_ascending_func_float(float x) { 78 | return (x - 0.5f) * (x - 0.5f) * (x - 0.5f) * (x - 0.5f); 79 | } 80 | 81 | TEST_CASE("Base cases", "[searching][ternary_search]") { 82 | REQUIRE(ternary_search(vector({5}), ASCEND_THEN_DESCEND) == 0); 83 | REQUIRE(ternary_search(vector({5}), DESCEND_THEN_ASCEND) == 0); 84 | REQUIRE(ternary_search(vector({-5}), ASCEND_THEN_DESCEND) == 0); 85 | REQUIRE(ternary_search(vector({-5}), DESCEND_THEN_ASCEND) == 0); 86 | 87 | REQUIRE(ternary_search(vector({4, 5}), ASCEND_THEN_DESCEND) == 1); 88 | REQUIRE(ternary_search(vector({4, 5}), DESCEND_THEN_ASCEND) == 0); 89 | 90 | // Testing ternary search for integer range and ascending then descending functions 91 | REQUIRE(ternary_search(&ascending_descending_func_int, 2, 2, ASCEND_THEN_DESCEND) == 2); 92 | REQUIRE(ternary_search(&ascending_descending_func_int, 2, 3, ASCEND_THEN_DESCEND) == 2); 93 | REQUIRE(ternary_search([](int x){return -(x - 2) * (x - 2);}, 1, 2, ASCEND_THEN_DESCEND) == 2); 94 | REQUIRE(ternary_search([](int x){return -(x - 2) * (x - 2);}, -4, -3, ASCEND_THEN_DESCEND) == -3); 95 | 96 | // Testing ternary search for integer range and descending then ascending functions 97 | REQUIRE(ternary_search(&descending_ascending_func_int, 5, 5, DESCEND_THEN_ASCEND) == 5); 98 | REQUIRE(ternary_search(&descending_ascending_func_int, 5, 6, DESCEND_THEN_ASCEND) == 5); 99 | REQUIRE(ternary_search([](int x){return (x - 5) * (x - 5) * (x - 5) * (x - 5);}, 4, 5, DESCEND_THEN_ASCEND) == 5); 100 | REQUIRE(ternary_search([](int x){return (x - 5) * (x - 5) * (x - 5) * (x - 5);}, 12, 13, DESCEND_THEN_ASCEND) == 12); 101 | 102 | // Testing ternary search for float range and ascending then descending functions 103 | REQUIRE(ternary_search(&ascending_descending_func_float, 9.0, 9.0, ASCEND_THEN_DESCEND, 10e-9) == Approx(9.0)); 104 | REQUIRE(ternary_search(&ascending_descending_func_float, 8.0, 9.0, ASCEND_THEN_DESCEND, 10e-9) == Approx(9.0)); 105 | REQUIRE(ternary_search([](float x){return -(x - 9.0f) * (x - 9.0f);}, 9.0, 10.0, ASCEND_THEN_DESCEND, 10e-9) == Approx(9.0)); 106 | REQUIRE(ternary_search([](float x){return -(x - 9.0f) * (x - 9.0f);}, -4.0, -3.0, ASCEND_THEN_DESCEND, 10e-9) == Approx(-3.0)); 107 | 108 | // Testing ternary search for float range and descending then ascending functions 109 | REQUIRE(ternary_search(&descending_ascending_func_float, 0.5, 0.5, DESCEND_THEN_ASCEND, 10e-9) == Approx(0.5)); 110 | REQUIRE(ternary_search(&descending_ascending_func_float, 0.4, 0.5, DESCEND_THEN_ASCEND, 10e-9) == Approx(0.5)); 111 | REQUIRE(ternary_search([](float x){return (x - 0.5f) * (x - 0.5f) * (x - 0.5f) * (x - 0.5f);}, 0.5, 0.6, DESCEND_THEN_ASCEND, 10e-9) == Approx(0.5)); 112 | REQUIRE(ternary_search([](float x){return (x - 0.5f) * (x - 0.5f) * (x - 0.5f) * (x - 0.5f);}, 2.2, 2.3, DESCEND_THEN_ASCEND, 10e-9) == Approx(2.2)); 113 | } 114 | 115 | TEST_CASE("Normal cases", "[searching][ternary_search]") { 116 | vector values; 117 | Pattern pattern; 118 | size_t expected_index; 119 | for (int test = 0; test < 20; test++) { 120 | if (bool(nextRand24() % 2)) { 121 | pattern = DESCEND_THEN_ASCEND; 122 | } 123 | else { 124 | pattern = ASCEND_THEN_DESCEND; 125 | } 126 | values = nextRandUnimodal(nextRand24() % 1000, pattern); 127 | expected_index = get_expected_index(values, pattern); 128 | REQUIRE(ternary_search(values, pattern) == expected_index); 129 | } 130 | 131 | REQUIRE(ternary_search([](int x){return -(x - 150) * (x - 150);}, 0, 400, ASCEND_THEN_DESCEND) == 150); 132 | REQUIRE(ternary_search([](float x){return (x + 351) * (x + 351);}, -1250, 5689, DESCEND_THEN_ASCEND) == -351); 133 | 134 | REQUIRE(ternary_search([](double d){return sin(d);}, 0.0, M_PI, ASCEND_THEN_DESCEND, 10e-9) == Approx(M_PI_2)); 135 | REQUIRE(ternary_search([](double d){return cos(d);}, 0.0, 2.0 * M_PI, DESCEND_THEN_ASCEND, 10e-9) == Approx(M_PI)); 136 | REQUIRE(ternary_search([](double d){return tan(d);}, -M_PI/4, M_PI/4, ASCEND_THEN_DESCEND, 10e-9) == Approx(M_PI/4)); 137 | 138 | REQUIRE(ternary_search([](float d){return (d <= -2.1f) ? d * 5.5f :-16.2f - d * 2.5f;}, -4509.0f, 240.878f, ASCEND_THEN_DESCEND, 10e-9f) == Approx(-2.1f)); 139 | REQUIRE(ternary_search([](float d){return (d <= 3.2f) ? - d * 3.0f :-13.44f + d * 1.2f;}, -25.2f, 240.3f, DESCEND_THEN_ASCEND, 10e-9f) == Approx(3.2f)); 140 | } 141 | -------------------------------------------------------------------------------- /cpp/test/algorithm/sorting/sorting.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "third_party/catch.hpp" 4 | #include "algorithm/sorting/bubble_sort.hpp" 5 | #include "algorithm/sorting/bucket_sort.hpp" 6 | #include "algorithm/sorting/comb_sort.hpp" 7 | #include "algorithm/sorting/counting_sort.hpp" 8 | #include "algorithm/sorting/heap_sort.hpp" 9 | #include "algorithm/sorting/insertion_sort.hpp" 10 | #include "algorithm/sorting/merge_sort.hpp" 11 | #include "algorithm/sorting/quick_sort.hpp" 12 | #include "algorithm/sorting/radix_sort.hpp" 13 | #include "algorithm/sorting/selection_sort.hpp" 14 | #include "algorithm/sorting/shell_sort.hpp" 15 | 16 | // Prototypes 17 | int generate_random_int(int, int); 18 | vector generate_unsorted_vector(int max_size = 1000); 19 | 20 | // Pointer to function 21 | using sorting_function = void(*)(vector&, int, bool); 22 | 23 | // Constant value 24 | const int TIMES_TO_RUN = 20; 25 | 26 | TEST_CASE("Sort in ascending order", "[sorting]") { 27 | // Sorting algorithms 28 | vector sorting_functions = { 29 | bubble_sort, 30 | bucket_sort, 31 | comb_sort, 32 | counting_sort, 33 | heap_sort, 34 | insertion_sort, 35 | merge_sort, 36 | quick_sort, 37 | // radix_sort, // This test reveals that the radix sort is broken 38 | selection_sort, 39 | shell_sort 40 | }; 41 | 42 | vector original, algo_sorted, std_sorted; 43 | 44 | int times_to_run = TIMES_TO_RUN; 45 | while (times_to_run--) { 46 | original = algo_sorted = std_sorted = generate_unsorted_vector(); 47 | std::sort(std_sorted.begin(), std_sorted.end()); 48 | 49 | // Run tests 50 | for (auto sorting_algo : sorting_functions) { 51 | sorting_algo(algo_sorted, 1, false); 52 | REQUIRE(algo_sorted == std_sorted); 53 | algo_sorted = original; 54 | } 55 | } 56 | } 57 | 58 | TEST_CASE("Sort in descending order", "[sorting]") { 59 | // Sorting algorithms 60 | vector sorting_functions = { 61 | bubble_sort, 62 | bucket_sort, 63 | comb_sort, 64 | counting_sort, 65 | heap_sort, 66 | insertion_sort, 67 | merge_sort, 68 | quick_sort, 69 | // radix_sort, // This test reveals that the radix sort is broken 70 | selection_sort, 71 | shell_sort 72 | }; 73 | 74 | vector original, algo_sorted, std_sorted; 75 | 76 | int times_to_run = TIMES_TO_RUN; 77 | while (times_to_run--) { 78 | original = algo_sorted = std_sorted = generate_unsorted_vector(); 79 | std::sort(std_sorted.rbegin(), std_sorted.rend()); 80 | 81 | // Run tests 82 | for (auto sorting_algo : sorting_functions) { 83 | sorting_algo(algo_sorted, -1, false); 84 | REQUIRE(algo_sorted == std_sorted); 85 | algo_sorted = original; 86 | } 87 | } 88 | } 89 | 90 | /* 91 | generate_unsorted_vector 92 | ------------------------ 93 | Creates a vector of random size and populates it with random integers. 94 | Default for max_size is set in function declaration. 95 | */ 96 | vector generate_unsorted_vector(int max_size) { 97 | vector v; 98 | auto vector_size = (size_t) generate_random_int(1, max_size); 99 | v.reserve(vector_size); 100 | 101 | for (int i = 0; i < (int) vector_size; i++) { 102 | v.push_back(generate_random_int(std::numeric_limits::min(), std::numeric_limits::max())); 103 | } 104 | return v; 105 | } 106 | 107 | /* 108 | generate_random_int 109 | ------------------- 110 | Generates a random int between min and max. 111 | */ 112 | int generate_random_int(int min, int max) { 113 | std::default_random_engine generator(std::random_device{}()); 114 | std::uniform_int_distribution<> int_range(min, max); 115 | return int_range(generator); 116 | } 117 | -------------------------------------------------------------------------------- /cpp/test/algorithm/string/edit_distance.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/string/edit_distance.hpp" 3 | 4 | TEST_CASE("Base cases", "[string][edit_distance]"){ 5 | REQUIRE(get_edit_distance("sunday", "") == 6); 6 | REQUIRE(get_edit_distance("", "sunday") == 6); 7 | REQUIRE(get_edit_distance("", "") == 0); 8 | } 9 | 10 | TEST_CASE("Normal cases", "[string][edit_distance]"){ 11 | REQUIRE(get_edit_distance("sunday", "saturday") == 3); 12 | REQUIRE(get_edit_distance("food", "money") == 4); 13 | REQUIRE(get_edit_distance("code", "code") == 0); 14 | REQUIRE(get_edit_distance("plot", "plotting") == 4); 15 | } 16 | 17 | TEST_CASE("Large cases", "[string][edit_distance]"){ 18 | REQUIRE(get_edit_distance("aaaaaaaaaaaaaaaaaaaaaaaXaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaXaaaaaaaaaaaaaaaaXaaaaaaaaaaaaaaaaaaaaXaaaaaaX") == 3); 19 | REQUIRE(get_edit_distance("abc*efghijklm---nopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLM+++NOPQRSTU*WXYZ") == 8); 20 | } 21 | -------------------------------------------------------------------------------- /cpp/test/algorithm/string/heaps_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "third_party/catch.hpp" 3 | #include "algorithm/string/heaps_algorithm.hpp" 4 | 5 | 6 | TEST_CASE("Base cases", "[string][heaps_algorithm]") { 7 | vector output_1; 8 | string s = ""; // empty string 9 | vector permutations = {""}; 10 | REQUIRE(heaps_algorithm(s.length(), s, output_1) == permutations); 11 | 12 | vector output_2; 13 | s = "a"; 14 | permutations = {"a"}; 15 | REQUIRE(heaps_algorithm(s.length(), s, output_2) == permutations); 16 | 17 | vector output_3; 18 | s = " "; 19 | permutations = {" "}; 20 | REQUIRE(heaps_algorithm(s.length(), s, output_3) == permutations); 21 | } 22 | 23 | 24 | TEST_CASE("short cases", "[string][heaps_algorithm]") { 25 | vector output_4; 26 | string s = "abc"; 27 | vector permutations = {"abc", "bac", "cab", "acb", "bca", "cba"}; 28 | REQUIRE(heaps_algorithm(s.length(), s, output_4) == permutations); 29 | 30 | vector output_5; 31 | s = "a$1"; 32 | permutations = {"a$1", "$a1", "1a$", "a1$", "$1a", "1$a"}; 33 | REQUIRE(heaps_algorithm(s.length(), s, output_5) == permutations); 34 | } 35 | 36 | TEST_CASE("long cases", "[string][heaps_algorithm]") { 37 | vector output_6; 38 | string s = "1_#c"; 39 | vector permutations = {"1_#c", "_1#c", "#1_c", "1#_c", "_#1c", 40 | "#_1c", "c_1#", "_c1#", "1c_#", "c1_#", 41 | "_1c#", "1_c#", "1#c_", "#1c_", "c1#_", 42 | "1c#_", "#c1_", "c#1_", "c#_1", "#c_1", 43 | "_c#1", "c_#1", "#_c1", "_#c1"}; 44 | 45 | REQUIRE(heaps_algorithm(s.length(), s, output_6) == permutations); 46 | 47 | vector output_7; 48 | s = "algos"; 49 | permutations = {"algos", "lagos", "galos", "aglos", "lgaos", 50 | "glaos", "olags", "loags", "aolgs", "oalgs", 51 | "laogs", "alogs", "agols", "gaols", "oagls", 52 | "aogls", "goals", "ogals", "oglas", "golas", 53 | "logas", "olgas", "gloas", "lgoas", "sgoal", 54 | "gsoal", "osgal", "sogal", "gosal", "ogsal", 55 | "agsol", "gasol", "sagol", "asgol", "gsaol", 56 | "sgaol", "soagl", "osagl", "asogl", "saogl", 57 | "oasgl", "aosgl", "aogsl", "oagsl", "gaosl", 58 | "agosl", "ogasl", "goasl", "loasg", "olasg", 59 | "alosg", "laosg", "oalsg", "aolsg", "solag", 60 | "oslag", "lsoag", "sloag", "olsag", "losag", 61 | "lasog", "alsog", "slaog", "lsaog", "aslog", 62 | "salog", "saolg", "asolg", "osalg", "soalg", 63 | "aoslg", "oaslg", "gaslo", "agslo", "sgalo", 64 | "gsalo", "asglo", "saglo", "lagso", "algso", 65 | "glaso", "lgaso", "aglso", "galso", "gslao", 66 | "sglao", "lgsao", "glsao", "slgao", "lsgao", 67 | "lsago", "slago", "alsgo", "lasgo", "salgo", 68 | "aslgo", "oslga", "solga", "losga", "olsga", 69 | "sloga", "lsoga", "gsola", "sgola", "ogsla", 70 | "gosla", "sogla", "osgla", "olgsa", "logsa", 71 | "golsa", "oglsa", "lgosa", "glosa", "glsoa", 72 | "lgsoa", "sgloa", "gsloa", "lsgoa", "slgoa"}; 73 | 74 | REQUIRE(heaps_algorithm(s.length(), s, output_7) == permutations); 75 | } 76 | -------------------------------------------------------------------------------- /cpp/test/algorithm/string/knuth_morris_pratt.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/string/knuth_morris_pratt.hpp" 3 | 4 | TEST_CASE("Base cases", "[string][knuth_morris_pratt]") { 5 | vector a = { }; 6 | REQUIRE(search("", "") == a); 7 | vector b = { 0 }; 8 | REQUIRE(search("a", "a") == b); 9 | vector c = { 0 }; 10 | REQUIRE(search("1", "1") == c); 11 | } 12 | 13 | TEST_CASE("Single cases", "[string][knuth_morris_pratt]") { 14 | vector a = { 0 }; 15 | REQUIRE(search("Sun", "Sunday") == a); 16 | vector b = { 4 }; 17 | REQUIRE(search("horse", "Wildhorse") == b); 18 | vector c = { 6 }; 19 | REQUIRE(search("you", "Won't you be my neighbor?") == c); 20 | vector d = { 7 }; 21 | REQUIRE(search("g", "Lady Gaga") == d); 22 | } 23 | 24 | TEST_CASE("Multiple cases", "[string][knuth_morris_pratt]") { 25 | vector a = {4, 9}; 26 | REQUIRE(search("a", "Michael Jackson") == a); 27 | vector b = {1, 5}; 28 | REQUIRE(search("u", "autobus") == b); 29 | vector c = {0, 7}; 30 | REQUIRE(search("sn", "snickersnee") == c); 31 | } 32 | -------------------------------------------------------------------------------- /cpp/test/algorithm/string/longest_common_subsequence.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "algorithm/string/longest_common_subsequence.hpp" 3 | 4 | TEST_CASE("Base cases", "[string][longest_common_subsequence]"){ 5 | REQUIRE(get_lcs("sunday", "") == ""); 6 | REQUIRE(get_lcs("", "sunday") == ""); 7 | REQUIRE(get_lcs("", "") == ""); 8 | } 9 | 10 | TEST_CASE("Lower alphabetical cases", "[string][longest_common_subsequence]"){ 11 | REQUIRE(get_lcs("cats", "dogs") == "s"); 12 | REQUIRE(get_lcs("cats", "ctss") == "cts"); 13 | REQUIRE(get_lcs("cats", "cross") == "cs"); 14 | } 15 | 16 | TEST_CASE("Upper alphabetical cases", "[string][longest_common_subsequence]"){ 17 | REQUIRE(get_lcs("CATS", "DOGS") == "S"); 18 | REQUIRE(get_lcs("CATS", "CTSS") == "CTS"); 19 | REQUIRE(get_lcs("CATS", "CROSS") == "CS"); 20 | } 21 | 22 | TEST_CASE("Mixed alphabetical cases", "[string][longest_common_subsequence]"){ 23 | REQUIRE(get_lcs("caTS", "dogs") == ""); 24 | REQUIRE(get_lcs("cAts", "catss") == "cts"); 25 | REQUIRE(get_lcs("cats", "CROsS") == "s"); 26 | } 27 | 28 | TEST_CASE("Numerical cases", "[string][longest_common_subsequence]"){ 29 | REQUIRE(get_lcs("123456", "136") == "136"); 30 | REQUIRE(get_lcs("111", "123") == "1"); 31 | REQUIRE(get_lcs("2849", "992719") == "29"); 32 | } 33 | 34 | TEST_CASE("Mixed numerical and alphabetical cases", "[string][longest_common_subsequence]"){ 35 | REQUIRE(get_lcs("c344ats", "do4gs") == "4s"); 36 | REQUIRE(get_lcs("cats2937", "2937ctss") == "2937"); 37 | REQUIRE(get_lcs("catsg777g", "cross77") == "cs77"); 38 | } 39 | 40 | TEST_CASE("Random long cases", "[string][longest_common_subsequence]"){ 41 | REQUIRE(get_lcs("189oi3n4oinoi34nuf79b39yb49b973b4f9fb9374bf993nfi293fn28", "guu37hngn83n") == "u37nn8"); 42 | REQUIRE(get_lcs("img82n4f8u939fn93n97h7rgb9737g937rbg9739j9jed98jng82jng", "g38jendungud") == "g38jnng"); 43 | REQUIRE(get_lcs("38jgjsg3j98j8j8hg8hs9f7dhg9d7fhg2r08jgefgnouefgne8282jf8g", "i2ijgh3unvnh") == "2jgun"); 44 | } 45 | 46 | TEST_CASE("Special character cases", "[string][longest_common_subsequence]"){ 47 | REQUIRE(get_lcs("@(&#(@&&@", "@($&%&@(&#") == "@(&&@"); 48 | REQUIRE(get_lcs("@(&#(@&&@", "(%*#(@*&!)") == "(#(@&"); 49 | REQUIRE(get_lcs("@(&#(@&&@", "@(#()*%&#&") == "@(#(&&"); 50 | } 51 | -------------------------------------------------------------------------------- /cpp/test/algorithm/string/shunting_yard.cpp: -------------------------------------------------------------------------------- 1 | #include "algorithm/string/shunting_yard.hpp" 2 | #include "third_party/catch.hpp" 3 | 4 | TEST_CASE("Valid cases", "[string][shunting_yard]") { 5 | OperatorOperations test_operations; 6 | std::vector test_input_vector; 7 | std::vector test_result_vector; 8 | std::vector test_expected_result_vector; 9 | 10 | test_input_vector.emplace_back("3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3"); 11 | test_input_vector.emplace_back("3+4 * 2 /( 1 - 5 ) ^ 2 ^ 3"); 12 | test_input_vector.emplace_back("3 ^ 1 / (5 * 6) + 10"); 13 | test_expected_result_vector.emplace_back("342*15-23^^/+"); 14 | test_expected_result_vector.emplace_back("342*15-23^^/+"); 15 | test_expected_result_vector.emplace_back("31^56*/10+"); 16 | test_result_vector = test_operations.to_reverse_polish(test_input_vector); 17 | REQUIRE(test_expected_result_vector == test_result_vector); 18 | } 19 | 20 | TEST_CASE("Empty cases", "[string][shunting_yard]") { 21 | OperatorOperations test_operations; 22 | std::vector test_input_vector; 23 | std::vector test_result_vector; 24 | std::vector test_expected_result_vector; 25 | 26 | test_input_vector.emplace_back(" "); 27 | test_input_vector.emplace_back(""); 28 | test_expected_result_vector.emplace_back(""); 29 | test_expected_result_vector.emplace_back(""); 30 | test_result_vector = test_operations.to_reverse_polish(test_input_vector); 31 | REQUIRE(test_expected_result_vector == test_result_vector); 32 | } 33 | 34 | TEST_CASE("Invalid cases", "[string][shunting_yard]") { 35 | OperatorOperations test_operations; 36 | std::vector test_input_vector; 37 | std::vector test_result_vector; 38 | std::vector test_expected_result_vector; 39 | 40 | test_input_vector.emplace_back("hello"); 41 | test_input_vector.emplace_back("he2o"); 42 | test_input_vector.emplace_back("hell0"); 43 | test_expected_result_vector.emplace_back("hello"); 44 | test_expected_result_vector.emplace_back("he2o"); 45 | test_expected_result_vector.emplace_back("hell0"); 46 | test_result_vector = test_operations.to_reverse_polish(test_input_vector); 47 | REQUIRE(test_expected_result_vector == test_result_vector); 48 | } 49 | -------------------------------------------------------------------------------- /cpp/test/data_structure/linked_list/doubly_linked_list.cpp: -------------------------------------------------------------------------------- 1 | #include "data_structure/linked_list/doubly_linked_list.hpp" 2 | #include "third_party/catch.hpp" 3 | 4 | TEST_CASE("Verify initial state", "[doubly-linked-list]") { 5 | DoublyLinkedList temp; 6 | 7 | REQUIRE(temp.length() == 0); 8 | } 9 | 10 | TEST_CASE("Adding values in front", "[doubly-linked-list]") { 11 | DoublyLinkedList temp; 12 | 13 | REQUIRE(temp.is_empty()); 14 | REQUIRE(temp.length() == 0); 15 | temp.insert_front(1); 16 | REQUIRE(!temp.is_empty()); 17 | REQUIRE(temp.length() == 1); 18 | temp.insert_front(2); 19 | REQUIRE(temp.length() == 2); 20 | temp.insert_front(3); 21 | REQUIRE(temp.length() == 3); 22 | temp.insert_front(4); 23 | REQUIRE(temp.length() == 4); 24 | temp.insert_front(5); 25 | REQUIRE(!temp.is_empty()); 26 | REQUIRE(temp.length() == 5); 27 | 28 | for (int i = 0; i < temp.length(); i++) { 29 | REQUIRE(temp[i] == 5 - i); 30 | } 31 | } 32 | 33 | TEST_CASE("Removing values from front", "[doubly-linked-list]") { 34 | DoublyLinkedList temp; 35 | 36 | REQUIRE(temp.is_empty()); 37 | REQUIRE(temp.length() == 0); 38 | temp.insert_front(1); 39 | REQUIRE(!temp.is_empty()); 40 | REQUIRE(temp.length() == 1); 41 | temp.insert_front(2); 42 | REQUIRE(temp.length() == 2); 43 | temp.insert_front(3); 44 | REQUIRE(temp.length() == 3); 45 | temp.insert_front(4); 46 | REQUIRE(temp.length() == 4); 47 | temp.insert_front(5); 48 | REQUIRE(!temp.is_empty()); 49 | REQUIRE(temp.length() == 5); 50 | 51 | temp.delete_front(); 52 | REQUIRE(temp.length() == 4); 53 | temp.delete_front(); 54 | REQUIRE(temp.length() == 3); 55 | temp.delete_front(); 56 | REQUIRE(temp.length() == 2); 57 | temp.delete_front(); 58 | REQUIRE(temp.length() == 1); 59 | temp.delete_front(); 60 | REQUIRE(temp.length() == 0); 61 | temp.delete_front(); 62 | REQUIRE(temp.is_empty()); 63 | REQUIRE(temp.length() == 0); 64 | } 65 | 66 | TEST_CASE("Adding values in rear", "[doubly-linked-list]") { 67 | DoublyLinkedList temp; 68 | 69 | REQUIRE(temp.is_empty()); 70 | REQUIRE(temp.length() == 0); 71 | temp.insert_rear(1); 72 | REQUIRE(!temp.is_empty()); 73 | REQUIRE(temp.length() == 1); 74 | temp.insert_rear(2); 75 | REQUIRE(temp.length() == 2); 76 | temp.insert_rear(3); 77 | REQUIRE(temp.length() == 3); 78 | temp.insert_rear(4); 79 | REQUIRE(temp.length() == 4); 80 | temp.insert_rear(5); 81 | REQUIRE(!temp.is_empty()); 82 | REQUIRE(temp.length() == 5); 83 | 84 | for (int i = 0; i < temp.length(); i++) { 85 | REQUIRE(temp[i] == i + 1); 86 | } 87 | } 88 | 89 | TEST_CASE("Reverse linked list", "[doubly-linked-list]") { 90 | DoublyLinkedList list; 91 | 92 | list.insert_rear(37); 93 | list.insert_rear(22); 94 | list.insert_rear(42); 95 | list.insert_rear(15); 96 | list.insert_rear(9); 97 | list.insert_rear(52); 98 | list.insert_rear(77); 99 | list.insert_rear(63); 100 | list.insert_rear(36); 101 | list.insert_rear(48); 102 | list.insert_rear(101); 103 | 104 | list.reverse(); 105 | 106 | // Verify reversed elements 107 | REQUIRE(list[0] == 101); 108 | REQUIRE(list[1] == 48); 109 | REQUIRE(list[2] == 36); 110 | REQUIRE(list[3] == 63); 111 | REQUIRE(list[4] == 77); 112 | REQUIRE(list[5] == 52); 113 | REQUIRE(list[6] == 9); 114 | REQUIRE(list[7] == 15); 115 | REQUIRE(list[8] == 42); 116 | REQUIRE(list[9] == 22); 117 | REQUIRE(list[10] == 37); 118 | 119 | } 120 | 121 | TEST_CASE("Removing values from rear", "[doubly-linked-list]") { 122 | DoublyLinkedList temp; 123 | 124 | REQUIRE(temp.is_empty()); 125 | REQUIRE(temp.length() == 0); 126 | temp.insert_rear(1); 127 | REQUIRE(temp.length() == 1); 128 | temp.insert_rear(2); 129 | REQUIRE(temp.length() == 2); 130 | temp.insert_rear(3); 131 | REQUIRE(temp.length() == 3); 132 | temp.insert_rear(4); 133 | REQUIRE(temp.length() == 4); 134 | temp.insert_rear(5); 135 | REQUIRE(!temp.is_empty()); 136 | REQUIRE(temp.length() == 5); 137 | 138 | temp.delete_rear(); 139 | REQUIRE(temp.length() == 4); 140 | temp.delete_rear(); 141 | REQUIRE(temp.length() == 3); 142 | temp.delete_rear(); 143 | REQUIRE(temp.length() == 2); 144 | temp.delete_rear(); 145 | REQUIRE(temp.length() == 1); 146 | temp.delete_rear(); 147 | REQUIRE(temp.length() == 0); 148 | temp.delete_rear(); 149 | REQUIRE(temp.is_empty()); 150 | REQUIRE(temp.length() == 0); 151 | } 152 | 153 | TEST_CASE("Inserting arbitrary values", "[doubly-linked-list]") { 154 | DoublyLinkedList list; 155 | 156 | REQUIRE(list.is_empty()); 157 | list.insert_rear(-13); 158 | list.insert_rear(157); 159 | list.insert_front(-166); 160 | list.insert_front(43); 161 | 162 | REQUIRE(list.length() == 4); 163 | REQUIRE(list[0] == 43); 164 | REQUIRE(list[1] == -166); 165 | REQUIRE(list[2] == -13); 166 | REQUIRE(list[3] == 157); 167 | } 168 | -------------------------------------------------------------------------------- /cpp/test/data_structure/linked_list/singly_linked_list.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "data_structure/linked_list/singly_linked_list.hpp" 3 | 4 | TEST_CASE("Create an empty linked list", "[singly-linked-list]") { 5 | SinglyLinkedList list; 6 | 7 | // Verify is_empty() 8 | REQUIRE(list.is_empty() == true); 9 | } 10 | 11 | TEST_CASE("Add elements", "[singly-linked-list]") { 12 | SinglyLinkedList list; 13 | 14 | list.insert_rear(27); 15 | list.insert_rear(2); 16 | list.insert_rear(72); 17 | list.insert_rear(681); 18 | list.insert_rear(233); 19 | list.insert_rear(2102); 20 | list.insert_rear(955); 21 | list.insert_rear(552); 22 | list.insert_rear(43); 23 | list.insert_rear(27); 24 | 25 | list.insert_front(29); 26 | list.insert_front(511); 27 | list.insert_front(23); 28 | list.insert_front(281); 29 | list.insert_front(-112); 30 | list.insert_front(251); 31 | list.insert_front(233); 32 | list.insert_front(551); 33 | list.insert_front(6732); 34 | list.insert_front(-722); 35 | 36 | // Verify length() 37 | REQUIRE(list.length() == 20); 38 | 39 | // Verify value_at() 40 | REQUIRE(list.value_at(0) == -722); 41 | REQUIRE(list.value_at(1) == 6732); 42 | REQUIRE(list.value_at(2) == 551); 43 | REQUIRE(list.value_at(3) == 233); 44 | REQUIRE(list.value_at(4) == 251); 45 | REQUIRE(list.value_at(5) == -112); 46 | // ... 47 | REQUIRE(list.value_at(17) == 552); 48 | REQUIRE(list.value_at(18) == 43); 49 | REQUIRE(list.value_at(19) == 27); 50 | 51 | // Verify [] operator 52 | REQUIRE(list[0] == -722); 53 | REQUIRE(list[1] == 6732); 54 | REQUIRE(list[2] == 551); 55 | // ... 56 | REQUIRE(list[14] == 233); 57 | REQUIRE(list[15] == 2102); 58 | REQUIRE(list[16] == 955); 59 | REQUIRE(list[17] == 552); 60 | REQUIRE(list[18] == 43); 61 | REQUIRE(list[19] == 27); 62 | } 63 | 64 | TEST_CASE("Delete elements", "[singly-linked-list]") { 65 | SinglyLinkedList list; 66 | 67 | list.insert_rear(27); 68 | list.insert_rear(2); 69 | list.insert_rear(72); 70 | list.insert_rear(681); 71 | list.insert_rear(233); 72 | list.insert_rear(2102); 73 | list.insert_rear(955); 74 | list.insert_rear(552); 75 | list.insert_rear(43); 76 | list.insert_rear(27); 77 | 78 | list.insert_front(29); 79 | list.insert_front(511); 80 | list.insert_front(23); 81 | list.insert_front(281); 82 | list.insert_front(-112); 83 | list.insert_front(251); 84 | list.insert_front(233); 85 | list.insert_front(551); 86 | list.insert_front(6732); 87 | list.insert_front(-722); 88 | 89 | // Verify length() 90 | REQUIRE(list.length() == 20); 91 | 92 | list.delete_front(); 93 | list.delete_front(); 94 | list.delete_front(); 95 | list.delete_front(); 96 | 97 | // Verify length() 98 | REQUIRE(list.length() == 16); 99 | 100 | // Verify element locations 101 | REQUIRE(list[0] == 251); 102 | REQUIRE(list[1] == -112); 103 | REQUIRE(list[2] == 281); 104 | REQUIRE(list[3] == 23); 105 | // ... 106 | REQUIRE(list[14] == 43); 107 | REQUIRE(list[15] == 27); 108 | 109 | list.delete_rear(); 110 | list.delete_rear(); 111 | list.delete_rear(); 112 | list.delete_rear(); 113 | 114 | // Verify length() 115 | REQUIRE(list.length() == 12); 116 | 117 | // Verify element locations 118 | REQUIRE(list[0] == 251); 119 | REQUIRE(list[1] == -112); 120 | // ... 121 | REQUIRE(list[8] == 72); 122 | REQUIRE(list[9] == 681); 123 | REQUIRE(list[10] == 233); 124 | REQUIRE(list[11] == 2102); 125 | } 126 | 127 | TEST_CASE("Reverse linked list", "[singly-linked-list]") { 128 | SinglyLinkedList list; 129 | 130 | list.insert_rear(37); 131 | list.insert_rear(22); 132 | list.insert_rear(42); 133 | list.insert_rear(15); 134 | list.insert_rear(9); 135 | list.insert_rear(52); 136 | list.insert_rear(77); 137 | list.insert_rear(63); 138 | list.insert_rear(36); 139 | list.insert_rear(48); 140 | list.insert_rear(101); 141 | 142 | list.reverse(); 143 | 144 | // Verify reversed elements 145 | REQUIRE(list[0] == 101); 146 | REQUIRE(list[1] == 48); 147 | REQUIRE(list[2] == 36); 148 | REQUIRE(list[3] == 63); 149 | REQUIRE(list[4] == 77); 150 | REQUIRE(list[5] == 52); 151 | REQUIRE(list[6] == 9); 152 | REQUIRE(list[7] == 15); 153 | REQUIRE(list[8] == 42); 154 | REQUIRE(list[9] == 22); 155 | REQUIRE(list[10] == 37); 156 | 157 | } 158 | 159 | TEST_CASE("Clear list", "[singly-linked-list]") { 160 | SinglyLinkedList list; 161 | 162 | list.insert_rear(27); 163 | list.insert_rear(2); 164 | list.insert_rear(72); 165 | list.insert_rear(681); 166 | list.insert_rear(233); 167 | list.insert_rear(2102); 168 | list.insert_rear(955); 169 | list.insert_rear(552); 170 | list.insert_rear(43); 171 | list.insert_rear(27); 172 | 173 | list.insert_front(29); 174 | list.insert_front(511); 175 | list.insert_front(23); 176 | list.insert_front(281); 177 | list.insert_front(-112); 178 | list.insert_front(251); 179 | list.insert_front(233); 180 | list.insert_front(551); 181 | list.insert_front(6732); 182 | list.insert_front(-722); 183 | 184 | // Verify length() 185 | REQUIRE(list.length() == 20); 186 | 187 | list.clear(); 188 | 189 | // Verify length() 190 | REQUIRE(list.length() == 0); 191 | 192 | // Verify is_empty() 193 | REQUIRE(list.is_empty() == true); 194 | } 195 | -------------------------------------------------------------------------------- /cpp/test/data_structure/queue/queue.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "data_structure/queue/queue.hpp" 3 | 4 | TEST_CASE("Verify initial state", "[queue]") { 5 | // Initialize queue 6 | Queue queue; 7 | 8 | // Verify state 9 | REQUIRE(queue.length() == 0); 10 | REQUIRE(queue.isEmpty() == true); 11 | } 12 | 13 | TEST_CASE("Add elements", "[queue]") { 14 | // Initialize queue 15 | Queue queue; 16 | 17 | // Add items 18 | queue.push(27); 19 | queue.push(2); 20 | queue.push(72); 21 | queue.push(681); 22 | queue.push(233); 23 | queue.push(2102); 24 | queue.push(955); 25 | queue.push(552); 26 | queue.push(43); 27 | queue.push(722); 28 | 29 | // Verify state 30 | REQUIRE(queue.length() == 10); 31 | REQUIRE(queue.isEmpty() == false); 32 | REQUIRE(queue.top() == 27); 33 | } 34 | 35 | TEST_CASE("Delete elements", "[queue]") { 36 | // Initialize queue 37 | Queue queue; 38 | 39 | // Add items 40 | queue.push(27); 41 | queue.push(2); 42 | queue.push(72); 43 | queue.push(681); 44 | queue.push(233); 45 | queue.push(2102); 46 | queue.push(955); 47 | queue.push(552); 48 | queue.push(43); 49 | queue.push(722); 50 | 51 | // Verify state 52 | REQUIRE(queue.length() == 10); 53 | REQUIRE(queue.isEmpty() == false); 54 | REQUIRE(queue.top() == 27); 55 | 56 | // Remove items 57 | queue.pop(); 58 | queue.pop(); 59 | queue.pop(); 60 | queue.pop(); 61 | 62 | // Verify state 63 | REQUIRE(queue.length() == 6); 64 | REQUIRE(queue.top() == 233); 65 | } 66 | 67 | TEST_CASE("Clear list", "[queue]") { 68 | // Initialize queue 69 | Queue queue; 70 | 71 | // Add items 72 | queue.push(27); 73 | queue.push(2); 74 | queue.push(72); 75 | queue.push(681); 76 | queue.push(233); 77 | queue.push(2102); 78 | queue.push(955); 79 | queue.push(552); 80 | queue.push(43); 81 | queue.push(722); 82 | 83 | // Verify state 84 | REQUIRE(queue.length() == 10); 85 | REQUIRE(queue.isEmpty() == false); 86 | REQUIRE(queue.top() == 27); 87 | 88 | // Remove items 89 | queue.pop(); 90 | queue.pop(); 91 | queue.pop(); 92 | queue.pop(); 93 | queue.pop(); 94 | queue.pop(); 95 | queue.pop(); 96 | queue.pop(); 97 | queue.pop(); 98 | queue.pop(); 99 | 100 | // Verify state 101 | REQUIRE(queue.length() == 0); 102 | REQUIRE(queue.isEmpty() == true); 103 | } 104 | 105 | TEST_CASE("Adding and removing values", "[queue]") { 106 | // Initialize state 107 | Queue queue; 108 | 109 | // Verify state after adding items 110 | queue.push(2); 111 | REQUIRE(queue.length() == 1); 112 | REQUIRE(queue.top() == 2); 113 | 114 | // Verify state after adding more items 115 | queue.push(5); 116 | queue.push(7); 117 | REQUIRE(queue.length() == 3); 118 | REQUIRE(queue.top() == 2); 119 | 120 | // Verify state after removing items 121 | queue.pop(); 122 | REQUIRE(queue.length() == 2); 123 | REQUIRE(queue.top() == 5); 124 | 125 | // Verify state after removing more items 126 | queue.pop(); 127 | REQUIRE(queue.length() == 1); 128 | REQUIRE(queue.top() == 7); 129 | 130 | // Verify state after removing remaining item 131 | queue.pop(); 132 | REQUIRE(queue.length() == 0); 133 | REQUIRE(queue.isEmpty() == true); 134 | } 135 | -------------------------------------------------------------------------------- /cpp/test/data_structure/set/disjoint_set.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "data_structure/set/disjoint_set.hpp" 3 | 4 | TEST_CASE("Create a large set containing 10^8 elements", "[disjoint-set]") { 5 | /* 6 | Note: This test requires around 800MB of memory. 7 | */ 8 | DisjointSet ds(1e8); 9 | REQUIRE(ds.size() == 1e8); 10 | } 11 | 12 | TEST_CASE("Check initial state", "[disjoint-set]") { 13 | DisjointSet ds(20); 14 | 15 | for (size_t element = 0; element < ds.size(); element++) { 16 | REQUIRE(ds.find(element) == element); 17 | } 18 | } 19 | 20 | TEST_CASE("Connect elements and verify their representatives", "[disjoint-set]") { 21 | DisjointSet ds(16); // create a disjoint-set with elements from 0 to 15 22 | 23 | ds.join(0, 8); 24 | REQUIRE(ds.find(0) == 0); 25 | REQUIRE(ds.find(8) == 0); 26 | 27 | ds.join(3, 15); 28 | REQUIRE(ds.find(3) == 3); 29 | REQUIRE(ds.find(15) == 3); 30 | 31 | ds.join(10, 5); 32 | REQUIRE(ds.find(10) == 10); 33 | REQUIRE(ds.find(5) == 10); 34 | 35 | SECTION("Connecting the elements the other way shouldn't change things") { 36 | ds.join(8, 0); 37 | REQUIRE(ds.find(0) == 0); 38 | REQUIRE(ds.find(8) == 0); 39 | 40 | ds.join(15, 3); 41 | REQUIRE(ds.find(3) == 3); 42 | REQUIRE(ds.find(15) == 3); 43 | 44 | ds.join(5, 10); 45 | REQUIRE(ds.find(10) == 10); 46 | REQUIRE(ds.find(5) == 10); 47 | } 48 | 49 | // Connect elements directly to representatives 50 | ds.join(0, 9); 51 | REQUIRE(ds.find(9) == 0); 52 | 53 | ds.join(3, 4); 54 | REQUIRE(ds.find(4) == 3); 55 | 56 | ds.join(10, 2); 57 | REQUIRE(ds.find(2) == 10); 58 | 59 | // Connect elements to the ones already connected to some other element 60 | ds.join(1, 9); 61 | REQUIRE(ds.find(1) == 0); 62 | 63 | ds.join(6, 4); 64 | REQUIRE(ds.find(6) == 3); 65 | 66 | ds.join(7, 2); 67 | REQUIRE(ds.find(7) == 10); 68 | 69 | // Connect some more elements 70 | ds.join(11, 12); 71 | ds.join(12, 13); 72 | ds.join(13, 14); 73 | REQUIRE(ds.find(11) == 11); 74 | REQUIRE(ds.find(12) == 11); 75 | REQUIRE(ds.find(13) == 11); 76 | REQUIRE(ds.find(14) == 11); 77 | 78 | // Connect elements belonging to different subsets 79 | ds.join(9, 4); 80 | REQUIRE(ds.find(9) == 0); 81 | REQUIRE(ds.find(4) == 0); 82 | REQUIRE(ds.find(3) == 0); 83 | 84 | ds.join(12, 7); 85 | REQUIRE(ds.find(12) == 11); 86 | REQUIRE(ds.find(7) == 11); 87 | REQUIRE(ds.find(10) == 11); 88 | 89 | ds.join(13, 6); 90 | for (size_t element = 0; element < ds.size(); element++) { 91 | REQUIRE(ds.find(element) == 11); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /cpp/test/data_structure/stack/stack.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "data_structure/stack/stack.hpp" 3 | 4 | TEST_CASE("Verify initial state", "[stack]") { 5 | // Initialize stack 6 | Stack stack; 7 | 8 | // Verify state 9 | REQUIRE(stack.length() == 0); 10 | REQUIRE(stack.isEmpty() == true); 11 | } 12 | 13 | TEST_CASE("Add elements", "[stack]") { 14 | // Initialize stack 15 | Stack stack; 16 | 17 | // Add items 18 | stack.push(27); 19 | stack.push(2); 20 | stack.push(72); 21 | stack.push(681); 22 | stack.push(233); 23 | stack.push(2102); 24 | stack.push(955); 25 | stack.push(552); 26 | stack.push(43); 27 | stack.push(722); 28 | 29 | // Verify state 30 | REQUIRE(stack.length() == 10); 31 | REQUIRE(stack.isEmpty() == false); 32 | REQUIRE(stack.top() == 722); 33 | } 34 | 35 | TEST_CASE("Delete elements", "[stack]") { 36 | // Initialize stack 37 | Stack stack; 38 | 39 | // Add items 40 | stack.push(27); 41 | stack.push(2); 42 | stack.push(72); 43 | stack.push(681); 44 | stack.push(233); 45 | stack.push(2102); 46 | stack.push(955); 47 | stack.push(552); 48 | stack.push(43); 49 | stack.push(722); 50 | 51 | // Verify state 52 | REQUIRE(stack.length() == 10); 53 | REQUIRE(stack.isEmpty() == false); 54 | REQUIRE(stack.top() == 722); 55 | 56 | // Remove items 57 | stack.pop(); 58 | stack.pop(); 59 | stack.pop(); 60 | stack.pop(); 61 | 62 | // Verify state 63 | REQUIRE(stack.length() == 6); 64 | REQUIRE(stack.top() == 2102); 65 | } 66 | 67 | TEST_CASE("Clear list", "[stack]") { 68 | // Initialize stack 69 | Stack stack; 70 | 71 | // Add items 72 | stack.push(27); 73 | stack.push(2); 74 | stack.push(72); 75 | stack.push(681); 76 | stack.push(233); 77 | stack.push(2102); 78 | stack.push(955); 79 | stack.push(552); 80 | stack.push(43); 81 | stack.push(722); 82 | 83 | // Verify state 84 | REQUIRE(stack.length() == 10); 85 | REQUIRE(stack.isEmpty() == false); 86 | REQUIRE(stack.top() == 722); 87 | 88 | // Remove items 89 | stack.pop(); 90 | stack.pop(); 91 | stack.pop(); 92 | stack.pop(); 93 | stack.pop(); 94 | stack.pop(); 95 | stack.pop(); 96 | stack.pop(); 97 | stack.pop(); 98 | stack.pop(); 99 | 100 | // Verify state 101 | REQUIRE(stack.length() == 0); 102 | REQUIRE(stack.isEmpty() == true); 103 | } 104 | 105 | TEST_CASE("Adding and removing values", "[stack]") { 106 | // Initialize state 107 | Stack stack; 108 | 109 | // Verify state after adding items 110 | stack.push(2); 111 | REQUIRE(stack.length() == 1); 112 | REQUIRE(stack.top() == 2); 113 | 114 | // Verify state after adding more items 115 | stack.push(5); 116 | stack.push(7); 117 | REQUIRE(stack.length() == 3); 118 | 119 | // Verify state after removing items 120 | stack.pop(); 121 | REQUIRE(stack.length() == 2); 122 | REQUIRE(stack.top() == 5); 123 | 124 | // Verify state after removing more items 125 | stack.pop(); 126 | REQUIRE(stack.length() == 1); 127 | REQUIRE(stack.top() == 2); 128 | 129 | // Verify state after removing remaining item 130 | stack.pop(); 131 | REQUIRE(stack.length() == 0); 132 | REQUIRE(stack.isEmpty() == true); 133 | } 134 | -------------------------------------------------------------------------------- /cpp/test/data_structure/tree/binary_search_tree.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "data_structure/tree/binary_search_tree.hpp" 3 | 4 | TEST_CASE("Create an empty search tree", "[binary-search-tree]") { 5 | BinarySearchTree tree; 6 | 7 | // Verify empty vectors 8 | REQUIRE(tree.traversal_inorder_recursive() == vector({})); 9 | REQUIRE(tree.traversal_inorder_iterative() == vector({})); 10 | REQUIRE(tree.traversal_preorder_recursive() == vector({})); 11 | REQUIRE(tree.traversal_preorder_iterative() == vector({})); 12 | REQUIRE(tree.traversal_postorder_recursive() == vector({})); 13 | REQUIRE(tree.traversal_postorder_iterative() == vector({})); 14 | } 15 | 16 | TEST_CASE("Add and remove values", "[binary-search-tree]") { 17 | BinarySearchTree tree; 18 | 19 | tree.insert(1); 20 | tree.insert(2); 21 | tree.insert(-22); 22 | tree.insert(0); 23 | tree.insert(211); 24 | tree.insert(28); 25 | tree.insert(94); 26 | tree.insert(-55); 27 | tree.insert(39); 28 | tree.insert(92); 29 | tree.insert(-122); 30 | tree.insert(20); 31 | tree.insert(298); 32 | tree.insert(91); 33 | tree.insert(77); 34 | tree.insert(-54); 35 | tree.insert(21); 36 | tree.insert(42); 37 | tree.insert(23); 38 | tree.insert(109); 39 | 40 | // Verify search() and insert() 41 | REQUIRE(tree.search(1) == true); 42 | REQUIRE(tree.search(2) == true); 43 | REQUIRE(tree.search(-22) == true); 44 | REQUIRE(tree.search(0) == true); 45 | REQUIRE(tree.search(211) == true); 46 | REQUIRE(tree.search(28) == true); 47 | REQUIRE(tree.search(94) == true); 48 | REQUIRE(tree.search(-55) == true); 49 | REQUIRE(tree.search(39) == true); 50 | REQUIRE(tree.search(92) == true); 51 | REQUIRE(tree.search(-122) == true); 52 | REQUIRE(tree.search(20) == true); 53 | REQUIRE(tree.search(298) == true); 54 | REQUIRE(tree.search(91) == true); 55 | REQUIRE(tree.search(77) == true); 56 | REQUIRE(tree.search(-54) == true); 57 | REQUIRE(tree.search(42) == true); 58 | REQUIRE(tree.search(23) == true); 59 | REQUIRE(tree.search(109) == true); 60 | 61 | REQUIRE(tree.search(-285) == false); 62 | REQUIRE(tree.search(19) == false); 63 | REQUIRE(tree.search(97) == false); 64 | REQUIRE(tree.search(93) == false); 65 | REQUIRE(tree.search(-381) == false); 66 | 67 | tree.remove(39); 68 | tree.remove(92); 69 | tree.remove(298); 70 | tree.remove(1); 71 | tree.remove(2); 72 | 73 | // Verify search() and remove() 74 | REQUIRE(tree.search(39) == false); 75 | REQUIRE(tree.search(92) == false); 76 | REQUIRE(tree.search(298) == false); 77 | REQUIRE(tree.search(1) == false); 78 | REQUIRE(tree.search(2) == false); 79 | 80 | REQUIRE(tree.search(77) == true); 81 | REQUIRE(tree.search(-54) == true); 82 | REQUIRE(tree.search(42) == true); 83 | REQUIRE(tree.search(23) == true); 84 | REQUIRE(tree.search(109) == true); 85 | } 86 | 87 | TEST_CASE("Traversals", "[binary-search-tree]") { 88 | BinarySearchTree tree; 89 | 90 | tree.insert(1); 91 | tree.insert(0); 92 | tree.insert(-1); 93 | tree.insert(5); 94 | tree.insert(2); 95 | tree.insert(3); 96 | tree.insert(4); 97 | tree.insert(6); 98 | 99 | // Verify traversals 100 | REQUIRE(tree.traversal_inorder_recursive() == vector({-1,0,1,2,3,4,5,6})); 101 | REQUIRE(tree.traversal_inorder_iterative() == vector({-1,0,1,2,3,4,5,6})); 102 | REQUIRE(tree.traversal_preorder_recursive() == vector({1,0,-1,5,2,3,4,6})); 103 | REQUIRE(tree.traversal_preorder_iterative() == vector({1,0,-1,5,2,3,4,6})); 104 | REQUIRE(tree.traversal_postorder_recursive() == vector({-1,0,4,3,2,6,5,1})); 105 | REQUIRE(tree.traversal_postorder_iterative() == vector({-1,0,4,3,2,6,5,1})); 106 | } 107 | -------------------------------------------------------------------------------- /cpp/test/data_structure/tree/fenwick_tree.cpp: -------------------------------------------------------------------------------- 1 | #include "third_party/catch.hpp" 2 | #include "data_structure/tree/fenwick_tree.hpp" 3 | 4 | TEST_CASE("Create an empty tree", "[fenwick-tree]") { 5 | vector original_array; 6 | FenwickTree tree(original_array); 7 | 8 | REQUIRE(tree.calculate_prefix_sum(0) == 0); 9 | } 10 | 11 | TEST_CASE("Check tree with 5 items", "[fenwick-tree]") { 12 | vector original_array{10, 3, 15, 12, 5}; 13 | 14 | FenwickTree tree(original_array); 15 | 16 | REQUIRE(tree.calculate_prefix_sum(0) == 10); 17 | REQUIRE(tree.calculate_prefix_sum(1) == 13); 18 | REQUIRE(tree.calculate_prefix_sum(2) == 28); 19 | REQUIRE(tree.calculate_prefix_sum(3) == 40); 20 | REQUIRE(tree.calculate_prefix_sum(4) == 45); 21 | } 22 | 23 | TEST_CASE("Check tree that has been updated", "[fenwick-tree]") { 24 | vector original_array{10, 3, 15, 12, 5}; 25 | 26 | FenwickTree tree(original_array); 27 | 28 | // Update in the middle of the array and then check 29 | tree.update_tree(2, 4); 30 | 31 | REQUIRE(tree.calculate_prefix_sum(0) == 10); 32 | REQUIRE(tree.calculate_prefix_sum(1) == 13); 33 | REQUIRE(tree.calculate_prefix_sum(2) == 32); 34 | REQUIRE(tree.calculate_prefix_sum(3) == 44); 35 | REQUIRE(tree.calculate_prefix_sum(4) == 49); 36 | 37 | // Update at the end of the array and then check 38 | tree.update_tree(4, 4); 39 | 40 | REQUIRE(tree.calculate_prefix_sum(0) == 10); 41 | REQUIRE(tree.calculate_prefix_sum(1) == 13); 42 | REQUIRE(tree.calculate_prefix_sum(2) == 32); 43 | REQUIRE(tree.calculate_prefix_sum(3) == 44); 44 | REQUIRE(tree.calculate_prefix_sum(4) == 53); 45 | 46 | // Update at the start of the array and then check 47 | tree.update_tree(0, 4); 48 | 49 | REQUIRE(tree.calculate_prefix_sum(0) == 14); 50 | REQUIRE(tree.calculate_prefix_sum(1) == 17); 51 | REQUIRE(tree.calculate_prefix_sum(2) == 36); 52 | REQUIRE(tree.calculate_prefix_sum(3) == 48); 53 | REQUIRE(tree.calculate_prefix_sum(4) == 57); 54 | } 55 | 56 | TEST_CASE("Check tree that has been updated with a negative number", "[fenwick-tree]") { 57 | vector original_array{10, 3, 15, 12, 5}; 58 | 59 | FenwickTree tree(original_array); 60 | 61 | // original_array will now be [10, 3, 19, 12, 5] 62 | tree.update_tree(1, -3); 63 | 64 | REQUIRE(tree.calculate_prefix_sum(0) == 10); 65 | REQUIRE(tree.calculate_prefix_sum(1) == 10); 66 | REQUIRE(tree.calculate_prefix_sum(2) == 25); 67 | REQUIRE(tree.calculate_prefix_sum(3) == 37); 68 | REQUIRE(tree.calculate_prefix_sum(4) == 42); 69 | 70 | tree.update_tree(4, -3); 71 | REQUIRE(tree.calculate_prefix_sum(0) == 10); 72 | REQUIRE(tree.calculate_prefix_sum(1) == 10); 73 | REQUIRE(tree.calculate_prefix_sum(2) == 25); 74 | REQUIRE(tree.calculate_prefix_sum(3) == 37); 75 | REQUIRE(tree.calculate_prefix_sum(4) == 39); 76 | 77 | tree.update_tree(0, -3); 78 | REQUIRE(tree.calculate_prefix_sum(0) == 7); 79 | REQUIRE(tree.calculate_prefix_sum(1) == 7); 80 | REQUIRE(tree.calculate_prefix_sum(2) == 22); 81 | REQUIRE(tree.calculate_prefix_sum(3) == 34); 82 | REQUIRE(tree.calculate_prefix_sum(4) == 36); 83 | } 84 | -------------------------------------------------------------------------------- /cpp/test/test_runner.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Catch test runner 3 | ----------------- 4 | Separated from the actual tests for faster compiles overall. 5 | See https://github.com/catchorg/Catch2/blob/master/docs/slow-compiles.md 6 | */ 7 | 8 | #define CATCH_CONFIG_MAIN 9 | 10 | #include "third_party/catch.hpp" 11 | 12 | // Do not add anything else here! 13 | -------------------------------------------------------------------------------- /docs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team personally. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4 72 | 73 | [homepage]: https://www.contributor-covenant.org/ 74 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | ## Contents 4 | 5 | * [Getting started](#getting-started) 6 | * [Writing code](#writing-code) 7 | * [Testing code](#testing-code) 8 | * [Opening a pull request](#opening-a-pull-request) 9 | * [Code of conduct](#code-of-conduct) 10 | 11 | ## Getting started 12 | 13 | * Start by exploring the repository. Take a look at how the algorithms and data structures are implemented, how tests are written, and which files go where. 14 | 15 | * Before beginning your contribution, [create an issue][issue-guide]. In your issue's description, please describe the addition or change you wish to make. This helps others guide your contribution, and it lets others know what you're working on. 16 | 17 | * [Fork][fork-guide] the repo, then clone your fork and configure the remotes: 18 | 19 | ```bash 20 | # Clone your fork of the repo into the current directory 21 | git clone https://github.com//ProAlgos-Cpp.git 22 | 23 | # Navigate to the newly cloned directory 24 | cd ProAlgos-Cpp 25 | 26 | # Assign the original repo to a remote called "upstream" 27 | git remote add upstream https://github.com/ProAlgos/ProAlgos-Cpp.git 28 | ``` 29 | 30 | * If you cloned a while ago, get the latest changes from upstream: 31 | 32 | ```bash 33 | git checkout master 34 | git pull upstream master 35 | ``` 36 | 37 | * Create a new branch (starting from the `master` branch) to contain your code for a specific algorithm or data structure: 38 | 39 | ```bash 40 | git checkout -b 41 | ``` 42 | 43 | ## Writing code 44 | 45 | * Start by reviewing our [C++ coding guidelines][coding-guidelines]. 46 | 47 | * Commit your changes in logical chunks. Use Git's [interactive rebase][rebase-info] 48 | feature to tidy up your commits before making them public. For more info, see the following [interactive rebase guide][rebase-guide]. 49 | 50 | * For each algorithm, mention its **time complexity** and **space complexity** 51 | in the _"description comment"_ of its implementation. In case the average-case 52 | and worst-case complexities are different, mention both of them. 53 | 54 | The format for the _"description comment"_ (which is written at the beginning) should be: 55 | 56 | ```text 57 | 58 | ------------------- 59 | 60 | 61 | Time complexity 62 | --------------- 63 | O(...), where 64 | 65 | Space complexity 66 | ---------------- 67 | O(...), where 68 | ``` 69 | 70 | * Before you push your changes to GitHub, make sure that your code compiles and runs without any errors or warnings. 71 | 72 | ## Testing code 73 | 74 | Algorithms and data structures are implemented as header files (.hpp) in the [`include` directory][include-dir] and then verified via unit test files (.cpp) in the [`test` directory][test-dir]. If you're adding an algorithm or data structure, you'll write both the implementation and the unit tests. 75 | 76 | #### Adding unit tests 77 | 78 | 1. Under `test`, locate (or create, if it doesn't exist) 79 | the directory having the same relative path from `test` as from `include`. 80 | For example, if you've created a header file in `include/algorithm/searching`, 81 | locate (or create) the directory `test/algorithm/searching`. 82 | 83 | 1. Create a file with the same name as the corresponding header file for which 84 | you are writing tests, except that the extension should be `.cpp`. 85 | 86 | 1. Add the following code to the test file: 87 | 88 | ```cpp 89 | #include "third_party/catch.hpp" 90 | #include "path/to/header_file.hpp" 91 | ``` 92 | 93 | The path to the header file is relative from the `include` directory. So, 94 | for instance, if you need to include the header file 95 | `include/algorithm/searching/linear_search.hpp`, you can write: 96 | 97 | ```cpp 98 | #include "algorithm/searching/linear_search.hpp" 99 | ``` 100 | 101 | 1. After these lines you can add your test cases. For details regarding how to 102 | write test cases using the [Catch test framework][catch], I suggest you to 103 | go through [this short tutorial][catch-tutorial]. You can also take a look 104 | at the [existing unit tests][test-dir] to get a clearer idea about how the 105 | tests are written. 106 | 107 | 1. Add an entry for your unit test in `CMakeLists.txt`. For example, if your 108 | unit test is `test/algorithm/searching/linear_search.cpp`, add the following 109 | entry for it: 110 | 111 | ```cmake 112 | add_executable(linear_search 113 | test/algorithm/searching/linear_search.cpp) 114 | target_link_libraries(linear_search test_runner) 115 | ``` 116 | 117 | That's it! Now you can compile the test using **`make test`** from the 118 | `C++` directory, which will also run all of the tests for you. In order to run 119 | only a specific test and see its results, run it manually from the `bin` directory. 120 | 121 | ## Opening a pull request 122 | 123 | Follow these steps when you're ready to submit your code: 124 | 125 | 1. Locally merge (or rebase) the upstream development branch into your branch: 126 | 127 | ```bash 128 | git pull [--rebase] upstream master 129 | ``` 130 | 131 | 1. Push your branch up to your fork: 132 | 133 | ```bash 134 | git push origin 135 | ``` 136 | 137 | 1. [Open a pull request][pr-guide] with a clear title and description against the 138 | `master` branch. Your pull request should reference the same issue you created 139 | above. 140 | 141 | 1. Once your pull request has been opened, we'll review it and go from there. :smile: 142 | 143 | ## Code of Conduct 144 | 145 | This project has a [Code of Conduct](CODE_OF_CONDUCT.md). Please follow it in all your interactions with the project. 146 | 147 | [coding-guidelines]: CODING_GUIDELINES.md 148 | [fork-guide]: https://help.github.com/fork-a-repo/ 149 | [rebase-info]: https://help.github.com/en/github/using-git/about-git-rebase 150 | [rebase-guide]: https://hackernoon.com/beginners-guide-to-interactive-rebasing-346a3f9c3a6d 151 | [pr-guide]: https://help.github.com/articles/about-pull-requests/ 152 | [issue-guide]: https://help.github.com/en/articles/about-issues 153 | [catch]: https://github.com/catchorg/Catch2 154 | [catch-tutorial]: https://github.com/catchorg/Catch2/blob/master/docs/tutorial.md#writing-tests 155 | [include-dir]: https://github.com/ProAlgos/ProAlgos-Cpp/tree/master/cpp/include 156 | [test-dir]: https://github.com/ProAlgos/ProAlgos-Cpp/tree/master/cpp/test 157 | --------------------------------------------------------------------------------