├── LICENSE.txt ├── README.md └── src ├── main ├── cpp │ └── algorithms │ │ ├── datastructures │ │ ├── binarysearchtree │ │ │ └── BinarySearchTree.h │ │ ├── hashtable │ │ │ ├── HashTableLinearProbing.h │ │ │ └── HashTableOpenAddressingBase.h │ │ ├── linkedlist │ │ │ └── DoublyLinkedList.h │ │ ├── queue │ │ │ ├── ArrayQueue.h │ │ │ ├── LinkedQueue.h │ │ │ └── Queue.h │ │ └── stack │ │ │ ├── ArrayStack.h │ │ │ ├── ListStack.h │ │ │ └── Stack.h │ │ ├── dp │ │ ├── CoinChange.h │ │ ├── JosephusProblem.h │ │ ├── KnapsackUnbounded.h │ │ ├── Knapsack_01.h │ │ ├── LongestCommonSubstring.h │ │ ├── LongestIncreasingSubsequence.h │ │ ├── LongestPalindromeSubsequence.h │ │ ├── MaximumSubarray.h │ │ └── MinimumWeightPerfectMatching.h │ │ ├── graphtheory │ │ ├── BellmanFordAdjacencyMatrix.h │ │ ├── BreadthFirstSearchAdjacencyListIterative.h │ │ ├── BridgesAdjacencyList.h │ │ ├── DepthFirstSearchAdjacencyListIterative.h │ │ ├── DijkstrasShortestPathAdjacencyList.h │ │ ├── DijkstrasShortestPathAdjacencyListWithDHeap.h │ │ ├── FloydWarshallSolver.h │ │ ├── Graph.h │ │ ├── TarjanSccSolverAdjacencyList.h │ │ ├── TopologicalSortAdjacencyList.h │ │ ├── TspBruteForce.h │ │ ├── TspDynamicProgrammingIterative.h │ │ └── treealgorithms │ │ │ └── RootingTree.h │ │ ├── math │ │ ├── GCD.h │ │ ├── IsPrime.h │ │ ├── LCM.h │ │ └── PrimeFactorization.h │ │ ├── other │ │ ├── BitManipulations.h │ │ └── UniqueCombinations.h │ │ ├── search │ │ ├── BinarySearch.h │ │ ├── InterpolationSearch.h │ │ ├── TernarySearch.h │ │ └── TernarySearchDiscrete.h │ │ └── sorting │ │ ├── BubbleSort.h │ │ ├── BucketSort.h │ │ ├── CountingSort.h │ │ ├── Heapsort.h │ │ └── QuickSort3.h └── python │ └── algorithms │ ├── datastructures │ ├── binarysearchtree │ │ └── BinarySearchTree.py │ ├── linkedlist │ │ └── DoublyLinkedList.py │ ├── queue │ │ ├── ArrayQueue.py │ │ ├── IntQueue.py │ │ ├── LinkedQueue.py │ │ └── Queue.py │ └── stack │ │ ├── ArrayStack.py │ │ ├── IntStack.py │ │ ├── ListStack.py │ │ └── Stack.py │ ├── other │ ├── BitManipulations.py │ ├── Combinations.py │ ├── CombinationsWithRepetition.py │ ├── LazyRangeAdder.py │ ├── Permutations.py │ ├── PowerSet.py │ ├── SlidingWindowMaximum.py │ ├── SquareRootDecomposition.py │ └── UniqueCombinations.py │ ├── search │ ├── BinarySearch.py │ ├── InterpolationSearch.py │ ├── TernarySearch.py │ └── TernarySearchDiscrete.py │ └── sorting │ ├── BubbleSort.py │ ├── BucketSort.py │ ├── CountingSort.py │ ├── Heapsort.py │ ├── InsertionSort.py │ ├── MergeSort.py │ ├── QuickSort.py │ ├── QuickSort3.py │ ├── RadixSort.py │ └── SelectionSort.py └── test ├── cpp └── algorithms │ ├── datastructures │ ├── binarysearchtree │ │ └── BinarySearchTreeTest.cpp │ ├── hashtable │ │ └── HashTableLinearProbingTest.cpp │ ├── linkedlist │ │ └── LinkedListTest.cpp │ ├── queue │ │ └── QueueTest.cpp │ └── stack │ │ └── StackTest.cpp │ ├── dp │ ├── DpTest.cpp │ └── MinimumWeightPerfectMatchingTest.cpp │ ├── graphtheory │ ├── BreadthFirstSearchAdjacencyListIterativeTest.cpp │ ├── BridgesAdjacencyListTest.cpp │ ├── FloydWarshallSolverTest.cpp │ ├── TarjanSccSolverAdjacencyListTest.cpp │ ├── TravelingSalesmanProblemTest.cpp │ └── treealgorithms │ │ └── RootingTreeTest.cpp │ ├── math │ └── MathTest.cpp │ ├── other │ └── BitManipulationsTest.cpp │ ├── search │ └── SearchingTest.cpp │ └── sorting │ └── SortingTest.cpp └── python └── algorithms ├── datastructures ├── binarysearchtree │ └── BinarySearchTreeTest.py ├── linkedlist │ └── DoublyLinkedListTest.py ├── queue │ ├── IntQueueTest.py │ └── QueueTest.py └── stack │ └── StackTest.py ├── other ├── BitManipulationsTest.py ├── LazyRangeAdderTest.py └── SlidingWindowMaximumTest.py ├── search └── InterpolationSearchTest.py └── sorting └── SortingTest.py /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 William Fiset 4 | Copyright (c) 2020 Armin Zare Zadeh 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorithms & data structures project 2 | 3 | This repository presents the Python and C++ code implementation of the provided Algorithms and data structures from William Fiset at: 4 | https://github.com/williamfiset/Algorithms 5 | 6 | 7 | # Contributing 8 | 9 | If you'd like to add or improve an algorithm, your contribution is welcome! 10 | 11 | 12 | # License 13 | 14 | This repository is released under the [MIT license](https://opensource.org/licenses/MIT). In short, this means you are free to use this software in any personal, open-source or commercial projects. Attribution is optional but appreciated. 15 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/datastructures/hashtable/HashTableLinearProbing.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file HashTableLinearProbing.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 14 July 2020 6 | * @version 0.1 7 | * @brief An implementation of a hash-table using open addressing with linear probing as a collision 8 | * resolution method. 9 | */ 10 | 11 | #ifndef D_HASHTABLELINEARPROBING_H 12 | #define D_HASHTABLELINEARPROBING_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include // set and multiset 20 | #include // map and multimap 21 | #include // unordered set/multiset 22 | #include // unordered map/multimap 23 | #include 24 | #include 25 | #include // some numeric algorithm 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace dsa { 35 | 36 | 37 | template 38 | class HashTableLinearProbing : public HashTableOpenAddressingBase { 39 | private: 40 | 41 | public: 42 | HashTableLinearProbing() : HashTableOpenAddressingBase() {} 43 | 44 | HashTableLinearProbing(int capacity) : HashTableOpenAddressingBase(capacity) {} 45 | 46 | HashTableLinearProbing(int capacity, double loadFactor) : HashTableOpenAddressingBase(capacity, loadFactor) {} 47 | 48 | protected: 49 | }; 50 | 51 | 52 | } // namespace dsa 53 | 54 | #endif /* D_HASHTABLELINEARPROBING_H */ 55 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/datastructures/queue/ArrayQueue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file ArrayQueue.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * liujingkun, liujkon@gmail.com 5 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 6 | * @date 03 July 2020 7 | * @version 0.1 8 | * @brief An array implementation of a queue. 9 | */ 10 | 11 | #ifndef D_ARRAY_QUEUE_H 12 | #define D_ARRAY_QUEUE_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include // set and multiset 19 | #include // map and multimap 20 | #include // unordered set/multiset 21 | #include // unordered map/multimap 22 | #include 23 | #include 24 | #include // some numeric algorithm 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace dsa { 34 | 35 | 36 | template 37 | class ArrayQueue : public Queue { 38 | private: 39 | std::vector data_; 40 | int front_; 41 | int rear_; 42 | 43 | public: 44 | ArrayQueue(int id, int capacity) : Queue(id) { 45 | // ArrayQueue maximum size is data.length - 1. 46 | data_= std::vector(capacity + 1, 0); 47 | front_ = 0; 48 | rear_ = 0; 49 | } 50 | 51 | 52 | ~ArrayQueue() { 53 | data_.clear(); 54 | } 55 | 56 | void clear() override { 57 | front_ = 0; 58 | rear_ = 0; 59 | } 60 | 61 | void offer(T elem) override { 62 | if (isFull()) { 63 | throw std::runtime_error("Queue Full"); 64 | } 65 | data_[rear_++] = elem; 66 | rear_ = adjustIndex(rear_, data_.size()); 67 | } 68 | 69 | 70 | T poll() override { 71 | if (isEmpty()) { 72 | throw std::runtime_error("Queue Empty"); 73 | } 74 | 75 | front_ = adjustIndex(front_, data_.size()); 76 | return (T) data_[front_++]; 77 | } 78 | 79 | 80 | T peek() override { 81 | if (isEmpty()) { 82 | throw std::runtime_error("Queue Empty"); 83 | } 84 | front_ = adjustIndex(front_, data_.size()); 85 | return (T) data_[front_]; 86 | } 87 | 88 | 89 | int size() override { 90 | return adjustIndex(rear_ + data_.size() - front_, data_.size()); 91 | } 92 | 93 | 94 | bool isEmpty() override { 95 | return rear_ == front_; 96 | } 97 | 98 | bool isFull() { 99 | return (front_ + data_.size() - rear_) % data_.size() == 1; 100 | } 101 | 102 | private: 103 | int adjustIndex(int index, int size) { 104 | return index >= size ? index - size : index; 105 | } 106 | }; 107 | 108 | } // namespace dsa 109 | 110 | #endif /* D_ARRAY_QUEUE_H */ 111 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/datastructures/queue/LinkedQueue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file LinkedQueue.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 03 July 2020 6 | * @version 0.1 7 | * @brief A simple queue implementation with a linkedlist. 8 | */ 9 | 10 | 11 | #ifndef D_LINKLIST_QUEUE_H 12 | #define D_LINKLIST_QUEUE_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include // set and multiset 19 | #include // map and multimap 20 | #include // unordered set/multiset 21 | #include // unordered map/multimap 22 | #include 23 | #include 24 | #include // some numeric algorithm 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace dsa { 34 | 35 | template 36 | class LinkedQueue : public Queue { 37 | 38 | private: 39 | std::list list_; 40 | 41 | public: 42 | // Create an empty stack 43 | LinkedQueue(int id) : Queue(id) {} 44 | 45 | LinkedQueue(int id, T firstElem) : Queue(id) { 46 | offer(firstElem); 47 | } 48 | 49 | ~LinkedQueue() { 50 | list_.clear(); 51 | } 52 | 53 | // Iterator class can be used to sequentially access nodes of queue 54 | class Iterator 55 | { 56 | public: 57 | 58 | Iterator() noexcept : it_ (list_.begin()) { 59 | } 60 | 61 | Iterator& operator=(typename std::list::iterator& it) 62 | { 63 | this->it_ = it; 64 | return *this; 65 | } 66 | 67 | // Prefix ++ overload 68 | Iterator& operator++() 69 | { 70 | if (it_) 71 | it_++; 72 | return *this; 73 | } 74 | 75 | // Postfix ++ overload 76 | Iterator operator++(int) 77 | { 78 | Iterator iterator = *this; 79 | ++*this; 80 | return iterator; 81 | } 82 | 83 | bool operator!=(const Iterator& iterator) 84 | { 85 | return it_ != iterator.it_; 86 | } 87 | 88 | T operator*() 89 | { 90 | return *it_; 91 | } 92 | 93 | private: 94 | const typename std::list::iterator it_; 95 | }; 96 | 97 | void clear() override { 98 | list_.clear(); 99 | } 100 | 101 | // Return the size of the queue 102 | int size() override { 103 | return list_.size(); 104 | } 105 | 106 | // Returns whether or not the queue is empty 107 | bool isEmpty() override { 108 | return size() == 0; 109 | } 110 | 111 | // Peek the element at the front of the queue 112 | // The method throws an error is the queue is empty 113 | T peek() override { 114 | if (isEmpty()) throw std::runtime_error("Queue Empty"); 115 | return list_.front(); 116 | } 117 | 118 | // Poll an element from the front of the queue 119 | // The method throws an error if the queue is empty 120 | T poll() override { 121 | if (isEmpty()) throw std::runtime_error("Queue Empty"); 122 | T f = list_.front(); 123 | list_.erase(list_.begin()); 124 | return f; 125 | } 126 | 127 | // Add an element to the back of the queue 128 | void offer(T elem) override { 129 | list_.push_back(elem); 130 | } 131 | 132 | }; 133 | 134 | } // namespace dsa 135 | 136 | #endif /* D_LINKLIST_QUEUE_H */ 137 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/datastructures/queue/Queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file Queue.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * liujingkun, liujkon@gmail.com 5 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 6 | * @date 03 July 2020 7 | * @version 0.1 8 | * @brief An abstract base class for queue. 9 | */ 10 | 11 | #ifndef D_QUEUE_H 12 | #define D_QUEUE_H 13 | 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace dsa { 32 | 33 | template 34 | class Queue 35 | { 36 | private: 37 | int id_; 38 | 39 | public: 40 | Queue(int id) : id_(id) {} 41 | 42 | virtual ~Queue() {} 43 | 44 | virtual void clear() = 0; 45 | 46 | virtual void offer(T elem) = 0; 47 | 48 | virtual T poll() = 0; 49 | 50 | virtual T peek() = 0; 51 | 52 | virtual int size() = 0; 53 | 54 | virtual bool isEmpty() = 0; 55 | }; 56 | 57 | } // namespace dsa 58 | 59 | #endif /* D_QUEUE_H */ 60 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/datastructures/stack/ArrayStack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file ArrayStack.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * liujingkun 5 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 6 | * @date 03 July 2020 7 | * @version 0.1 8 | * @brief An array implementation of a stack. 9 | */ 10 | 11 | #ifndef D_ARRAY_STACK_H 12 | #define D_ARRAY_STACK_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include // set and multiset 19 | #include // map and multimap 20 | #include // unordered set/multiset 21 | #include // unordered map/multimap 22 | #include 23 | #include 24 | #include // some numeric algorithm 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace dsa { 34 | 35 | template 36 | class ArrayStack : public Stack { 37 | private: 38 | int capacity_; 39 | std::vector data_; 40 | 41 | public: 42 | ArrayStack(int id) : Stack(id) { 43 | capacity_ = data_.capacity(); 44 | } 45 | 46 | ~ArrayStack() { 47 | data_.clear(); 48 | } 49 | 50 | // Clear the stack 51 | void clear() override { 52 | data_.clear(); 53 | data_.shrink_to_fit(); 54 | capacity_ = data_.capacity(); 55 | } 56 | 57 | int size() override { 58 | return data_.size(); 59 | } 60 | 61 | 62 | bool isEmpty() override { 63 | return data_.size() == 0; 64 | } 65 | 66 | 67 | void push(T elem) override { 68 | data_.push_back(elem); 69 | } 70 | 71 | 72 | T pop() override { 73 | if (isEmpty()) throw std::runtime_error("Empty Stack"); 74 | T elem = data_.back(); 75 | data_.erase(data_.end()-1); 76 | // if (data_.capacity() > data_.size()*2) 77 | // data_.shrink_to_fit(); 78 | return elem; 79 | } 80 | 81 | 82 | T peek() override { 83 | if (isEmpty()) throw std::runtime_error("Empty Stack"); 84 | return data_.back(); 85 | } 86 | }; 87 | 88 | } // namespace dsa 89 | 90 | #endif /* D_ARRAY_STACK_H */ 91 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/datastructures/stack/ListStack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file ListStack.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 02 July 2020 6 | * @version 0.1 7 | * @brief A linked list implementation of a stack. 8 | */ 9 | 10 | 11 | #ifndef D_LINKLIST_STACK_H 12 | #define D_LINKLIST_STACK_H 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include // set and multiset 19 | #include // map and multimap 20 | #include // unordered set/multiset 21 | #include // unordered map/multimap 22 | #include 23 | #include 24 | #include // some numeric algorithm 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace dsa { 34 | 35 | template 36 | class ListStack : public Stack { 37 | 38 | private: 39 | std::list list_; 40 | 41 | public: 42 | // Create an empty stack 43 | ListStack(int id) : Stack(id) {} 44 | 45 | // Create a Stack with an initial element 46 | ListStack(int id, T firstElem) : Stack(id) { 47 | push(firstElem); 48 | } 49 | 50 | ~ListStack() { 51 | list_.clear(); 52 | } 53 | 54 | // Iterator class can be used to sequentially access nodes of stack 55 | class Iterator 56 | { 57 | public: 58 | 59 | Iterator() noexcept : it_ (list_.begin()) { 60 | } 61 | 62 | Iterator& operator=(typename std::list::iterator& it) 63 | { 64 | this->it_ = it; 65 | return *this; 66 | } 67 | 68 | // Prefix ++ overload 69 | Iterator& operator++() 70 | { 71 | if (it_) 72 | it_++; 73 | return *this; 74 | } 75 | 76 | // Postfix ++ overload 77 | Iterator operator++(int) 78 | { 79 | Iterator iterator = *this; 80 | ++*this; 81 | return iterator; 82 | } 83 | 84 | bool operator!=(const Iterator& iterator) 85 | { 86 | return it_ != iterator.it_; 87 | } 88 | 89 | T operator*() 90 | { 91 | return *it_; 92 | } 93 | 94 | private: 95 | const typename std::list::iterator it_; 96 | }; 97 | 98 | // Return the number of elements in the stack 99 | int size() override { 100 | return list_.size(); 101 | } 102 | 103 | // Clear the stack 104 | void clear() override { 105 | list_.clear(); 106 | } 107 | 108 | // Check if the stack is empty 109 | bool isEmpty() override { 110 | return size() == 0; 111 | } 112 | 113 | // Push an element on the stack 114 | void push(T elem) override { 115 | list_.push_back(elem); 116 | } 117 | 118 | // Pop an element off the stack 119 | // Throws an error is the stack is empty 120 | T pop() override { 121 | if (isEmpty()) throw std::runtime_error("Empty Stack"); 122 | T f = list_.back(); 123 | list_.erase(--list_.end()); 124 | return f; 125 | } 126 | 127 | // Peek the top of the stack without removing an element 128 | // Throws an exception if the stack is empty 129 | T peek() override { 130 | if (isEmpty()) throw std::runtime_error("Empty Stack"); 131 | return list_.back(); 132 | } 133 | 134 | }; 135 | 136 | } // namespace dsa 137 | 138 | #endif /* D_LINKLIST_STACK_H */ 139 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/datastructures/stack/Stack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file Stack.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * liujingkun 5 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 6 | * @date 02 July 2020 7 | * @version 0.1 8 | * @brief An abstract base class for stack. 9 | */ 10 | 11 | #ifndef D_STACK_H 12 | #define D_STACK_H 13 | 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace dsa { 32 | 33 | template 34 | class Stack 35 | { 36 | private: 37 | int id_; 38 | 39 | public: 40 | Stack(int id) : id_(id) {} 41 | 42 | virtual ~Stack() {} 43 | 44 | // return the ID the stack implementation 45 | virtual int id() { return id_; } 46 | 47 | // return the number of elements in the stack 48 | virtual int size() = 0; 49 | 50 | // clear the stack 51 | virtual void clear() = 0; 52 | 53 | // return if the stack is empty 54 | virtual bool isEmpty() = 0; 55 | 56 | // push the element on the stack 57 | virtual void push(T elem) = 0; 58 | 59 | // pop the element off the stack 60 | virtual T pop() = 0; 61 | 62 | virtual T peek() = 0; 63 | }; 64 | 65 | } // namespace dsa 66 | 67 | #endif /* D_STACK_H */ 68 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/dp/CoinChange.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file CoinChange.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 15 July 2020 6 | * @version 0.1 7 | * @brief The coin change problem is an unbounded knapsack problem variant. The problem asks you to find 8 | * the minimum number of coins required for a certain amount of change given the coin denominations. 9 | * You may use each coin denomination as many times as you please. 10 | * 11 | *

Tested against: https://leetcode.com/problems/coin-change/ 12 | */ 13 | 14 | #ifndef D_COINCHANGE_H 15 | #define D_COINCHANGE_H 16 | 17 | #include 18 | #include 19 | #include 20 | #include // set and multiset 21 | #include // map and multimap 22 | #include // unordered set/multiset 23 | #include // unordered map/multimap 24 | #include 25 | #include 26 | #include // some numeric algorithm 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace dsa { 36 | 37 | class CoinChange { 38 | 39 | private: 40 | static const int INF; 41 | public: 42 | static int coinChange(const std::vector& coins, int amount) { 43 | 44 | if (coins.size() == 0) throw std::invalid_argument("No coin values :/"); 45 | 46 | int N = coins.size(); 47 | // Initialize table and set first row to be infinity 48 | std::vector> DP(N + 1, std::vector(amount + 1, INF)); 49 | DP[1][0] = 0; 50 | 51 | // Iterate through all the coins 52 | for (int i = 1; i <= N; i++) { 53 | 54 | int coinValue = coins[i - 1]; 55 | for (int j = 1; j <= amount; j++) { 56 | 57 | // Consider not selecting this coin 58 | DP[i][j] = DP[i - 1][j]; 59 | 60 | // Try selecting this coin if it's better 61 | if (j - coinValue >= 0 && DP[i][j - coinValue] + 1 < DP[i][j]) 62 | DP[i][j] = DP[i][j - coinValue] + 1; 63 | } 64 | } 65 | 66 | // The amount we wanted to make cannot be made :/ 67 | if (DP[N][amount] == INF) return -1; 68 | 69 | // Return the minimum number of coins needed 70 | return DP[N][amount]; 71 | } 72 | 73 | 74 | static int coinChangeSpaceEfficient(const std::vector& coins, int amount) { 75 | 76 | if (coins.size() == 0) throw std::invalid_argument("Coins array is null"); 77 | 78 | // Initialize table and set everything to infinity except first cell 79 | std::vector DP(amount + 1, INF); 80 | DP[0] = 0; 81 | 82 | for (int i = 1; i <= amount; i++) 83 | for (int coinValue : coins) 84 | if (i - coinValue >= 0 && DP[i - coinValue] + 1 < DP[i]) DP[i] = DP[i - coinValue] + 1; 85 | 86 | // The amount we wanted to make cannot be made :/ 87 | if (DP[amount] == INF) return -1; 88 | 89 | // Return the minimum number of coins needed 90 | return DP[amount]; 91 | } 92 | 93 | public: 94 | // The recursive approach has the advantage that it does not have to visit 95 | // all possible states like the tabular approach does. This can speedup 96 | // things especially if the coin denominations are large. 97 | static int coinChangeRecursive(const std::vector& coins, int amount) { 98 | 99 | if (coins.size() == 0) throw std::invalid_argument("Coins array is null"); 100 | if (amount < 0) return -1; 101 | 102 | std::vector DP(amount + 1); 103 | return coinChangeRecursive(amount, coins, DP); 104 | } 105 | 106 | private: 107 | // Private helper method to actually go the recursion 108 | static int coinChangeRecursive(int amount, const std::vector& coins, std::vector& DP) { 109 | 110 | // Base cases. 111 | if (amount < 0) return -1; 112 | if (amount == 0) return 0; 113 | if (DP[amount] != 0) return DP[amount]; 114 | 115 | int minCoins = INF; 116 | for (int coinValue : coins) { 117 | 118 | int newAmount = amount - coinValue; 119 | int value = coinChangeRecursive(newAmount, coins, DP); 120 | if (value != -1 && value < minCoins) minCoins = value + 1; 121 | } 122 | 123 | // If we weren't able to find some coins to make our 124 | // amount then cache -1 as the answer. 125 | return DP[amount] = (minCoins == INF) ? -1 : minCoins; 126 | } 127 | 128 | }; 129 | const int CoinChange::INF = 987654321; 130 | 131 | 132 | void CoinChange_test() 133 | { 134 | const std::vector coins{2, 6, 1}; 135 | std::cout << CoinChange::coinChange(coins, 17) << std::endl; 136 | std::cout << CoinChange::coinChangeSpaceEfficient(coins, 17) << std::endl; 137 | std::cout << CoinChange::coinChangeRecursive(coins, 17) << std::endl; 138 | } 139 | 140 | } // namespace dsa 141 | 142 | #endif /* D_JOSEPHUSPROBLEM_H */ 143 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/dp/JosephusProblem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file JosephusProblem.h 3 | * @author (original JAVA) Micah Stairs 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 15 July 2020 6 | * @version 0.1 7 | * @brief An implementation of the Josephus problem Time complexity: O(n) 8 | */ 9 | 10 | #ifndef D_JOSEPHUSPROBLEM_H 11 | #define D_JOSEPHUSPROBLEM_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace dsa { 32 | 33 | class JosephusProblem { 34 | public: 35 | // Suppose there are n people in a circle and person 36 | // 0 kill the k'th person, then the k'th person kills 37 | // the 2k'th person and so on until only one person remains. 38 | // The question is who lives? 39 | // Let n be the number of people and k the hop size 40 | static int josephus(int n, int k) { 41 | std::vector dp(n, 0); 42 | for (int i = 1; i < n; i++) dp[i] = (dp[i - 1] + k) % (i + 1); 43 | return dp[n - 1]; 44 | } 45 | 46 | }; 47 | 48 | 49 | void Josephusproblem_test() 50 | { 51 | int n = 41, k = 2; 52 | std::cout << JosephusProblem::josephus(n, k) << std::endl; 53 | 54 | n = 25; 55 | k = 18; 56 | std::cout << JosephusProblem::josephus(n, k) << std::endl; 57 | 58 | n = 5; 59 | k = 2; 60 | std::cout << JosephusProblem::josephus(n, k) << std::endl; 61 | } 62 | 63 | } // namespace dsa 64 | 65 | #endif /* D_JOSEPHUSPROBLEM_H */ 66 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/dp/KnapsackUnbounded.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file KnapsackUnbounded.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 15 July 2020 6 | * @version 0.1 7 | * @brief This file contains a dynamic programming solutions to the classic unbounded knapsack problem 8 | * where are you are trying to maximize the total profit of items selected without exceeding the 9 | * capacity of your knapsack. 10 | * 11 | *

Version 1: Time Complexity: O(nW) Version 1 Space Complexity: O(nW) 12 | * 13 | *

Version 2: Time Complexity: O(nW) Space Complexity: O(W) 14 | * 15 | *

Tested code against: https://www.hackerrank.com/challenges/unbounded-knapsack 16 | */ 17 | 18 | #ifndef D_KNAPSACKUNBOUNDED_H 19 | #define D_KNAPSACKUNBOUNDED_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include // set and multiset 25 | #include // map and multimap 26 | #include // unordered set/multiset 27 | #include // unordered map/multimap 28 | #include 29 | #include 30 | #include // some numeric algorithm 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | namespace dsa { 40 | 41 | class KnapsackUnbounded { 42 | public: 43 | /** 44 | * @param maxWeight - The maximum weight of the knapsack 45 | * @param W - The weights of the items 46 | * @param V - The values of the items 47 | * @return The maximum achievable profit of selecting a subset of the elements such that the 48 | * capacity of the knapsack is not exceeded 49 | */ 50 | static int unboundedKnapsack(int maxWeight, const std::vector& W, const std::vector& V) { 51 | 52 | if (W.size() == 0 || W.size() != V.size() || maxWeight < 0) 53 | throw std::invalid_argument("Invalid input"); 54 | 55 | int N = W.size(); 56 | 57 | // Initialize a table where individual rows represent items 58 | // and columns represent the weight of the knapsack 59 | std::vector> DP(N + 1, std::vector(maxWeight + 1, 0)); 60 | 61 | // Loop through items 62 | for (int i = 1; i <= N; i++) { 63 | 64 | // Get the value and weight of the item 65 | int w = W[i - 1], v = V[i - 1]; 66 | 67 | // Consider all possible knapsack sizes 68 | for (int sz = 1; sz <= maxWeight; sz++) { 69 | 70 | // Try including the current element 71 | if (sz >= w) DP[i][sz] = DP[i][sz - w] + v; 72 | 73 | // Check if not selecting this item at all is more profitable 74 | if (DP[i - 1][sz] > DP[i][sz]) DP[i][sz] = DP[i - 1][sz]; 75 | } 76 | } 77 | 78 | // Return the best value achievable 79 | return DP[N][maxWeight]; 80 | } 81 | 82 | 83 | public: 84 | static int unboundedKnapsackSpaceEfficient(int maxWeight, const std::vector& W, const std::vector& V) { 85 | 86 | if (W.size() == 0 || W.size() != V.size() || maxWeight < 0) 87 | throw std::invalid_argument("Invalid input"); 88 | 89 | int N = W.size(); 90 | 91 | // Initialize a table where we will only keep track of 92 | // the best possible value for each knapsack weight 93 | std::vector DP(maxWeight + 1, 0); 94 | 95 | // Consider all possible knapsack sizes 96 | for (int sz = 1; sz <= maxWeight; sz++) { 97 | 98 | // Loop through items 99 | for (int i = 0; i < N; i++) { 100 | 101 | // First check that we can include this item (we can't include it if 102 | // it's too heavy for our knapsack). Assumming it fits inside the 103 | // knapsack check if including this element would be profitable. 104 | if (sz - W[i] >= 0 && DP[sz - W[i]] + V[i] > DP[sz]) DP[sz] = DP[sz - W[i]] + V[i]; 105 | } 106 | } 107 | 108 | // Return the best value achievable 109 | return DP[maxWeight]; 110 | } 111 | 112 | }; 113 | 114 | 115 | void UnboundedKnapsack_test() 116 | { 117 | std::vector W{3, 6, 2}; 118 | std::vector V{5, 20, 3}; 119 | int knapsackValue = KnapsackUnbounded::unboundedKnapsackSpaceEfficient(10, W, V); 120 | std::cout << "Maximum knapsack value: " << knapsackValue << std::endl; 121 | } 122 | 123 | } // namespace dsa 124 | 125 | #endif /* D_KNAPSACKUNBOUNDED_H */ 126 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/dp/Knapsack_01.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file Knapsack_01.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 15 July 2020 6 | * @version 0.1 7 | * @brief This file contains a dynamic programming solutions to the classic 0/1 knapsack problem where are 8 | * you are trying to maximize the total profit of items selected without exceeding the capacity of 9 | * your knapsack. 10 | * 11 | *

Time Complexity: O(nW) Space Complexity: O(nW) 12 | * 13 | *

Tested code against: https://open.kattis.com/problems/knapsack 14 | */ 15 | 16 | #ifndef D_KNAPSACK01_H 17 | #define D_KNAPSACK01_H 18 | 19 | #include 20 | #include 21 | #include 22 | #include // set and multiset 23 | #include // map and multimap 24 | #include // unordered set/multiset 25 | #include // unordered map/multimap 26 | #include 27 | #include 28 | #include // some numeric algorithm 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | namespace dsa { 38 | 39 | class Knapsack_01 { 40 | public: 41 | /** 42 | * @param capacity - The maximum capacity of the knapsack 43 | * @param W - The weights of the items 44 | * @param V - The values of the items 45 | * @return The maximum achievable profit of selecting a subset of the elements such that the 46 | * capacity of the knapsack is not exceeded 47 | */ 48 | static int knapsack(int capacity, const std::vector& W, const std::vector& V, std::vector& itemsSelected) { 49 | 50 | if (W.size() == 0 || W.size() != V.size() || capacity < 0) 51 | throw std::invalid_argument("Invalid input"); 52 | 53 | int N = W.size(); 54 | 55 | // Initialize a table where individual rows represent items 56 | // and columns represent the weight of the knapsack 57 | std::vector> DP(N + 1, std::vector(capacity + 1, 0)); 58 | 59 | for (int i = 1; i <= N; i++) { 60 | 61 | // Get the value and weight of the item 62 | int w = W[i - 1], v = V[i - 1]; 63 | 64 | for (int sz = 1; sz <= capacity; sz++) { 65 | 66 | // Consider not picking this element 67 | DP[i][sz] = DP[i - 1][sz]; 68 | 69 | // Consider including the current element and 70 | // see if this would be more profitable 71 | if (sz >= w && DP[i - 1][sz - w] + v > DP[i][sz]) DP[i][sz] = DP[i - 1][sz - w] + v; 72 | } 73 | } 74 | 75 | int sz = capacity; 76 | 77 | // Using the information inside the table we can backtrack and determine 78 | // which items were selected during the dynamic programming phase. The idea 79 | // is that if DP[i][sz] != DP[i-1][sz] then the item was selected 80 | for (int i = N; i > 0; i--) { 81 | if (DP[i][sz] != DP[i - 1][sz]) { 82 | int itemIndex = i - 1; 83 | itemsSelected.push_back(itemIndex); 84 | sz -= W[itemIndex]; 85 | } 86 | } 87 | 88 | // Return the maximum profit 89 | return DP[N][capacity]; 90 | } 91 | 92 | }; 93 | 94 | 95 | void Knapsack01_test() 96 | { 97 | { 98 | int capacity = 10; 99 | std::vector V{1, 4, 8, 5}; 100 | std::vector W{3, 3, 5, 6}; 101 | std::vector itemsSelected; 102 | std::cout << Knapsack_01::knapsack(capacity, W, V, itemsSelected) << std::endl; 103 | } 104 | 105 | { 106 | int capacity = 7; 107 | std::vector V{2, 2, 4, 5, 3}; 108 | std::vector W{3, 1, 3, 4, 2}; 109 | std::vector itemsSelected; 110 | std::cout << Knapsack_01::knapsack(capacity, W, V, itemsSelected) << std::endl; 111 | } 112 | } 113 | 114 | } // namespace dsa 115 | 116 | #endif /* D_KNAPSACK01_H */ 117 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/dp/LongestCommonSubstring.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file LongestCommonSubstring.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 14 July 2020 6 | * @version 0.1 7 | * @brief This file contains an implementation of finding the Longest Common Substring (LCS) between two 8 | * strings using dynamic programming. 9 | * 10 | *

Time Complexity: O(nm) 11 | */ 12 | 13 | #ifndef D_LONGESTCOMMONSUBSTRING_H 14 | #define D_LONGESTCOMMONSUBSTRING_H 15 | 16 | #include 17 | #include 18 | #include 19 | #include // set and multiset 20 | #include // map and multimap 21 | #include // unordered set/multiset 22 | #include // unordered map/multimap 23 | #include 24 | #include 25 | #include // some numeric algorithm 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | namespace dsa { 35 | 36 | class LongestCommonSubstring { 37 | 38 | public: 39 | // Returns a non unique Longest Common Substring 40 | // between the strings str1 and str2 in O(nm) 41 | static std::string lcs(const std::vector& A, const std::vector& B) { 42 | 43 | if (A.size() == 0 || B.size() == 0) return std::string(); 44 | 45 | int n = A.size(); 46 | int m = B.size(); 47 | 48 | if (n == 0 || m == 0) return std::string(); 49 | 50 | std::vector> dp(n + 1, std::vector(m + 1)); 51 | 52 | // Suppose A = a1a2..an-1an and B = b1b2..bn-1bn 53 | for (int i = 1; i <= n; i++) { 54 | for (int j = 1; j <= m; j++) { 55 | 56 | // If ends match the LCS(a1a2..an-1an, b1b2..bn-1bn) = LCS(a1a2..an-1, b1b2..bn-1) + 1 57 | if (A[i - 1] == B[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; 58 | 59 | // If the ends do not match the LCS of a1a2..an-1an and b1b2..bn-1bn is 60 | // max( LCS(a1a2..an-1, b1b2..bn-1bn), LCS(a1a2..an-1an, b1b2..bn-1) ) 61 | else dp[i][j] = std::max(dp[i - 1][j], dp[i][j - 1]); 62 | } 63 | } 64 | 65 | int lcsLen = dp[n][m]; 66 | std::vector lcs(lcsLen); 67 | int index = 0; 68 | 69 | // Backtrack to find a LCS. We search for the cells 70 | // where we included an element which are those with 71 | // dp[i][j] != dp[i-1][j] and dp[i][j] != dp[i][j-1]) 72 | int i = n, j = m; 73 | while (i >= 1 && j >= 1) { 74 | 75 | int v = dp[i][j]; 76 | 77 | // The order of these may output different LCSs 78 | while (i > 1 && dp[i - 1][j] == v) i--; 79 | while (j > 1 && dp[i][j - 1] == v) j--; 80 | 81 | // Make sure there is a match before adding 82 | if (v > 0) lcs[lcsLen - index++ - 1] = A[i - 1]; // or B[j-1]; 83 | 84 | i--; 85 | j--; 86 | } 87 | 88 | return std::string(lcs.begin(), lcs.end()); 89 | } 90 | 91 | }; 92 | 93 | 94 | void LongestCommonSubstring_test() 95 | { 96 | { 97 | std::vector A{'A', 'X', 'B', 'C', 'Y'}; 98 | std::vector B{'Z', 'A', 'Y', 'W', 'B', 'C'}; 99 | std::cout << LongestCommonSubstring::lcs(A, B) << std::endl; // ABC 100 | } 101 | 102 | { 103 | std::vector A{'3', '9', '8', '3', '9', '7', '9', '7', '0'}; 104 | std::vector B{'3', '3', '9', '9', '9', '1', '7', '2', '0', '6'}; 105 | std::cout << LongestCommonSubstring::lcs(A, B) << std::endl; // 339970 106 | } 107 | } 108 | 109 | } // namespace dsa 110 | 111 | #endif /* D_LONGESTCOMMONSUBSTRING_H */ 112 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/dp/LongestIncreasingSubsequence.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file LongestIncreasingSubsequence.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 14 July 2020 6 | * @version 0.1 7 | * @brief This file shows you how to find the length of the longest increasing subsequence length, using 8 | * dynamic programming. Time complexity: O(n^2) 9 | */ 10 | 11 | #ifndef D_LONGESTINCREASINGSUBSEQUENCE_H 12 | #define D_LONGESTINCREASINGSUBSEQUENCE_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include // set and multiset 18 | #include // map and multimap 19 | #include // unordered set/multiset 20 | #include // unordered map/multimap 21 | #include 22 | #include 23 | #include // some numeric algorithm 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace dsa { 33 | 34 | 35 | class LongestIncreasingSubsequence { 36 | 37 | public: 38 | 39 | // Finds the length of the longest increasing subsequence length, O(n^2) 40 | static int lis(const std::vector& ar) { 41 | 42 | if (ar.size() == 0) return 0; 43 | int n = ar.size(), len = 0; 44 | 45 | // When starting, each individual element has a LIS 46 | // of exactly one, so each index is initialized to 1 47 | std::vector dp(n, 1); 48 | 49 | // Processing the array left to right update the value of dp[j] if two 50 | // conditions hold 1) The value at i is less than that of the one at j 51 | // and 2) updating the value of dp[j] to dp[i]+1 is better 52 | for (int i = 0; i < n; i++) { 53 | for (int j = i + 1; j < n; j++) { 54 | if (ar[i] < ar[j] && dp[j] < dp[i] + 1) { 55 | dp[j] = dp[i] + 1; 56 | } 57 | } 58 | // Track the LIS 59 | if (dp[i] > len) len = dp[i]; 60 | } 61 | 62 | return len; 63 | } 64 | }; 65 | 66 | 67 | void LongestIncreasingSubsequence_test() 68 | { 69 | std::cout << LongestIncreasingSubsequence::lis(std::vector{1, 3, 2, 4, 3}) << std::endl; // 3 70 | std::cout << LongestIncreasingSubsequence::lis(std::vector{2, 7, 4, 3, 8}) << std::endl; // 3 71 | std::cout << LongestIncreasingSubsequence::lis(std::vector{5, 4, 3, 2, 1}) << std::endl; // 1 72 | std::cout << LongestIncreasingSubsequence::lis(std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9}) << std::endl; // 9 73 | } 74 | 75 | 76 | } // namespace dsa 77 | 78 | #endif /* D_LONGESTINCREASINGSUBSEQUENCE_H */ 79 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/dp/LongestPalindromeSubsequence.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file LongestPalindromeSubsequence.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 14 July 2020 6 | * @version 0.1 7 | * @brief Implementation of finding the longest paldindrome subsequence Time complexity: O(n^2) 8 | */ 9 | 10 | #ifndef D_LONGESTPALINDROMSUBSEQUENCE_H 11 | #define D_LONGESTPALINDROMSUBSEQUENCE_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace dsa { 32 | 33 | 34 | class LongestPalindromeSubsequence { 35 | public: 36 | // Returns the length of the longest paldindrome subsequence 37 | static int lps(const std::string& s) { 38 | if (s.length() == 0) return 0; 39 | std::vector> dp(s.length(), std::vector(s.length(), 0)); 40 | return lps(s, dp, 0, s.length() - 1); 41 | } 42 | 43 | 44 | private: 45 | // Private recursive method with memoization to count 46 | // the longest paldindrome subsequence. 47 | static int lps(const std::string& s, std::vector>& dp, int i, int j) { 48 | 49 | // Base cases 50 | if (j < i) return 0; 51 | if (i == j) return 1; 52 | if (dp[i][j] != 0) return dp[i][j]; 53 | 54 | char c1 = s.at(i), c2 = s.at(j); 55 | 56 | // Both end characters match 57 | if (c1 == c2) return dp[i][j] = lps(s, dp, i + 1, j - 1) + 2; 58 | 59 | // Consider both possible substrings and take the maximum 60 | return dp[i][j] = std::max(lps(s, dp, i + 1, j), lps(s, dp, i, j - 1)); 61 | } 62 | }; 63 | 64 | 65 | void LongestPalindromeSubsequence_test() 66 | { 67 | std::cout << LongestPalindromeSubsequence::lps("bbbab") << std::endl; // Outputs 4 since "bbbb" is valid soln 68 | std::cout << LongestPalindromeSubsequence::lps("bccd") << std::endl; // Outputs 2 since "cc" is valid soln 69 | } 70 | 71 | 72 | } // namespace dsa 73 | 74 | #endif /* D_LONGESTPALINDROMSUBSEQUENCE_H */ 75 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/dp/MaximumSubarray.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file MaximumSubarray.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 14 July 2020 6 | * @version 0.1 7 | * @brief This file shows you how to find the maximal subarray in an integer array Time complexity: O(n) 8 | */ 9 | 10 | #ifndef D_MAXSUBARRAY_H 11 | #define D_MAXSUBARRAY_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace dsa { 32 | 33 | 34 | class MaximumSubarray { 35 | 36 | public: 37 | // Return the value of the maximum subarray in 'ar' 38 | static long maximumSubarrayValue(const std::vector& ar) { 39 | 40 | if (ar.size() == 0) return 0L; 41 | int n = ar.size(), maxValue, sum; 42 | 43 | maxValue = sum = ar[0]; 44 | 45 | for (int i = 1; i < n; i++) { 46 | 47 | // At each step consider continuing the current subarray 48 | // or starting a new one because adding the next element 49 | // doesn't acutally make the subarray sum any better. 50 | if (ar[i] > sum + ar[i]) sum = ar[i]; 51 | else sum = sum + ar[i]; 52 | 53 | if (sum > maxValue) maxValue = sum; 54 | } 55 | 56 | return maxValue; 57 | } 58 | }; 59 | 60 | 61 | void MaximumSubarray_test() 62 | { 63 | std::cout << MaximumSubarray::maximumSubarrayValue(std::vector{-5}) << std::endl; 64 | std::cout << MaximumSubarray::maximumSubarrayValue(std::vector{-5, -4, -10, -3, -1, -12, -6}) << std::endl; 65 | std::cout << MaximumSubarray::maximumSubarrayValue(std::vector{1, 2, 1, -7, 2, -1, 40, -89}) << std::endl; 66 | } 67 | 68 | 69 | } // namespace dsa 70 | 71 | #endif /* D_MAXSUBARRAY_H */ 72 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/graphtheory/DepthFirstSearchAdjacencyListIterative.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file DepthFirstSearchAdjacencyListIterative.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 09 July 2020 6 | * @version 0.1 7 | * @brief An implementation of a iterative DFS with an adjacency list 8 | * Time Complexity: O(V + E) 9 | * 10 | * # Global or class scope variables 11 | * n = number of nodes in the graph 12 | * g = adjacency list representing graph 13 | * visited = [false, ..., false] # size n 14 | * 15 | * function dfs(at): 16 | * if visited[at]: return 17 | * visited[at] = true 18 | * 19 | * neighbours = graph[at] 20 | * for next in neighbours: 21 | * dfs(next) 22 | * 23 | * # Start DFS at node zero 24 | * start_node = 0 25 | * dfs(start_node) 26 | */ 27 | 28 | #ifndef D_GRAPH_DEPTHFIRSTSEARCH_H 29 | #define D_GRAPH_DEPTHFIRSTSEARCH_H 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include // set and multiset 37 | #include // map and multimap 38 | #include // unordered set/multiset 39 | #include // unordered map/multimap 40 | #include 41 | #include 42 | #include // some numeric algorithm 43 | #include 44 | #include 45 | 46 | #include 47 | 48 | namespace dsa { 49 | 50 | class DepthFirstSearchAdjacencyListIterative 51 | { 52 | 53 | private: 54 | Graph *graph_; 55 | unsigned n_; 56 | 57 | public: 58 | DepthFirstSearchAdjacencyListIterative(Graph *graph) { 59 | if (graph == nullptr) throw std::invalid_argument("GRAPH NULL"); 60 | n_ = graph->size(); 61 | graph_ = graph; 62 | } 63 | 64 | DepthFirstSearchAdjacencyListIterative(const DepthFirstSearchAdjacencyListIterative&) = delete; 65 | DepthFirstSearchAdjacencyListIterative& operator=(DepthFirstSearchAdjacencyListIterative const&) = delete; 66 | 67 | const Graph& operator()() { 68 | return *graph_; 69 | } 70 | 71 | public: 72 | 73 | // Perform a depth first search on a graph with n nodes 74 | // from a starting point to count the number of nodes 75 | // in a given component. 76 | int dfs(int start) { 77 | int count = 0; 78 | 79 | if (n_ == 0) return count; 80 | 81 | if (start < 0 || (unsigned)start >= n_) throw std::invalid_argument("Invalid start node index"); 82 | 83 | std::vector visited(n_, false); 84 | std::stack stack_; 85 | 86 | std::cout << std::endl; 87 | 88 | // Start by visiting the starting node 89 | stack_.push(start); 90 | 91 | while (!stack_.empty()) { 92 | int node = stack_.top(); 93 | stack_.pop(); 94 | if (!visited[node]) { 95 | count++; 96 | visited[node] = true; 97 | std::cout << "DFS visiting node: " << node << std::endl; 98 | auto graphItr = (*graph_)()->find(node); 99 | if (graphItr != (*graph_)()->end()) { 100 | std::cout << " is in graph map" << std::endl; 101 | if (!graphItr->second.empty()){ 102 | for (auto edge: graphItr->second){ 103 | if (!visited[edge.first]) { 104 | stack_.push(edge.first); 105 | std::cout << " visiting edge: " << graphItr->first << " -> " << edge.first << std::endl; 106 | } 107 | else{ 108 | std::cout << " already visited edge: " << graphItr->first << " -> " << edge.first << std::endl; 109 | } 110 | } 111 | } 112 | } 113 | else { 114 | std::cout << " is not in graph map" << std::endl; 115 | } 116 | } 117 | } 118 | 119 | std::cout << std::endl; 120 | 121 | return count; 122 | } 123 | }; 124 | 125 | 126 | 127 | // Example usage of DFS 128 | int dfs_test() 129 | { 130 | // Create a fully connected graph 131 | // (0) 132 | // / \ 133 | // 5 / \ 4 134 | // / \ 135 | // 10 < -2 > 136 | // +->(2)<------(1) (4) 137 | // +--- \ / 138 | // \ / 139 | // 1 \ / 6 140 | // > < 141 | // (3) 142 | Graph graph(5); 143 | 144 | graph.addDirectedEdge(0, 1); 145 | graph.addDirectedEdge(0, 2); 146 | graph.addDirectedEdge(1, 2); 147 | graph.addDirectedEdge(1, 3); 148 | graph.addDirectedEdge(2, 3); 149 | graph.addDirectedEdge(2, 2); // Self loop 150 | 151 | DepthFirstSearchAdjacencyListIterative solver(&graph); 152 | 153 | int nodeCount = solver.dfs(0); 154 | std::cout << "DFS node count starting at node 0: " << nodeCount << std::endl; 155 | if (nodeCount != 4) std::cout << "Error with DFS " << std::endl; 156 | 157 | nodeCount = solver.dfs(4); 158 | std::cout << "DFS node count starting at node 4:" << nodeCount << std::endl; 159 | if (nodeCount != 1) std::cout << "Error with DFS" << std::endl; 160 | 161 | return 0; 162 | } 163 | 164 | } // namespace dsa 165 | 166 | #endif /* D_GRAPH_DEPTHFIRSTSEARCH_H */ 167 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/graphtheory/Graph.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file Graph.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 07 July 2020 6 | * @version 0.1 7 | * @brief An implementation of Graph with an adjacency list. 8 | */ 9 | 10 | #ifndef D_GRAPH_H 11 | #define D_GRAPH_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace dsa { 31 | 32 | typedef std::vector IntegerVector; 33 | 34 | class Graph 35 | { 36 | 37 | public: 38 | 39 | using GRAPH_EDGE = std::unordered_map; // Node ID, Cost 40 | using GRAPH_VERTEX = std::unordered_map; // Node ID, Edges 41 | 42 | private: 43 | GRAPH_VERTEX *vertices_; 44 | int edgeCount_; 45 | 46 | public: 47 | Graph(int n) { 48 | vertices_ = new GRAPH_VERTEX(); 49 | for (int i = 0; i < n; i++) { 50 | GRAPH_EDGE edge_; 51 | vertices_->insert(make_pair(i, std::move(edge_))); 52 | } 53 | edgeCount_ = 0; 54 | } 55 | 56 | 57 | virtual ~Graph() { 58 | if (vertices_) { 59 | delete vertices_; 60 | vertices_ = nullptr; 61 | } 62 | } 63 | 64 | 65 | Graph(const Graph& rhs) { // Copy constructor 66 | std::cout << "Graph copy constructor" << std::endl; 67 | vertices_ = rhs.vertices_; 68 | edgeCount_ = rhs.edgeCount_; 69 | } 70 | 71 | 72 | Graph(const Graph&& rhs) { // Move constructor 73 | std::cout << "Graph move constructor" << std::endl; 74 | vertices_ = rhs.vertices_; 75 | edgeCount_ = rhs.edgeCount_; 76 | } 77 | 78 | 79 | Graph& operator = (const Graph& rhs ) { 80 | std::cout << "Graph copy operator" << std::endl; 81 | if (this != &rhs) { 82 | for (auto it = rhs.vertices_->begin();; it++) { 83 | if (it == rhs.vertices_->end()) break; 84 | GRAPH_EDGE edges; 85 | if (!it->second.empty()) { 86 | for (auto edge: it->second) { 87 | edges.insert(std::move(edge)); 88 | } 89 | } 90 | vertices_->insert(make_pair(it->first, std::move(edges))); 91 | } 92 | } 93 | std::cout << "Graph copy operator DONE" << std::endl; 94 | 95 | return *this; 96 | } 97 | 98 | Graph& operator = (Graph&& rhs ) { 99 | std::cout << "Graph move operator" << std::endl; 100 | if (this != &rhs) { 101 | vertices_ = rhs.vertices_; 102 | } 103 | return *this; 104 | } 105 | 106 | GRAPH_VERTEX* operator()() { 107 | return vertices_; 108 | } 109 | 110 | 111 | // Empty this graph 112 | void clear() { 113 | for (auto itr = vertices_->begin(); itr != vertices_->end(); itr++) 114 | itr->second.erase(itr->second.begin(), itr->second.end()); 115 | vertices_->erase(vertices_->begin(), vertices_->end()); 116 | } 117 | 118 | 119 | // Get size of graph 120 | unsigned int size() { 121 | return vertices_->size(); 122 | } 123 | 124 | 125 | // Get number of edges 126 | unsigned int edgeCount() { 127 | return edgeCount_; 128 | } 129 | 130 | 131 | // Add a directed edge from node 'u' to node 'v' with cost 'cost'. 132 | // 133 | // Adds a directed edge to the graph. 134 | // 135 | // @param from - The index of the node the directed edge starts at. 136 | // @param to - The index of the node the directed edge end at. 137 | // @param cost - The cost of the edge. 138 | // 139 | void addDirectedEdge(int u, int v, double cost = 0.0) { 140 | (*vertices_)[u][v] = cost; 141 | edgeCount_++; 142 | } 143 | 144 | 145 | // Add an undirected edge between nodes 'u' and 'v'. 146 | void addUndirectedEdge(int u, int v, double cost = 0.0) { 147 | addDirectedEdge(u, v, cost); 148 | addDirectedEdge(v, u, cost); 149 | } 150 | 151 | 152 | // Add an undirected un-weighted edge between nodes 'u' and 'v'. The edge added 153 | // will have a weight of 1 since its intended to be unweighted. 154 | void addUnweightedUndirectedEdge(int u, int v) { 155 | addUndirectedEdge(u, v, 0.0); 156 | } 157 | 158 | 159 | static std::string formatPath(int start, int end, std::list& path) { 160 | std::stringstream ss; 161 | ss << "Path(" << start << ":" << end << ")["; 162 | if (path.size()) { 163 | for (auto node: path) { 164 | ss << " -> "; 165 | ss << node; 166 | } 167 | } 168 | ss << "]"; 169 | std::string s = ss.str(); 170 | 171 | return s; 172 | } 173 | 174 | 175 | std::string toString() const { 176 | std::stringstream os; 177 | os << "Graph[" << std::endl; 178 | 179 | for (auto it = vertices_->begin();; it++) { 180 | if (it == vertices_->end()) break; 181 | os << " Node(" << it->first << ")["; 182 | if (!it->second.empty()) { 183 | for (auto edge: it->second) { 184 | os << "Edge(" << "->" << edge.first << ",cost:" << edge.second << ")"; 185 | os << ","; 186 | } 187 | } 188 | os << "]" << std::endl; 189 | } 190 | 191 | os << "]"; 192 | 193 | return os.str(); 194 | } 195 | 196 | 197 | friend std::ostream& operator<<(std::ostream &strm, const Graph &g) { 198 | return strm << g.toString(); 199 | } 200 | 201 | }; 202 | 203 | } // namespace dsa 204 | 205 | #endif /* D_GRAPH_H */ 206 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/math/GCD.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file GCD.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 15 July 2020 6 | * @version 0.1 7 | * @brief An implementation of finding the GCD of two numbers 8 | * 9 | *

Time Complexity ~O(log(a + b)) 10 | */ 11 | 12 | #ifndef D_GCD_H 13 | #define D_GCD_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include // set and multiset 19 | #include // map and multimap 20 | #include // unordered set/multiset 21 | #include // unordered map/multimap 22 | #include 23 | #include 24 | #include // some numeric algorithm 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace dsa { 34 | 35 | class GCD { 36 | public: 37 | // Computes the Greatest Common Divisor (GCD) of a & b 38 | // This method ensures that the value returned is non negative 39 | static long gcd(long a, long b) { 40 | return b == 0 ? (a < 0 ? -a : a) : gcd(b, a % b); 41 | } 42 | }; 43 | 44 | 45 | void GCD_test() 46 | { 47 | std::cout << GCD::gcd(12, 18) << std::endl; // 6 48 | std::cout << GCD::gcd(-12, 18) << std::endl; // 6 49 | std::cout << GCD::gcd(12, -18) << std::endl; // 6 50 | std::cout << GCD::gcd(-12, -18) << std::endl; // 6 51 | 52 | std::cout << GCD::gcd(5, 0) << std::endl; // 5 53 | std::cout << GCD::gcd(0, 5) << std::endl; // 5 54 | std::cout << GCD::gcd(-5, 0) << std::endl; // 5 55 | std::cout << GCD::gcd(0, -5) << std::endl; // 5 56 | std::cout << GCD::gcd(0, 0) << std::endl; // 0 57 | } 58 | 59 | } // namespace dsa 60 | 61 | #endif /* D_GCD_H */ 62 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/math/IsPrime.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file IsPrime.h 3 | * @author (original JAVA) Micah Stairs, William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 15 July 2020 6 | * @version 0.1 7 | * @brief Tests whether a number is a prime number or not Time Complexity: O(sqrt(n)) 8 | */ 9 | 10 | #ifndef D_ISPRIME_H 11 | #define D_ISPRIME_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace dsa { 32 | 33 | class IsPrime { 34 | public: 35 | static bool isPrime(long n) { 36 | if (n < 2) return false; 37 | if (n == 2 || n == 3) return true; 38 | if (n % 2 == 0 || n % 3 == 0) return false; 39 | 40 | long limit = (long) sqrt(n); 41 | 42 | for (long i = 5; i <= limit; i += 6) { 43 | if (n % i == 0 || n % (i + 2) == 0) { 44 | return false; 45 | } 46 | } 47 | return true; 48 | } 49 | 50 | }; 51 | 52 | 53 | void IsPrime_test() 54 | { 55 | std::cout << IsPrime::isPrime(5) << std::endl; 56 | std::cout << IsPrime::isPrime(31) << std::endl; 57 | std::cout << IsPrime::isPrime(1433) << std::endl; 58 | std::cout << IsPrime::isPrime(8763857775536878331L) << std::endl; 59 | } 60 | 61 | } // namespace dsa 62 | 63 | #endif /* D_ISPRIME_H */ 64 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/math/LCM.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file LCM.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 15 July 2020 6 | * @version 0.1 7 | * @brief An implementation of finding the LCM of two numbers 8 | * 9 | *

Time Complexity ~O(log(a + b)) 10 | */ 11 | 12 | #ifndef D_LCM_H 13 | #define D_LCM_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include // set and multiset 19 | #include // map and multimap 20 | #include // unordered set/multiset 21 | #include // unordered map/multimap 22 | #include 23 | #include 24 | #include // some numeric algorithm 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace dsa { 34 | 35 | class LCM { 36 | private: 37 | // Finds the greatest common divisor of a and b 38 | static long gcd(long a, long b) { 39 | return b == 0 ? (a < 0 ? -a : a) : gcd(b, a % b); 40 | } 41 | 42 | public: 43 | // Finds the least common multiple of a and b 44 | static long lcm(long a, long b) { 45 | long lcm = (a / gcd(a, b)) * b; 46 | return lcm > 0 ? lcm : -lcm; 47 | } 48 | }; 49 | 50 | 51 | void LCM_test() 52 | { 53 | std::cout << LCM::lcm(12, 18) << std::endl; // 36 54 | std::cout << LCM::lcm(-12, 18) << std::endl; // 36 55 | std::cout << LCM::lcm(12, -18) << std::endl; // 36 56 | std::cout << LCM::lcm(-12, -18) << std::endl; // 36 57 | } 58 | 59 | } // namespace dsa 60 | 61 | #endif /* D_LCM_H */ 62 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/math/PrimeFactorization.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file PrimeFactorization.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 15 July 2020 6 | * @version 0.1 7 | * @brief An implementation of finding the LCM of two numbers 8 | * 9 | */ 10 | 11 | #ifndef D_PRIMEFACTORIZATION_H 12 | #define D_PRIMEFACTORIZATION_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include // set and multiset 19 | #include // map and multimap 20 | #include // unordered set/multiset 21 | #include // unordered map/multimap 22 | #include 23 | #include 24 | #include // some numeric algorithm 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace dsa { 36 | 37 | 38 | class PrimeFactorization { 39 | 40 | public: 41 | static std::multiset primeFactorization(long n) { 42 | std::multiset factors; 43 | if (n <= 0) throw std::invalid_argument("Invalid input"); 44 | else if (n == 1) return factors; 45 | auto longComparer = [](long a, long b) -> bool { return a > b; }; 46 | std::priority_queue, decltype(longComparer)> divisorQueue(longComparer); 47 | divisorQueue.push(n); 48 | while (divisorQueue.size() > 0) { 49 | long divisor = divisorQueue.top(); 50 | divisorQueue.pop(); 51 | if (isPrime(divisor)) { 52 | factors.insert(divisor); 53 | continue; 54 | } 55 | long next_divisor = pollardRho(divisor); 56 | if (next_divisor == divisor) { 57 | divisorQueue.push(divisor); 58 | } else { 59 | divisorQueue.push(next_divisor); 60 | divisorQueue.push(divisor / next_divisor); 61 | } 62 | } 63 | return factors; 64 | } 65 | 66 | private: 67 | 68 | static int genRandInt(int start_in, int end_in) 69 | { 70 | // engine only provides a source of randomness 71 | std::mt19937_64 rng; 72 | // initialize the random number generator with time-dependent seed 73 | uint64_t timeSeed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 74 | std::seed_seq ss{uint32_t(timeSeed & 0xffffffff), uint32_t(timeSeed>>32)}; 75 | rng.seed(ss); 76 | std::uniform_int_distribution dist(start_in, end_in); 77 | 78 | return dist(rng); 79 | } 80 | 81 | 82 | static long pollardRho(long n) { 83 | if (n % 2 == 0) return 2; 84 | long x = 2 + (long) genRandInt(0, 999999); 85 | long c = 2 + (long) genRandInt(0, 999999); 86 | long y = x; 87 | long d = 1; 88 | while (d == 1) { 89 | x = (x * x + c) % n; 90 | y = (y * y + c) % n; 91 | y = (y * y + c) % n; 92 | d = gcd(abs(x - y), n); 93 | if (d == n) break; 94 | } 95 | return d; 96 | } 97 | 98 | 99 | static long gcd(long a, long b) { 100 | return b == 0 ? a : gcd(b, a % b); 101 | } 102 | 103 | 104 | static bool isPrime(long n) { 105 | if (n < 2) return false; 106 | if (n == 2 || n == 3) return true; 107 | if (n % 2 == 0 || n % 3 == 0) return false; 108 | long limit = (long) sqrt(n); 109 | for (long i = 5; i <= limit; i += 6) if (n % i == 0 || n % (i + 2) == 0) return false; 110 | return true; 111 | } 112 | 113 | }; 114 | 115 | 116 | void PrimeFactorization_test() 117 | { 118 | #define PRINT_FACTORIZATION(r) \ 119 | do { \ 120 | std::cout << "["; \ 121 | for (auto pf : PrimeFactorization::primeFactorization(r)) std::cout << pf << ","; \ 122 | std::cout << "]"; \ 123 | } while(0) 124 | 125 | PRINT_FACTORIZATION(7); // [7] 126 | PRINT_FACTORIZATION(100); // [2,2,5,5] 127 | PRINT_FACTORIZATION(666); // [2,3,3,37] 128 | PRINT_FACTORIZATION(872342345); // [5, 7, 7, 67, 19, 2797] 129 | } 130 | 131 | } // namespace dsa 132 | 133 | #endif /* D_PRIMEFACTORIZATION_H */ 134 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/other/BitManipulations.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file BitManipulations.h 3 | * @author (original JAVA) Micah Stairs 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 13 July 2020 6 | * @version 0.1 7 | * @brief Fundamental bit manipulation operations you must know Time Complexity: O(1). 8 | */ 9 | 10 | #ifndef D_BITMANIPULATIONS_H 11 | #define D_BITMANIPULATIONS_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace dsa { 31 | 32 | class BitManipulations { 33 | public: 34 | BitManipulations(const BitManipulations&) = delete; 35 | BitManipulations& operator=(BitManipulations const&) = delete; 36 | 37 | // Sets the i'th bit to 1 38 | static int setBit(int set, int i) { 39 | return set | (1 << i); 40 | } 41 | 42 | 43 | // Checks if the i'th is set 44 | static bool isSet(int set, int i) { 45 | return (set & (1 << i)) != 0; 46 | } 47 | 48 | 49 | // Sets the i'th bit to zero 50 | static int clearBit(int set, int i) { 51 | return set & ~(1 << i); 52 | } 53 | 54 | 55 | // Toggles the i'th bit from 0 -> 1 or 1 -> 0 56 | static int toggleBit(int set, int i) { 57 | return set ^ (1 << i); 58 | } 59 | 60 | 61 | // Returns a number with the first n bits set to 1 62 | static int setAll(int n) { 63 | return (1 << n) - 1; 64 | } 65 | 66 | 67 | // Verifies if a number n is a power of two 68 | static bool isPowerOfTwo(int n) { 69 | return n > 0 && (n & (n - 1)) == 0; 70 | } 71 | }; 72 | 73 | } // namespace dsa 74 | 75 | #endif /* D_BITMANIPULATIONS_H */ 76 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/other/UniqueCombinations.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file UniqueCombinations.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 13 July 2020 6 | * @version 0.1 7 | * @brief 8 | * This file shows you how to generate all the unique combinations of a set even though some 9 | * elements may be repeated. For example, if your set is {2, 2, 3, 3, 3} and you care only about 10 | * sets of size two (r = 2) then the unique sets are {{2,2}, {2,3}, {3,3}}. 11 | * 12 | *

Time Complexity: O( n choose r ) 13 | */ 14 | 15 | #ifndef D_UNIQUECOMBINATIONS_H 16 | #define D_UNIQUECOMBINATIONS_H 17 | 18 | #include 19 | #include 20 | #include 21 | #include // set and multiset 22 | #include // map and multimap 23 | #include // unordered set/multiset 24 | #include // unordered map/multimap 25 | #include 26 | #include 27 | #include // some numeric algorithm 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace dsa { 36 | 37 | class UniqueCombinations { 38 | 39 | public: 40 | static void combinations(const std::vector& set, int r) { 41 | 42 | if (set.size() == 0) return; 43 | if (r < 0) return; 44 | 45 | // Sort the numbers so we can easily skip duplicates. 46 | std::vector set_cpy = set; 47 | std::sort(set_cpy.begin(), set_cpy.end()); 48 | 49 | std::vector used(set.size(), false); 50 | combinations(0, r, used, set); 51 | } 52 | 53 | private: 54 | static void combinations(int at, int r, std::vector &used, const std::vector& set) { 55 | 56 | int n = set.size(); 57 | 58 | // We select 'r' elements so we found a valid subset! 59 | if (r == 0) { 60 | 61 | std::vector subset; 62 | for (int i = 0; i < n; i++) if (used[i]) subset.push_back(set[i]); 63 | std::cout << "["; 64 | for (auto s : subset) std::cout << s << ","; 65 | std::cout << "]" << std::endl; 66 | 67 | } else { 68 | for (int i = at; i < n; i++) { 69 | 70 | // Since the elements are sorted we can skip duplicate 71 | // elements to ensure the uniqueness of our output. 72 | if (i > at && set[i - 1] == set[i]) continue; 73 | 74 | used[i] = true; 75 | combinations(i + 1, r - 1, used, set); 76 | used[i] = false; 77 | } 78 | } 79 | } 80 | 81 | }; 82 | 83 | 84 | // Example usage of Unique Combunations 85 | int UniqueCombunations_test() 86 | { 87 | // Example #1 88 | int r = 2; 89 | std::vector set{2, 3, 3, 2, 3}; 90 | UniqueCombinations::combinations(set, r); 91 | // Prints: 92 | // [2, 2] 93 | // [2, 3] 94 | // [3, 3] 95 | 96 | 97 | r = 3; 98 | set = std::vector{1, 2, 2, 2, 3, 3, 4, 4}; 99 | UniqueCombinations::combinations(set, r); 100 | // Prints: 101 | // [1, 2, 2] 102 | // [1, 2, 3] 103 | // [1, 2, 4] 104 | // [1, 3, 3] 105 | // [1, 3, 4] 106 | // [1, 4, 4] 107 | // [2, 2, 2] 108 | // [2, 2, 3] 109 | // [2, 2, 4] 110 | // [2, 3, 3] 111 | // [2, 3, 4] 112 | // [2, 4, 4] 113 | // [3, 3, 4] 114 | // [3, 4, 4] 115 | 116 | return 0; 117 | } 118 | 119 | } // namespace dsa 120 | 121 | #endif /* D_UNIQUECOMBINATIONS_H */ 122 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/search/InterpolationSearch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file InterpolationSearch.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 14 July 2020 6 | * @version 0.1 7 | * @brief An implementation of interpolation search. 8 | *

Time Complexity: O(log(log(n))) if data is uniform O(n) in worst case 9 | */ 10 | 11 | #ifndef D_INTERPOLATIONSEARCH_H 12 | #define D_INTERPOLATIONSEARCH_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include // set and multiset 18 | #include // map and multimap 19 | #include // unordered set/multiset 20 | #include // unordered map/multimap 21 | #include 22 | #include 23 | #include // some numeric algorithm 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace dsa { 33 | 34 | 35 | class InterpolationSearch { 36 | 37 | public: 38 | /** 39 | * A fast alternative to a binary search when the elements are uniformly distributed. This 40 | * algorithm runs in a time complexity of ~O(log(log(n))). 41 | * 42 | * @param nums - an ordered list containing uniformly distributed values. 43 | * @param val - the value we're looking for in 'nums' 44 | */ 45 | static int interpolationSearch(const std::vector& nums, int val) { 46 | int lo = 0, mid = 0, hi = nums.size() - 1; 47 | while (nums[lo] <= val && nums[hi] >= val) { 48 | mid = lo + ((val - nums[lo]) * (hi - lo)) / (nums[hi] - nums[lo]); 49 | if (nums[mid] < val) { 50 | lo = mid + 1; 51 | } else if (nums[mid] > val) { 52 | hi = mid - 1; 53 | } else return mid; 54 | } 55 | if (nums[lo] == val) return lo; 56 | return -1; 57 | } 58 | 59 | }; 60 | 61 | 62 | // Example usage of Interpolation search 63 | int InterpolationSearch_test() 64 | { 65 | std::vector values{10, 20, 25, 35, 50, 70, 85, 100, 110, 120, 125}; 66 | 67 | // Since 25 exists in the values array the interpolation search 68 | // returns that it has found 25 at the index 2 69 | std::cout << InterpolationSearch::interpolationSearch(values, 25) << std::endl; 70 | 71 | // 111 does not exist so we get -1 as an index value 72 | std::cout << InterpolationSearch::interpolationSearch(values, 111) << std::endl; 73 | 74 | return 0; 75 | } 76 | 77 | } // namespace dsa 78 | 79 | #endif /* D_INTERPOLATIONSEARCH_H */ 80 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/search/TernarySearch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file TernarySearch.h 3 | * @author (original JAVA) Micah Stairs 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 14 July 2020 6 | * @version 0.1 7 | * @brief An implementation of TernarySearch search. 8 | * Ternary search is similar to binary search except that it works on a function which decreases and 9 | * then increases. This implementation of ternary search returns the input value corresponding with 10 | * the minimum output value of the function you're searching on. 11 | * 12 | *

Time Complexity: O(log(high - low)). 13 | * 14 | *

NOTE: You can also work with a function which increases and then decreases, simply negate your 15 | * function :) 16 | */ 17 | 18 | #ifndef D_TERNARYSEARCH_H 19 | #define D_TERNARYSEARCH_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include // set and multiset 25 | #include // map and multimap 26 | #include // unordered set/multiset 27 | #include // unordered map/multimap 28 | #include 29 | #include 30 | #include // some numeric algorithm 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | namespace dsa { 40 | 41 | class TernarySearch { 42 | 43 | public: 44 | // Perform a ternary search on the interval low to high. 45 | // Remember that your function must be a continuous unimodal 46 | // function, this means a function which decreases then increases (U shape) 47 | static double ternarySearch(double low, double high, std::function function) { 48 | // Define a very small epsilon value to compare double values 49 | const double EPS = 0.000000001; 50 | double best = std::numeric_limits::quiet_NaN(); 51 | while (true) { 52 | double mid1 = (2 * low + high) / 3, mid2 = (low + 2 * high) / 3; 53 | double res1 = function(mid1), res2 = function(mid2); 54 | if (res1 > res2) low = mid1; 55 | else high = mid2; 56 | if (!std::isnan(best) && std::abs(best - mid1) < EPS) break; 57 | best = mid1; 58 | } 59 | return best; 60 | } 61 | 62 | }; 63 | 64 | 65 | // Example /usage of Ternary search 66 | int TernarySearch_test() 67 | { 68 | // Search for the lowest point on the function x^2 + 3x + 5 69 | // using a ternary search on the interval [-100, +100] 70 | auto function = [](double x) -> double { return x * x + 3 * x + 5; }; 71 | double root = TernarySearch::ternarySearch(-100.0, +100.0, function); 72 | std::cout << root << std::endl; 73 | return 0; 74 | } 75 | 76 | } // namespace dsa 77 | 78 | #endif /* D_TERNARYSEARCH_H */ 79 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/search/TernarySearchDiscrete.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file TernarySearchDiscrete.h 3 | * @author (original JAVA) Thomas Finn Lidbetter 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 14 July 2020 6 | * @version 0.1 7 | * @brief An implementation of TernarySearch search. 8 | * Ternary search is similar to binary search except that it works on a function which decreases and 9 | * then increases. This implementation of ternary search works on discrete values and returns the 10 | * input value corresponding with the minimum output value of the function you're searching on. 11 | * 12 | *

Time Complexity: O(log(high - low)). 13 | * 14 | *

NOTE: You can also work with a function which increases and then decreases, simply negate your 15 | * function :) 16 | */ 17 | 18 | #ifndef D_TERNARYSEARCHDISCRETE_H 19 | #define D_TERNARYSEARCHDISCRETE_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include // set and multiset 25 | #include // map and multimap 26 | #include // unordered set/multiset 27 | #include // unordered map/multimap 28 | #include 29 | #include 30 | #include // some numeric algorithm 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | namespace dsa { 40 | 41 | class TernarySearchDiscrete { 42 | 43 | public: 44 | static double discreteTernarySearch(int lo, int hi, std::function function) { 45 | // Define a very small epsilon value to compare double values. 46 | while (lo != hi) { 47 | if (hi - lo == 1) return std::min(function(lo), function(hi)); 48 | if (hi - lo == 2) return std::min(function(lo), std::min(function(lo + 1), function(hi))); 49 | int mid1 = (2 * lo + hi) / 3, mid2 = (lo + 2 * hi) / 3; 50 | double res1 = function(mid1), res2 = function(mid2); 51 | if (std::abs(res1 - res2) < 0.000000001) { 52 | lo = mid1; 53 | hi = mid2; 54 | } else if (res1 > res2) lo = mid1; 55 | else hi = mid2; 56 | } 57 | return lo; 58 | } 59 | 60 | }; 61 | 62 | 63 | // Example /usage of Ternary search discrete 64 | int TernarySearchDiscrete_test() 65 | { 66 | // Define your own function on whatever you're attempting to ternary 67 | // search. Remember that your function must be a discrete and a unimodal 68 | // function, this means a function which decreases then increases (U shape) 69 | std::vector func_coe{16, 12, 10, 3, 6, 7, 9, 10, 11, 12, 13, 17}; 70 | auto function = [&func_coe](int i) -> double { 71 | // A discrete function is just a set of data points. 72 | return func_coe[i]; 73 | }; 74 | 75 | int lo = 0; 76 | int hi = func_coe.size() - 1; 77 | 78 | // Use ternary search to find the minimum value on the 79 | // whole interval of out function. 80 | double minValue = TernarySearchDiscrete::discreteTernarySearch(lo, hi, function); 81 | std::cout << minValue << std::endl; 82 | 83 | return 0; 84 | } 85 | 86 | } // namespace dsa 87 | 88 | #endif /* D_TERNARYSEARCHDISCRETE_H */ 89 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/sorting/BubbleSort.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file BubbleSort.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 13 July 2020 6 | * @version 0.1 7 | * @brief Bubble sort implementation. 8 | */ 9 | 10 | #ifndef D_BUBBLESORT_H 11 | #define D_BUBBLESORT_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace dsa { 31 | 32 | class BubbleSort { 33 | public: 34 | static void sort(std::vector& values) { 35 | bubbleSort(values); 36 | } 37 | 38 | 39 | // Sort the array using bubble sort. The idea behind 40 | // bubble sort is to look for adjacent indexes which 41 | // are out of place and interchange their elements 42 | // until the entire array is sorted. 43 | private: 44 | static void bubbleSort(std::vector& ar) { 45 | if (ar.size() == 0) { 46 | return; 47 | } 48 | 49 | bool sorted; 50 | do { 51 | sorted = true; 52 | for (unsigned i = 1; i < ar.size(); i++) { 53 | if (ar[i] < ar[i - 1]) { 54 | swap(ar, i - 1, i); 55 | sorted = false; 56 | } 57 | } 58 | } while (!sorted); 59 | } 60 | 61 | 62 | static void swap(std::vector& ar, int i, int j) { 63 | int tmp = ar[i]; 64 | ar[i] = ar[j]; 65 | ar[j] = tmp; 66 | } 67 | }; 68 | 69 | 70 | // Example usage of Bubble Sort 71 | int BubbleSort_test() 72 | { 73 | std::vector array{10, 4, 6, 8, 13, 2, 3}; 74 | BubbleSort::sort(array); 75 | // Prints: 76 | // [2, 3, 4, 6, 8, 10, 13] 77 | std::cout << "["; 78 | for (auto a : array) std::cout << a << ","; 79 | std::cout << "]" << std::endl; 80 | return 0; 81 | } 82 | 83 | } // namespace dsa 84 | 85 | #endif /* D_BUBBLESORT_H */ 86 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/sorting/BucketSort.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file BucketSort.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 13 July 2020 6 | * @version 0.1 7 | * @brief Bucket sort implementation. 8 | */ 9 | 10 | #ifndef D_BUCKETSORT_H 11 | #define D_BUCKETSORT_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace dsa { 31 | 32 | class BucketSort { 33 | 34 | public: 35 | static void sort(std::vector& values) { 36 | const int POSITIVE_INFINITY = std::numeric_limits::infinity(); 37 | const int NEGATIVE_INFINITY = -std::numeric_limits::infinity(); 38 | int minValue = POSITIVE_INFINITY; 39 | int maxValue = NEGATIVE_INFINITY; 40 | for (unsigned i = 0; i < values.size(); i++) { 41 | if (values[i] < minValue) minValue = values[i]; 42 | if (values[i] > maxValue) maxValue = values[i]; 43 | } 44 | bucketSort(values, minValue, maxValue); 45 | } 46 | 47 | 48 | // Performs a bucket sort of an array in which all the elements are 49 | // bounded in the range [minValue, maxValue]. For bucket sort to give linear 50 | // performance the elements need to be uniformly distributed 51 | private: 52 | static void bucketSort(std::vector& ar, int minValue, int maxValue) { 53 | if (ar.size() == 0 || minValue == maxValue) return; 54 | 55 | // N is number elements and M is the range of values 56 | int N = ar.size(), M = maxValue - minValue + 1, numBuckets = M / N + 1; 57 | std::vector> buckets(numBuckets); 58 | 59 | // Place each element in a bucket 60 | for (int i = 0; i < N; i++) { 61 | int bi = (ar[i] - minValue) / M; 62 | buckets[bi].push_back(ar[i]); 63 | } 64 | 65 | // Sort buckets and stitch together answer 66 | for (int bi = 0, j = 0; bi < numBuckets; bi++) { 67 | if (buckets[bi].size() != 0) { 68 | std::sort(buckets[bi].begin(), buckets[bi].end()); 69 | for (unsigned k = 0; k < buckets[bi].size(); k++) { 70 | ar[j++] = buckets[bi][k]; 71 | } 72 | } 73 | } 74 | } 75 | 76 | }; 77 | 78 | 79 | // Example usage of Bucket Sort 80 | int BucketSort_test() 81 | { 82 | std::vector array{10, 4, 6, 8, 13, 2, 3}; 83 | BucketSort::sort(array); 84 | // Prints: 85 | // [2, 3, 4, 6, 8, 10, 13] 86 | std::cout << "["; 87 | for (auto a : array) std::cout << a << ","; 88 | std::cout << "]" << std::endl; 89 | 90 | 91 | array = std::vector{10, 10, 10, 10, 10}; 92 | BucketSort::sort(array); 93 | // Prints: 94 | // [10, 10, 10, 10, 10] 95 | std::cout << "["; 96 | for (auto a : array) std::cout << a << ","; 97 | std::cout << "]" << std::endl; 98 | 99 | return 0; 100 | } 101 | 102 | 103 | } // namespace dsa 104 | 105 | #endif /* D_BUCKETSORT_H */ 106 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/sorting/CountingSort.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file CountingSort.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 13 July 2020 6 | * @version 0.1 7 | * @brief Counting sort implementation. 8 | */ 9 | 10 | #ifndef D_COUNTINGSORT_H 11 | #define D_COUNTINGSORT_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace dsa { 31 | 32 | 33 | class CountingSort { 34 | 35 | public: 36 | static void sort(std::vector& values) { 37 | const int POSITIVE_INFINITY = std::numeric_limits::infinity(); 38 | const int NEGATIVE_INFINITY = -std::numeric_limits::infinity(); 39 | int minValue = POSITIVE_INFINITY; 40 | int maxValue = NEGATIVE_INFINITY; 41 | for (unsigned i = 0; i < values.size(); i++) { 42 | if (values[i] < minValue) minValue = values[i]; 43 | if (values[i] > maxValue) maxValue = values[i]; 44 | } 45 | countingSort(values, minValue, maxValue); 46 | } 47 | 48 | 49 | private: 50 | // Sorts values in the range of [minVal, maxVal] in O(n+maxVal-maxVal) 51 | static void countingSort(std::vector& ar, int minVal, int maxVal) { 52 | int sz = maxVal - minVal + 1; 53 | std::vector b(sz, 0); 54 | for (unsigned i = 0; i < ar.size(); i++) b[ar[i] - minVal]++; 55 | for (int i = 0, k = 0; i < sz; i++) { 56 | while (b[i]-- > 0) ar[k++] = i + minVal; 57 | } 58 | } 59 | 60 | }; 61 | 62 | 63 | // Example usage of Counting Sort 64 | int CountingSort_test() 65 | { 66 | std::vector nums{+4, -10, +0, +6, +1, -5, -5, +1, +1, -2, 0, +6, +8, -7, +10}; 67 | CountingSort::sort(nums); 68 | 69 | // Prints: 70 | // [-10, -7, -5, -5, -2, 0, 0, 1, 1, 1, 4, 6, 6, 8, 10] 71 | std::cout << "["; 72 | for (auto a : nums) std::cout << a << ","; 73 | std::cout << "]" << std::endl; 74 | 75 | return 0; 76 | } 77 | 78 | 79 | } // namespace dsa 80 | 81 | #endif /* D_COUNTINGSORT_H */ 82 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/sorting/Heapsort.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file Heapsort.h 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 13 July 2020 6 | * @version 0.1 7 | * @brief Heap sort implementation. 8 | */ 9 | 10 | #ifndef D_HEAPSORT_H 11 | #define D_HEAPSORT_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include // set and multiset 17 | #include // map and multimap 18 | #include // unordered set/multiset 19 | #include // unordered map/multimap 20 | #include 21 | #include 22 | #include // some numeric algorithm 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace dsa { 31 | 32 | class Heapsort { 33 | 34 | public: 35 | static void sort(std::vector& values) { 36 | heapsort(values); 37 | } 38 | 39 | 40 | private: 41 | static void heapsort(std::vector& ar) { 42 | if (ar.size() == 0) return; 43 | int n = ar.size(); 44 | 45 | // Heapify, converts array into binary heap O(n), see: 46 | // http://www.cs.umd.edu/~meesh/351/mount/lectures/lect14-heapsort-analysis-part.pdf 47 | for (int i = std::max(0, (n / 2) - 1); i >= 0; i--) { 48 | sink(ar, n, i); 49 | } 50 | 51 | // Sorting bit 52 | for (int i = n - 1; i >= 0; i--) { 53 | swap(ar, 0, i); 54 | sink(ar, i, 0); 55 | } 56 | } 57 | 58 | 59 | static void sink(std::vector& ar, int n, int i) { 60 | while (true) { 61 | int left = 2 * i + 1; // Left node 62 | int right = 2 * i + 2; // Right node 63 | int largest = i; 64 | 65 | // Right child is larger than parent 66 | if (right < n && ar[right] > ar[largest]) largest = right; 67 | 68 | // Left child is larger than parent 69 | if (left < n && ar[left] > ar[largest]) largest = left; 70 | 71 | // Move down the tree following the largest node 72 | if (largest != i) { 73 | swap(ar, largest, i); 74 | i = largest; 75 | } else break; 76 | } 77 | } 78 | 79 | 80 | static void swap(std::vector& ar, int i, int j) { 81 | int tmp = ar[i]; 82 | ar[i] = ar[j]; 83 | ar[j] = tmp; 84 | } 85 | 86 | }; 87 | 88 | 89 | // Example usage of Heap Sort 90 | int HeapSort_test() 91 | { 92 | std::vector array{10, 4, 6, 4, 8, -13, 2, 3}; 93 | Heapsort::sort(array); 94 | // Prints: 95 | // [-13, 2, 3, 4, 4, 6, 8, 10] 96 | std::cout << "["; 97 | for (auto a : array) std::cout << a << ","; 98 | std::cout << "]" << std::endl; 99 | 100 | return 0; 101 | } 102 | 103 | } // namespace dsa 104 | 105 | #endif /* D_HEAPSORT_H */ 106 | -------------------------------------------------------------------------------- /src/main/cpp/algorithms/sorting/QuickSort3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @file QuickSort3.h 3 | * @author (original JAVA) Atharva Thorve, aaathorve@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 13 July 2020 6 | * @version 0.1 7 | * @brief Quick sort implementation. 8 | * QuickSort3 or Dutch National Flag algorithm is similar to the QuickSort algorithm but has an 9 | * improved partitioning algorithm. QuickSort is quite slow in the case where very few unique 10 | * elements exist in the array so the QuickSort3 algorithm is used at that time. 11 | */ 12 | 13 | #ifndef D_QUICK3SORT_H 14 | #define D_QUICK3SORT_H 15 | 16 | #include 17 | #include 18 | #include 19 | #include // set and multiset 20 | #include // map and multimap 21 | #include // unordered set/multiset 22 | #include // unordered map/multimap 23 | #include 24 | #include 25 | #include // some numeric algorithm 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace dsa { 36 | 37 | class QuickSort3 { 38 | 39 | public: 40 | static void sort(std::vector& values) { 41 | if (values.size() == 0) return; 42 | randomizedQuickSort(values, 0, values.size() - 1); 43 | } 44 | 45 | 46 | private: 47 | 48 | static int genRandInt(int start_in, int end_in) 49 | { 50 | // engine only provides a source of randomness 51 | std::mt19937_64 rng; 52 | // initialize the random number generator with time-dependent seed 53 | uint64_t timeSeed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 54 | std::seed_seq ss{uint32_t(timeSeed & 0xffffffff), uint32_t(timeSeed>>32)}; 55 | rng.seed(ss); 56 | std::uniform_int_distribution dist(start_in, end_in); 57 | 58 | return dist(rng); 59 | } 60 | 61 | 62 | // partiton array in such a way that all the elements whose value is equal to 63 | // pivot are grouped together 64 | static std::vector partition3(std::vector& a, int l, int r) { 65 | int j, k; 66 | if (r - l <= 1) { 67 | if (a[r] < a[l]) { 68 | swap(a, l, r); 69 | } 70 | j = l; 71 | k = r; 72 | std::vector m{j, k}; 73 | return std::move(m); 74 | } 75 | int mid = l; 76 | int p = a[r]; 77 | while (mid <= r) { 78 | if (a[mid] < p) { 79 | swap(a, l, mid); 80 | l++; 81 | mid++; 82 | } else if (a[mid] == p) { 83 | mid++; 84 | } else { 85 | swap(a, mid, r); 86 | r--; 87 | } 88 | } 89 | j = l - 1; 90 | k = mid; 91 | std::vector m{j, k}; 92 | return std::move(m); 93 | } 94 | 95 | 96 | // Sort interval [lo, hi] inplace recursively 97 | // This chooses random pivot value thus improving time complexity 98 | static void randomizedQuickSort(std::vector& a, int l, int r) { 99 | if (l >= r) { 100 | return; 101 | } 102 | int k = genRandInt(0, r - l + 1) + l; 103 | int t = a[l]; 104 | a[l] = a[k]; 105 | a[k] = t; 106 | // use partition3 107 | std::vector m = partition3(a, l, r); 108 | randomizedQuickSort(a, l, m[0]); 109 | randomizedQuickSort(a, m[1], r); 110 | } 111 | 112 | 113 | // Swap two elements 114 | static void swap(std::vector& ar, int i, int j) { 115 | int tmp = ar[i]; 116 | ar[i] = ar[j]; 117 | ar[j] = tmp; 118 | } 119 | 120 | }; 121 | 122 | 123 | // Example usage of Quick3 Sort 124 | int Quick3Sort_test() 125 | { 126 | std::vector array = {10, 4, 6, 4, 8, -13, 2, 3}; 127 | QuickSort3::sort(array); 128 | // Prints: 129 | // [-13, 2, 3, 4, 4, 6, 8, 10] 130 | std::cout << "["; 131 | for (auto a : array) std::cout << a << ","; 132 | std::cout << "]" << std::endl; 133 | 134 | return 0; 135 | } 136 | 137 | 138 | } // namespace dsa 139 | 140 | #endif /* D_QUICK3SORT_H */ 141 | -------------------------------------------------------------------------------- /src/main/python/algorithms/datastructures/queue/ArrayQueue.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file ArrayStack.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * liujingkun, liujkon@gmail.com 5 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 6 | * @date 22 Jun 2020 7 | * @version 0.1 8 | * @brief An array implementation of a queue. 9 | ''' 10 | 11 | from Queue import Queue 12 | 13 | class ArrayQueue(Queue): 14 | ''' 15 | An array implementation of a stack 16 | ''' 17 | def __init__(self, obj, capacity): 18 | self.qSize = 0 19 | self.data = [obj for i in range(capacity)] 20 | self.front = 0 21 | self.rear = 0 22 | 23 | 24 | def size(self): 25 | return self.adjustIndex(self.rear + len(self.data) - self.front, len(self.data)) 26 | 27 | 28 | def offer(self, elem): 29 | if self.isFull(): 30 | raise Exception('Queue is full') 31 | 32 | self.data[self.rear] = elem 33 | self.rear += 1 34 | self.rear = self.adjustIndex(self.rear, len(self.data)) 35 | 36 | 37 | def poll(self): 38 | if self.isEmpty(): 39 | raise Exception('Queue is empty') 40 | self.front = self.adjustIndex(self.front, len(self.data)) 41 | d = self.data[self.front] 42 | self.front += 1 43 | return d 44 | 45 | 46 | def peek(self): 47 | if self.isEmpty(): 48 | raise Exception('Queue is empty') 49 | self.front = self.adjustIndex(self.front, len(self.data)) 50 | return self.data[self.front] 51 | 52 | 53 | def isEmpty(self): 54 | return self.rear == self.front 55 | 56 | 57 | def isFull(self): 58 | return (self.front + len(self.data) - self.rear) % len(self.data) == 1 59 | 60 | 61 | def adjustIndex(self, index, size): 62 | return index - size if index >= size else index 63 | 64 | 65 | if __name__ == '__main__': 66 | q = ArrayQueue(0, 6) 67 | 68 | q.offer(1); 69 | q.offer(2); 70 | q.offer(3); 71 | q.offer(4); 72 | q.offer(5); 73 | 74 | print(q.poll()) # 1 75 | print(q.poll()) # 2 76 | print(q.poll()) # 3 77 | print(q.poll()) # 4 78 | 79 | print(q.isEmpty()) # false 80 | 81 | q.offer(1) 82 | q.offer(2) 83 | q.offer(3) 84 | 85 | print(q.poll()) # 5 86 | print(q.poll()) # 1 87 | print(q.poll()) # 2 88 | print(q.poll()) # 3 89 | 90 | print(q.isEmpty()) # true 91 | -------------------------------------------------------------------------------- /src/main/python/algorithms/datastructures/queue/IntQueue.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file IntQueue.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * liujingkun, liujkon@gmail.com 5 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 6 | * @date 23 Jun 2020 7 | * @version 0.1 8 | * @brief This file contains an implementation of an integer only queue. 9 | * 10 | ''' 11 | 12 | import time 13 | from array import array as arr 14 | from collections import deque 15 | from Queue import Queue 16 | 17 | 18 | class IntQueue(Queue): 19 | ''' 20 | An integer only implementation of a queue 21 | ''' 22 | def __init__(self, maxSize): 23 | """ 24 | maxSize is the maximum number of items 25 | that can be in the queue at any given time 26 | """ 27 | self.front = 0 28 | self.end = 0 29 | self.qSize = 0 30 | self.data = arr('i', (0 for i in range(maxSize))) 31 | 32 | 33 | def isEmpty(self): 34 | """ 35 | Return true/false on whether the queue is empty 36 | """ 37 | return self.qSize == 0 38 | 39 | 40 | def size(self): 41 | """ 42 | Return the number of elements inside the queue 43 | """ 44 | return self.qSize 45 | 46 | 47 | def peek(self): 48 | if self.isEmpty(): 49 | raise Exception('Queue is empty') 50 | 51 | self.front = self.front % len(self.data) 52 | return self.data[self.front] 53 | 54 | 55 | def isFull(self): 56 | return self.qSize == len(self.data) 57 | 58 | 59 | def offer(self, value): 60 | """ 61 | Add an element to the queue 62 | """ 63 | if self.isFull(): 64 | raise Exception("Queue too small!") 65 | 66 | self.data[self.end] = value 67 | self.end += 1 68 | self.qSize += 1 69 | self.end = self.end % len(self.data) 70 | 71 | 72 | def poll(self): 73 | """ 74 | Make sure you check is the queue is not empty before calling poll! 75 | """ 76 | if self.isEmpty(): 77 | raise Exception('Queue is empty') 78 | 79 | self.qSize -= 1 80 | self.front = self.front % len(self.data) 81 | d = self.data[self.front] 82 | self.front += 1 83 | return d 84 | 85 | 86 | 87 | def benchMarkTest(): 88 | """ 89 | BenchMark IntQueue vs ArrayDeque. 90 | """ 91 | 92 | n = 10000000 93 | intQ = IntQueue(n) 94 | 95 | # IntQueue times at around 12.109375 seconds 96 | start = time.process_time() 97 | for i in range(0, n): 98 | intQ.offer(i) 99 | for i in range(0, n): 100 | intQ.poll() 101 | end = time.process_time() 102 | print("IntQueue Time: ", (end - start)) 103 | 104 | # ArrayDeque times at around 1.1875 seconds 105 | arrayDeque = deque() 106 | start = time.process_time() 107 | for i in range(0, n): 108 | arrayDeque.append(i) 109 | for i in range(0, n): 110 | arrayDeque.popleft() 111 | end = time.process_time() 112 | print("ArrayDeque Time: ", (end - start)) 113 | 114 | 115 | 116 | if __name__ == '__main__': 117 | """ 118 | Example usage 119 | """ 120 | 121 | q = IntQueue(5) 122 | 123 | q.offer(1) 124 | q.offer(2) 125 | q.offer(3) 126 | q.offer(4) 127 | q.offer(5) 128 | 129 | print(q.poll()) # 1 130 | print(q.poll()) # 2 131 | print(q.poll()) # 3 132 | print(q.poll()) # 4 133 | 134 | print(q.isEmpty()) # false 135 | 136 | q.offer(1); 137 | q.offer(2); 138 | q.offer(3); 139 | 140 | print(q.poll()) # 5 141 | print(q.poll()) # 1 142 | print(q.poll()) # 2 143 | print(q.poll()) # 3 144 | 145 | print(q.isEmpty()) # true 146 | 147 | benchMarkTest() 148 | -------------------------------------------------------------------------------- /src/main/python/algorithms/datastructures/queue/LinkedQueue.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file LinkedQueue.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 23 Jun 2020 6 | * @version 0.1 7 | * @brief A simple queue implementation with a linkedlist. 8 | ''' 9 | 10 | from Queue import Queue 11 | from DoublyLinkedList import DoublyLinkedList 12 | 13 | class LinkedQueue(Queue): 14 | ''' 15 | A linked list implementation of a queue 16 | ''' 17 | def __init__(self): 18 | self.list = DoublyLinkedList() 19 | self.iterList = iter(self.list) 20 | 21 | 22 | def size(self): 23 | """ 24 | Return the size of the queue 25 | """ 26 | return self.list.size() 27 | 28 | 29 | def isEmpty(self): 30 | """ 31 | Returns whether or not the queue is empty 32 | """ 33 | return self.size() == 0 34 | 35 | 36 | def peek(self): 37 | """ 38 | Peek the element at the front of the queue 39 | The method throws an error is the queue is empty 40 | """ 41 | if self.isEmpty(): 42 | raise Exception('Queue Empty') 43 | return self.list.peekFirst() 44 | 45 | 46 | def poll(self): 47 | """ 48 | Poll an element from the front of the queue 49 | The method throws an error is the queue is empty 50 | """ 51 | if self.isEmpty(): 52 | raise Exception('Queue Empty') 53 | return self.list.removeFirst() 54 | 55 | 56 | def offer(self, elem): 57 | """ 58 | Add an element to the back of the queue 59 | """ 60 | self.list.addLast(elem) 61 | 62 | 63 | def __iter__(self): 64 | """ 65 | Called when iteration is initialized 66 | 67 | Return an iterator to allow the user to traverse 68 | through the elements found inside the queue 69 | """ 70 | self.iterList = iter(self.list) 71 | return self 72 | 73 | 74 | def __next__(self): 75 | """ 76 | To move to next element. 77 | """ 78 | return next(self.iterList) 79 | 80 | 81 | if __name__ == '__main__': 82 | q = LinkedQueue() 83 | 84 | q.offer(1); 85 | q.offer(2); 86 | q.offer(3); 87 | q.offer(4); 88 | q.offer(5); 89 | 90 | print(q.poll()) # 1 91 | print(q.poll()) # 2 92 | print(q.poll()) # 3 93 | print(q.poll()) # 4 94 | 95 | print(q.isEmpty()) # false 96 | 97 | q.offer(1) 98 | q.offer(2) 99 | q.offer(3) 100 | 101 | print(q.poll()) # 5 102 | print(q.poll()) # 1 103 | print(q.poll()) # 2 104 | print(q.poll()) # 3 105 | 106 | print(q.isEmpty()) # true 107 | -------------------------------------------------------------------------------- /src/main/python/algorithms/datastructures/queue/Queue.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file Queue.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * liujingkun, liujkon@gmail.com 5 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 6 | * @date 23 Jun 2020 7 | * @version 0.1 8 | * @brief An abstract base class for queue. 9 | ''' 10 | 11 | from abc import ABC,abstractmethod 12 | 13 | 14 | class Queue(ABC): 15 | 16 | @abstractmethod 17 | def offer(self, elem): 18 | pass 19 | 20 | @abstractmethod 21 | def poll(self): 22 | pass 23 | 24 | @abstractmethod 25 | def peek(self): 26 | pass 27 | 28 | @abstractmethod 29 | def size(self): 30 | pass 31 | 32 | @abstractmethod 33 | def isEmpty(self): 34 | pass 35 | -------------------------------------------------------------------------------- /src/main/python/algorithms/datastructures/stack/ArrayStack.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file ArrayStack.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * liujingkun 5 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 6 | * @date 22 Jun 2020 7 | * @version 0.1 8 | * @brief An array implementation of a stack. 9 | ''' 10 | 11 | import sys 12 | from Stack import Stack 13 | 14 | 15 | class ArrayStack(Stack): 16 | ''' 17 | An array implementation of a stack 18 | ''' 19 | def __init__(self, obj): 20 | self.stkSize = 0 21 | # self.capacity = 16 22 | self.data = [] #[obj for i in range(self.capacity)] 23 | self.initSize = sys.getsizeof(self.data) 24 | 25 | 26 | 27 | def size(self): 28 | return self.stkSize 29 | 30 | 31 | def isEmpty(self): 32 | return self.stkSize == 0 33 | 34 | 35 | def push(self, elem): 36 | self.data.append(elem) 37 | self.stkSize += 1 38 | spaceLeft = ((sys.getsizeof(self.data) - self.initSize) - len(self.data) * 8) // 8 39 | print("space left after append: ", spaceLeft) 40 | 41 | 42 | def pop(self): 43 | if self.isEmpty(): 44 | raise Exception('Empty Stack') 45 | self.stkSize -= 1 46 | elem = self.data[self.stkSize] 47 | 48 | # spaceLeft = ((sys.getsizeof(self.data) - self.initSize) - len(self.data) * 8) // 8 49 | # print("space left before pop: ", spaceLeft) 50 | 51 | # self.data[self.stkSize] = None 52 | elem = self.data.pop(self.stkSize) 53 | 54 | # spaceLeft = ((sys.getsizeof(self.data) - self.initSize) - len(self.data) * 8) // 8 55 | # print("space left after pop: ", spaceLeft) 56 | 57 | return elem 58 | 59 | 60 | def peek(self): 61 | if self.isEmpty(): 62 | raise Exception('Empty Stack') 63 | 64 | return self.data[self.stkSize - 1] 65 | 66 | 67 | if __name__ == '__main__': 68 | """ 69 | Example usage 70 | """ 71 | 72 | s = ArrayStack(5) 73 | 74 | s.push(1) 75 | s.push(2) 76 | s.push(3) 77 | s.push(4) 78 | s.push(5) 79 | 80 | print(s.pop()) # 5 81 | print(s.pop()) # 4 82 | print(s.pop()) # 3 83 | 84 | s.push(3) 85 | s.push(4) 86 | s.push(5) 87 | 88 | while s.isEmpty() is False: 89 | print(s.pop()) 90 | 91 | -------------------------------------------------------------------------------- /src/main/python/algorithms/datastructures/stack/IntStack.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file IntStack.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 23 Jun 2020 6 | * @version 0.1 7 | * @brief An integer implementation of a stack. 8 | * This file contains an implementation of an integer only stack which is extremely quick and 9 | * lightweight. 10 | ''' 11 | 12 | import time 13 | from collections import deque 14 | from queue import LifoQueue 15 | from ListStack import ListStack 16 | from ArrayStack import ArrayStack 17 | from array import array as arr 18 | from Stack import Stack 19 | 20 | 21 | class IntStack(Stack): 22 | ''' 23 | An integer implementation of a stack 24 | ''' 25 | def __init__(self, maxSize): 26 | ''' 27 | maxSize is the maximum number of items 28 | that can be in the queue at any given time 29 | ''' 30 | self.pos = 0 31 | self.ar = arr('i', (0 for i in range(maxSize))) 32 | 33 | 34 | def size(self): 35 | """ 36 | Returns the number of elements insize the stack 37 | """ 38 | return self.pos 39 | 40 | 41 | def isEmpty(self): 42 | """ 43 | Returns true/false on whether the stack is empty 44 | """ 45 | return self.pos == 0 46 | 47 | 48 | def peek(self): 49 | if self.isEmpty(): 50 | raise Exception('Empty Stack') 51 | return self.ar[self.pos - 1] 52 | 53 | 54 | def push(self, value): 55 | """ 56 | Add an element to the top of the stack 57 | """ 58 | self.ar[self.pos] = value 59 | self.pos += 1 60 | 61 | 62 | def pop(self): 63 | """ 64 | Make sure you check that the stack is not empty before calling pop! 65 | """ 66 | if self.isEmpty(): 67 | raise Exception('Empty Stack') 68 | self.pos -= 1 69 | return self.ar[self.pos] 70 | 71 | 72 | def benchMarkTest(): 73 | """ 74 | BenchMark IntStack vs Python deque. 75 | """ 76 | n = 10000000 77 | intStack = IntStack(n) 78 | 79 | 80 | # Implemenation using IntStack module (5.046 sec) 81 | start = time.process_time() 82 | for i in range(0, n): 83 | intStack.push(i) 84 | for i in range(0, n): 85 | intStack.pop() 86 | end = time.process_time() 87 | print("IntStack Time: ", (end - start)) 88 | 89 | 90 | 91 | # Implemenation using ListStack module (29.609375 sec) 92 | listStack = ListStack() 93 | start = time.process_time() 94 | for i in range(0, n): 95 | listStack.push(i) 96 | for i in range(0, n): 97 | listStack.pop() 98 | end = time.process_time() 99 | print("ListStack Time: ", (end - start)) 100 | 101 | 102 | 103 | 104 | # Implemenation using ArrayStack module (7.09375 sec) 105 | arrayStack = ArrayStack(0) 106 | start = time.process_time() 107 | for i in range(0, n): 108 | arrayStack.push(i) 109 | for i in range(0, n): 110 | arrayStack.pop() 111 | end = time.process_time() 112 | print("ArrayStack Time: ", (end - start)) 113 | 114 | 115 | 116 | # Implementation using collections.deque (1.28125 sec) 117 | # Python stack can be implemented using deque class from collections module. 118 | # Deque is preferred over list in the cases where we need quicker append and 119 | # pop operations from both the ends of the container, as deque provides an O(1) 120 | # time complexity for append and pop operations as compared to list which 121 | # provides O(n) time complexity. 122 | # Same methods on deque as seen in list are used, append() and pop(). 123 | stackDeque = deque() 124 | # deque is slower when you give it an initial capacity. 125 | start = time.process_time() 126 | for i in range(0, n): 127 | stackDeque.append(i) 128 | for i in range(0, n): 129 | stackDeque.pop() 130 | end = time.process_time() 131 | print("DequeStack Time: ", (end - start)) 132 | 133 | 134 | 135 | # Implemenation using queue module (33.765625 sec) 136 | # Queue module also has a LIFO Queue, which is basically a Stack. Data is 137 | # inserted into Queue using put() function and get() takes data out from the Queue. 138 | lifoStack = LifoQueue(maxsize = n) 139 | start = time.process_time() 140 | for i in range(0, n): 141 | lifoStack.put(i) 142 | for i in range(0, n): 143 | lifoStack.get() 144 | end = time.process_time() 145 | print("LIFOStack Time: ", (end - start)) 146 | 147 | 148 | 149 | if __name__ == '__main__': 150 | """ 151 | Example usage 152 | """ 153 | 154 | s = IntStack(5) 155 | 156 | s.push(1) 157 | s.push(2) 158 | s.push(3) 159 | s.push(4) 160 | s.push(5) 161 | 162 | print(s.pop()) # 5 163 | print(s.pop()) # 4 164 | print(s.pop()) # 3 165 | 166 | s.push(3) 167 | s.push(4) 168 | s.push(5) 169 | 170 | while s.isEmpty() is False: 171 | print(s.pop()) 172 | 173 | benchMarkTest() 174 | -------------------------------------------------------------------------------- /src/main/python/algorithms/datastructures/stack/ListStack.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file ListStack.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 22 Jun 2020 6 | * @version 0.1 7 | * @brief A linked list implementation of a stack. 8 | ''' 9 | 10 | from Stack import Stack 11 | from DoublyLinkedList import DoublyLinkedList 12 | 13 | class ListStack(Stack): 14 | ''' 15 | A linked list implementation of a stack 16 | ''' 17 | def __init__(self): 18 | self.list = DoublyLinkedList() 19 | self.iterList = iter(self.list) 20 | 21 | 22 | def size(self): 23 | ''' 24 | Return the number of elements in the stack 25 | ''' 26 | return self.list.size() 27 | 28 | 29 | def isEmpty(self): 30 | """ 31 | Check if the stack is empty 32 | """ 33 | return self.size() == 0 34 | 35 | 36 | def push(self, elem): 37 | """ 38 | Push an element on the stack 39 | """ 40 | self.list.addLast(elem) 41 | 42 | 43 | def pop(self): 44 | """ 45 | Pop an element off the stack 46 | Throws an error is the stack is empty 47 | """ 48 | if self.isEmpty(): 49 | raise Exception('Empty Stack') 50 | return self.list.removeLast() 51 | 52 | 53 | def peek(self): 54 | """ 55 | Peek the top of the stack without removing an element 56 | Throws an exception if the stack is empty 57 | """ 58 | if self.isEmpty(): 59 | raise Exception('Empty Stack') 60 | return self.list.peekLast() 61 | 62 | 63 | def __iter__(self): 64 | """ 65 | Called when iteration is initialized 66 | """ 67 | self.iterList = iter(self.list) 68 | return self 69 | 70 | 71 | def __next__(self): 72 | """ 73 | To move to next element. 74 | """ 75 | return next(self.iterList) 76 | -------------------------------------------------------------------------------- /src/main/python/algorithms/datastructures/stack/Stack.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file Stack.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 22 Jun 2020 6 | * @version 0.1 7 | * @brief An abstract base class for stack. 8 | ''' 9 | 10 | from abc import ABC,abstractmethod 11 | 12 | 13 | class Stack(ABC): 14 | 15 | @abstractmethod 16 | def size(self): 17 | """ 18 | return the number of elements in the stack 19 | """ 20 | pass 21 | 22 | 23 | @abstractmethod 24 | def isEmpty(self): 25 | """ 26 | return if the stack is empty 27 | """ 28 | pass 29 | 30 | 31 | @abstractmethod 32 | def push(self, elem): 33 | """ 34 | push the element on the stack 35 | """ 36 | pass 37 | 38 | 39 | @abstractmethod 40 | def pop(self): 41 | """ 42 | pop the element off the stack 43 | """ 44 | pass 45 | 46 | 47 | @abstractmethod 48 | def peek(self): 49 | """ 50 | """ 51 | pass 52 | -------------------------------------------------------------------------------- /src/main/python/algorithms/other/BitManipulations.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file BitManipulations.py 3 | * @author (original JAVA) Micah Stairs 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief B 8 | * Fundamental bit manipulation operations you must know Time Complexity: O(1) 9 | ''' 10 | 11 | class BitManipulations(): 12 | 13 | def __init__(self): 14 | pass 15 | 16 | 17 | def setBit(self, set, i): 18 | """ 19 | Sets the i'th bit to 1 20 | """ 21 | return set | (1 << i) 22 | 23 | 24 | def isSet(self, set, i): 25 | """ 26 | Checks if the i'th is set 27 | """ 28 | return (set & (1 << i)) != 0 29 | 30 | 31 | def clearBit(self, set, i): 32 | """ 33 | Sets the i'th bit to zero 34 | """ 35 | return set & ~(1 << i) 36 | 37 | 38 | def toggleBit(self, set, i): 39 | """ 40 | Toggles the i'th bit from 0 -> 1 or 1 -> 0 41 | """ 42 | return set ^ (1 << i) 43 | 44 | 45 | def setAll(self, n): 46 | """ 47 | Returns a number with the first n bits set to 1 48 | """ 49 | return (1 << n) - 1 50 | 51 | 52 | def isPowerOfTwo(self, n): 53 | """ 54 | Verifies if a number n is a power of two 55 | """ 56 | return n > 0 and (n & (n - 1)) == 0 57 | -------------------------------------------------------------------------------- /src/main/python/algorithms/other/Combinations.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file Combinations.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief Combinations implementation 8 | * Here we present two methods (recursive and iterative) of generating all the combinations of a set 9 | * by choosing only r of n elements. 10 | * 11 | *

Time Complexity: O( n choose r ) 12 | ''' 13 | 14 | import math 15 | 16 | class Combinations(): 17 | 18 | def __init__(self): 19 | pass 20 | 21 | def combinationsChooseR(self, set, r): 22 | """ 23 | This method finds all the combinations of size r in a set 24 | """ 25 | 26 | if r < 0: 27 | return 28 | if set == None: 29 | return 30 | 31 | used = [False]*len(set) 32 | self.combinations(set, r, 0, used) 33 | 34 | 35 | def combinations(self, set, r, at, used): 36 | """ 37 | To find all the combinations of size r we need to recurse until we have 38 | selected r elements (aka r = 0), otherwise if r != 0 then we need to select 39 | an element which is found after the position of our last selected element 40 | """ 41 | 42 | N = len(set) 43 | 44 | # Return early if there are more elements left to select than what is available. 45 | elementsLeftToPick = N - at 46 | if elementsLeftToPick < r: 47 | return 48 | 49 | # We selected 'r' elements so we found a valid subset! 50 | if r == 0: 51 | print("{ ", end = '') 52 | for i in range(0, N): 53 | if used[i]: 54 | print('{} '.format(set[i]), end = '') 55 | print("}") 56 | 57 | else: 58 | 59 | for i in range(at, N): 60 | 61 | # Try including this element 62 | used[i] = True 63 | 64 | self.combinations(set, r - 1, i + 1, used) 65 | 66 | # Backtrack and try the instance where we did not include this element 67 | used[i] = False 68 | 69 | 70 | def nextCombination(self, selection, N, r): 71 | """ 72 | Use this method in combination with a do while loop to generate all the combinations 73 | of a set choosing r elements in a iterative fashion. This method returns 74 | false once the last combination has been generated. 75 | NOTE: Originally the selection needs to be initialized to {0,1,2,3 ... r-1} 76 | """ 77 | if r > N: 78 | raise Exception("r must be <= N") 79 | i = r - 1 80 | while selection[i] == N - r + i: 81 | i -= 1 82 | if i < 0: 83 | return False 84 | selection[i] += 1 85 | for j in range(i + 1, r): 86 | selection[j] = selection[i] + j - i 87 | return True 88 | 89 | 90 | 91 | 92 | if __name__ == '__main__': 93 | """ 94 | Example usage 95 | """ 96 | 97 | c = Combinations() 98 | 99 | # Recursive approach 100 | R = 3 101 | set = [1, 2, 3, 4, 5] 102 | c.combinationsChooseR(set, R) 103 | # prints: 104 | # { 1 2 3 } 105 | # { 1 2 4 } 106 | # { 1 2 5 } 107 | # { 1 3 4 } 108 | # { 1 3 5 } 109 | # { 1 4 5 } 110 | # { 2 3 4 } 111 | # { 2 3 5 } 112 | # { 2 4 5 } 113 | # { 3 4 5 } 114 | 115 | # Suppose we want to select all combinations of colors where R = 3 116 | colors = ["red", "purple", "green", "yellow", "blue", "pink"] 117 | R = 3 118 | 119 | # Initialize the selection to be {0, 1, ... , R-1} 120 | selection = [0, 1, 2] 121 | while True: 122 | 123 | # Print each combination 124 | for index in selection: 125 | print('{} '.format(colors[index]), end = '') 126 | print() 127 | 128 | if not c.nextCombination(selection, len(colors), R): 129 | break 130 | # prints: 131 | # red purple green 132 | # red purple yellow 133 | # red purple blue 134 | # red purple pink 135 | # red green yellow 136 | # red green blue 137 | # red green pink 138 | # red yellow blue 139 | # red yellow pink 140 | # red blue pink 141 | # purple green yellow 142 | # purple green blue 143 | # purple green pink 144 | # purple yellow blue 145 | # purple yellow pink 146 | # purple blue pink 147 | # green yellow blue 148 | # green yellow pink 149 | # green blue pink 150 | # yellow blue pink 151 | -------------------------------------------------------------------------------- /src/main/python/algorithms/other/CombinationsWithRepetition.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file CombinationsWithRepetition.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief Combinations implementation 8 | * Here I show how you can generate all the combinations of a sequence of size r which are repeated 9 | * at most k times. 10 | * 11 | *

Time Complexity: O(n+r-1 choose r) = O((n+r-1)!/(r!(n-1)!)) 12 | ''' 13 | 14 | import math 15 | 16 | class CombinationsWithRepetition(): 17 | 18 | def __init__(self): 19 | pass 20 | 21 | 22 | def combinationsWithRepetition(self, sequence, usedCount, at, r, k): 23 | """ 24 | * Computes all combinations of elements of 'r' elements which can be repeated at most 'k' times 25 | * each. 26 | * 27 | * @param sequence - The sequence containing all the elements we wish to take combinations from 28 | * @param usedCount - Tracks how many of each element we currently have selected 29 | * @param at - The current position we're at in the sequence 30 | * @param r - The number of elements we're choosing 31 | * @param k - The maximum number of times each element is allowed to be picked 32 | """ 33 | 34 | N = len(sequence) 35 | 36 | # We reached the end 37 | if at == N: 38 | 39 | # We selected 'r' elements in total 40 | if r == 0: 41 | 42 | # Print combination 43 | print("{ ", end = '') 44 | for i in range(0, N): 45 | for j in range(0, usedCount[i]): 46 | print('{} '.format(sequence[i]), end = '') 47 | print("}") 48 | 49 | 50 | else: 51 | 52 | # For this particular time at position 'at' try including it each of [0, k] times 53 | for itemCount in range(0, k+1): 54 | 55 | # Try including this element itemCount number of times (this is possibly more than once) 56 | usedCount[at] = itemCount 57 | 58 | self.combinationsWithRepetition(sequence, usedCount, at + 1, r - itemCount, k) 59 | 60 | 61 | 62 | def printCombinationsWithRepetition(self, sequence, r, k): 63 | """ 64 | Given a sequence this method prints all the combinations of size 65 | 'r' in a given sequence which has each element repeated at most 'k' times 66 | """ 67 | if sequence == None: 68 | return 69 | n = len(sequence) 70 | if r > n: 71 | raise Exception("r must be <= n") 72 | if k > r: 73 | raise Exception("k must be <= r") 74 | 75 | usedCount = [0]*len(sequence) 76 | self.combinationsWithRepetition(sequence, usedCount, 0, r, k) 77 | 78 | 79 | if __name__ == '__main__': 80 | """ 81 | Example usage 82 | """ 83 | 84 | cwr = CombinationsWithRepetition() 85 | # Prints all combinations of size 3 where 86 | # each element is repeated at most twice 87 | seq = [1, 2, 3, 4] 88 | cwr.printCombinationsWithRepetition(seq, 3, 2) 89 | # prints: 90 | # { 3 4 4 } 91 | # { 3 3 4 } 92 | # { 2 4 4 } 93 | # { 2 3 4 } 94 | # { 2 3 3 } 95 | # { 2 2 4 } 96 | # { 2 2 3 } 97 | # { 1 4 4 } 98 | # { 1 3 4 } 99 | # { 1 3 3 } 100 | # { 1 2 4 } 101 | # { 1 2 3 } 102 | # { 1 2 2 } 103 | # { 1 1 4 } 104 | # { 1 1 3 } 105 | # { 1 1 2 } 106 | -------------------------------------------------------------------------------- /src/main/python/algorithms/other/LazyRangeAdder.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file LazyRangeAdder.py 3 | * @author (original JAVA) Atharva Thorve, aaathorve@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 30 Jun 2020 6 | * @version 0.1 7 | * @brief LazyRangeAdder implementation 8 | * The LazyRangerAdder is a handy class for performing addition range updates of constant values on 9 | * an array. This range adder is especially useful for offline algorithms which know all range 10 | * updates ahead of time. 11 | * 12 | *

Time complexity to update O(1) but time complexity to finalize all additions is O(n) 13 | ''' 14 | 15 | import math 16 | 17 | class LazyRangeAdder(): 18 | 19 | def __init__(self): 20 | 21 | # The number of elements in the input array. 22 | self.n = 0 23 | 24 | # The original input array 25 | self.array = [] 26 | 27 | # The difference array with the deltas between values, size n+1 28 | self.differenceArray = [] 29 | 30 | 31 | 32 | def lazyRangeAdder(self, array): 33 | """ 34 | Initialize an instance of a LazyRangeAdder on some input values 35 | """ 36 | self.array = array 37 | self.n = len(array) 38 | 39 | self.differenceArray = [0]*(self.n + 1) 40 | self.differenceArray[0] = self.array[0] 41 | for i in range(1, self.n): 42 | self.differenceArray[i] = self.array[i] - self.array[i - 1] 43 | 44 | 45 | 46 | def add(self, l, r, x): 47 | """ 48 | Add `x` to the range [l, r] inclusive 49 | """ 50 | self.differenceArray[l] += x; 51 | self.differenceArray[r + 1] -= x; 52 | 53 | 54 | 55 | def done(self): 56 | """ 57 | IMPORTANT: Make certain to call this method once all the additions 58 | have been made with add(l, r, x) 59 | """ 60 | for i in range(0, self.n): 61 | if i == 0: 62 | self.array[i] = self.differenceArray[i] 63 | else: 64 | self.array[i] = self.differenceArray[i] + self.array[i - 1] 65 | 66 | 67 | 68 | 69 | if __name__ == '__main__': 70 | """ 71 | Example usage 72 | """ 73 | la = LazyRangeAdder() 74 | 75 | # Array to be updated 76 | array = [10, 4, 6, 13, 8, 15, 17, 22] 77 | la.lazyRangeAdder(array) 78 | 79 | # After below add(l, r, x), the 80 | # elements should become [10, 14, 16, 23, 18, 15, 17, 22] 81 | la.add(1, 4, 10) 82 | la.done() 83 | print(array) 84 | 85 | # After below add(l, r, x), the 86 | # elements should become [22, 26, 28, 30, 25, 22, 24, 34] 87 | la.add(3, 6, -5) 88 | la.add(0, 7, 12) 89 | la.done() 90 | print(array) 91 | 92 | -------------------------------------------------------------------------------- /src/main/python/algorithms/other/Permutations.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file Permutations.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief Permutations implementation 8 | * Here we present two methods (recursive and iterative) of generating all the permutations of a 9 | * list of elements. 10 | * 11 | *

Time Complexity: O(n!) 12 | ''' 13 | 14 | import math 15 | 16 | class Permutations(): 17 | 18 | def __init__(self): 19 | pass 20 | 21 | ############################################################ 22 | # RECURSIVE APPROACH 23 | 24 | def generatePermutations(self, sequence): 25 | """ 26 | Generates all the permutations of a sequence of objects 27 | """ 28 | if sequence == None: 29 | return 30 | used = [False]*len(sequence) 31 | picked = [0]*len(sequence) 32 | self.permutations(0, used, picked, sequence) 33 | 34 | 35 | def permutations(self, at, used, picked, sequence): 36 | """ 37 | Recursive method to generate all the permutations of a sequence 38 | at -> Current element we're considering 39 | used -> The elements we have currently selected in our permutation 40 | picked -> The order of the indexes we have selected in our permutation 41 | sequence -> The array we're generating permutations for 42 | """ 43 | 44 | N = len(sequence) 45 | 46 | # We reached the end, so we've found a valid permutation! 47 | if at == N: 48 | 49 | # Print permutation 50 | print("[ ", end = '') 51 | for i in range(0, N): 52 | print('{} '.format(sequence[picked[i]]), end = '') 53 | print("]") 54 | 55 | else: 56 | 57 | for i in range(0, N): 58 | 59 | # We can only select elements once, so make sure we do 60 | # not select an element which has already been chosen 61 | if not used[i]: 62 | 63 | # Select this element and track in picked which 64 | # element was chosen for this permutations 65 | used[i] = True 66 | picked[at] = i 67 | self.permutations(at + 1, used, picked, sequence) 68 | 69 | # Backtrack (unselect element) 70 | used[i] = False 71 | 72 | 73 | 74 | ############################################################ 75 | # ITERATIVE APPROACH 76 | 77 | def nextPermutation(self, sequence): 78 | """ 79 | Generates the next ordered permutation in-place (skips repeated permutations). 80 | Calling this when the array is already at the highest permutation returns false. 81 | Recommended usage is to start with the smallest permutations and use a do while 82 | loop to generate each successive permutations (see main for example). 83 | """ 84 | first = self.getFirst(sequence) 85 | if first == -1: 86 | return False 87 | toSwap = len(sequence) - 1 88 | while sequence[first] >= sequence[toSwap]: 89 | toSwap -= 1 90 | self.swap(sequence, first, toSwap) 91 | first += 1 92 | toSwap = len(sequence) - 1 93 | while first < toSwap: 94 | self.swap(sequence, first, toSwap) 95 | first += 1 96 | toSwap -= 1 97 | return True 98 | 99 | 100 | def getFirst(self, sequence): 101 | for i in range(len(sequence) - 2, -1, -1): 102 | if sequence[i] < sequence[i + 1]: 103 | return i 104 | return -1 105 | 106 | 107 | def swap(self, sequence, i, j): 108 | tmp = sequence[i] 109 | sequence[i] = sequence[j] 110 | sequence[j] = tmp 111 | 112 | 113 | if __name__ == '__main__': 114 | """ 115 | Example usage 116 | """ 117 | p = Permutations() 118 | 119 | sequence = [1, 1, 2, 3] 120 | p.generatePermutations(sequence) 121 | # prints: 122 | # [ 1 1 2 3 ] 123 | # [ 1 1 3 2 ] 124 | # [ 1 2 1 3 ] 125 | # [ 1 2 3 1 ] 126 | # [ 1 3 1 2 ] 127 | # [ 1 3 2 1 ] 128 | # [ 1 1 2 3 ] 129 | # [ 1 1 3 2 ] 130 | # [ 1 2 1 3 ] 131 | # [ 1 2 3 1 ] 132 | # [ 1 3 1 2 ] 133 | # [ 1 3 2 1 ] 134 | # [ 2 1 1 3 ] 135 | # [ 2 1 3 1 ] 136 | # [ 2 1 1 3 ] 137 | # [ 2 1 3 1 ] 138 | # [ 2 3 1 1 ] 139 | # [ 2 3 1 1 ] 140 | # [ 3 1 1 2 ] 141 | # [ 3 1 2 1 ] 142 | # [ 3 1 1 2 ] 143 | # [ 3 1 2 1 ] 144 | # [ 3 2 1 1 ] 145 | # [ 3 2 1 1 ] 146 | 147 | 148 | alpha = ["A", "B", "C", "D"] 149 | while True: 150 | 151 | print(str(alpha)) 152 | 153 | # Loop while alpha is not at its highest permutation ordering 154 | if not p.nextPermutation(alpha): 155 | break 156 | 157 | # prints: 158 | # [A, B, C, D] 159 | # [A, B, D, C] 160 | # [A, C, B, D] 161 | # [A, C, D, B] 162 | # [A, D, B, C] 163 | # [A, D, C, B] 164 | # [B, A, C, D] 165 | # [B, A, D, C] 166 | # [B, C, A, D] 167 | # [B, C, D, A] 168 | # [B, D, A, C] 169 | # [B, D, C, A] 170 | # [C, A, B, D] 171 | # [C, A, D, B] 172 | # [C, B, A, D] 173 | # [C, B, D, A] 174 | # [C, D, A, B] 175 | # [C, D, B, A] 176 | # [D, A, B, C] 177 | # [D, A, C, B] 178 | # [D, B, A, C] 179 | # [D, B, C, A] 180 | # [D, C, A, B] 181 | # [D, C, B, A] 182 | -------------------------------------------------------------------------------- /src/main/python/algorithms/other/PowerSet.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file PowerSet.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 30 Jun 2020 6 | * @version 0.1 7 | * @brief PowerSet implementation 8 | * This code snippet shows how to generate the powerset of a set which is the set of all subsets of 9 | * a set. There are two common ways of doing this which are to use the binary representation of 10 | * numbers on a computer or to do it recursively. Both methods are shown here, pick your flavor! 11 | * 12 | *

Time Complexity: O( 2^n ) 13 | ''' 14 | 15 | import math 16 | 17 | class PowerSet(): 18 | 19 | def __init__(self): 20 | pass 21 | 22 | 23 | def powerSetUsingBinary(self, set): 24 | """ 25 | Use the fact that numbers represented in binary can be 26 | used to generate all the subsets of an array 27 | """ 28 | 29 | N = len(set) 30 | MAX_VAL = 1 << N 31 | 32 | for subset in range(0, MAX_VAL): 33 | print("{ ", end = '') 34 | for i in range(0, N): 35 | mask = 1 << i 36 | if (subset & mask) == mask: 37 | print('{} '.format(set[i]), end = '') 38 | 39 | print("}") 40 | 41 | 42 | 43 | def powerSetRecursive(self, at, set, used): 44 | """ 45 | Recursively generate the powerset (set of all subsets) of an array by maintaining 46 | a boolean array used to indicate which element have been selected 47 | """ 48 | 49 | if at == len(set): 50 | 51 | # Print found subset! 52 | print("{ ", end = '') 53 | for i in range(0, len(set)): 54 | if used[i]: 55 | print('{} '.format(set[i]), end = '') 56 | print("}"); 57 | 58 | else: 59 | 60 | # Include this element 61 | used[at] = True 62 | self.powerSetRecursive(at + 1, set, used) 63 | 64 | # Backtrack and don't include this element 65 | used[at] = False 66 | self.powerSetRecursive(at + 1, set, used) 67 | 68 | 69 | 70 | if __name__ == '__main__': 71 | """ 72 | Example usage 73 | """ 74 | ps = PowerSet() 75 | 76 | # Example usage: 77 | set = [1, 2, 3] 78 | 79 | ps.powerSetUsingBinary(set) 80 | # prints: 81 | # { } 82 | # { 1 } 83 | # { 2 } 84 | # { 1 2 } 85 | # { 3 } 86 | # { 1 3 } 87 | # { 2 3 } 88 | # { 1 2 3 } 89 | 90 | print() 91 | 92 | ps.powerSetRecursive(0, set, [False]*len(set)) 93 | # prints: 94 | # { 1 2 3 } 95 | # { 1 2 } 96 | # { 1 3 } 97 | # { 1 } 98 | # { 2 3 } 99 | # { 2 } 100 | # { 3 } 101 | # { } 102 | -------------------------------------------------------------------------------- /src/main/python/algorithms/other/SlidingWindowMaximum.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file SlidingWindowMaximum.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 30 Jun 2020 6 | * @version 0.1 7 | * @brief SlidingWindowMaximum implementation 8 | * This file contain an implementation of the maximum sliding window problem. This code has been 9 | * tested against the judge data on: 10 | * 11 | *

https://leetcode.com/problems/sliding-window-maximum/description/ 12 | ''' 13 | 14 | import math 15 | from collections import deque 16 | 17 | class SlidingWindowMaximum(): 18 | 19 | def __init__(self, values): 20 | if values == None: 21 | raise Exception() 22 | self.values = values 23 | self.N = len(values) 24 | self.lo = 0 25 | self.hi = 0 26 | self.deque = deque() 27 | 28 | 29 | def advance(self): 30 | """ 31 | Advances the front of the window by one unit 32 | """ 33 | 34 | # Remove all the worse values in the back of the deque 35 | while len(self.deque) and self.values[self.deque[-1]] < self.values[self.hi]: 36 | self.deque.pop() # Change the '<' sign here ^^^ to '>' for minimum sliding window 37 | 38 | # Add the next index to the back of the deque 39 | self.deque.append(self.hi) 40 | 41 | # Increase the window size 42 | self.hi += 1 43 | 44 | 45 | def shrink(self): 46 | """ 47 | Retracks the back of the window by one unit 48 | """ 49 | 50 | # Decrease window size by pushing it forward 51 | self.lo += 1 52 | 53 | # Remove elements in the front of the queue whom are no longer 54 | # valid in the reduced window. 55 | while len(self.deque) and self.deque[0] < self.lo: 56 | self.deque.popleft() 57 | 58 | 59 | # Query the current maximum value in the window 60 | def getMax(self): 61 | if self.lo >= self.hi: 62 | raise Exception("Make sure lo < hi") 63 | # print(self.deque) 64 | if len(self.deque): 65 | return self.values[self.deque[0]] 66 | else: 67 | return None 68 | 69 | -------------------------------------------------------------------------------- /src/main/python/algorithms/other/SquareRootDecomposition.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file SquareRootDecomposition.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 30 Jun 2020 6 | * @version 0.1 7 | * @brief SquareRootDecomposition implementation 8 | * Range queries in O(sqrt(n)) and point updates in O(1). Currently this implementation supports 9 | * summing over the entries in the array, but it can be modified to support many different 10 | * operations. 11 | * 12 | *

Time Complexity: Point update in O(1) and query in O(sqrt(n)) 13 | ''' 14 | 15 | import math 16 | 17 | class SquareRootDecomposition(): 18 | 19 | def __init__(self, values): 20 | """ 21 | Creates an empty range [0,n] 22 | """ 23 | sz = len(values) 24 | self.blockSize = int(math.sqrt(sz)) 25 | self.nBlocks = (sz // self.blockSize) + 1 26 | self.blocks = [0]*self.nBlocks 27 | self.arr = [0]*sz 28 | 29 | for i in range(0, sz): 30 | self.set(i, values[i]) 31 | 32 | 33 | 34 | def blockID(self, index): 35 | return index // self.blockSize 36 | 37 | 38 | 39 | def set(self, index, val): 40 | """ 41 | Sets [index, index] = val 42 | """ 43 | self.blocks[self.blockID(index)] -= self.arr[index]; 44 | self.blocks[self.blockID(index)] += val 45 | self.arr[index] = val 46 | 47 | 48 | 49 | def query(self, lo, hi): 50 | """ 51 | Get sum query from [lo, hi] in O(sqrt(n)) 52 | """ 53 | 54 | sum = 0 55 | loId = self.blockID(lo) 56 | hiId = self.blockID(hi) 57 | for i in range(loId + 1, hiId): 58 | sum += self.blocks[i] 59 | 60 | if loId == hiId: 61 | for i in range(lo, hi+1): 62 | sum += self.arr[i] 63 | return sum 64 | 65 | loMax = (((lo // self.blockSize) + 1) * self.blockSize) - 1 66 | hiMin = (hi // self.blockSize) * self.blockSize 67 | for i in range(lo, loMax+1): 68 | sum += self.arr[i] 69 | for i in range(hiMin, hi+1): 70 | sum += self.arr[i] 71 | 72 | return sum 73 | 74 | 75 | 76 | if __name__ == '__main__': 77 | """ 78 | Square root decomposition range query example usage 79 | """ 80 | 81 | values = [1, 2, 3, 4, 5, 6, 7, 8, 9] 82 | rng = SquareRootDecomposition(values) 83 | 84 | # Prints: The sum from [0,8] is: 45 85 | print('The sum from [{},{}] is: {}\n'.format(0, 8, rng.query(0, 8))) 86 | 87 | # Prints: The sum from [2,2] is: 3 88 | print('The sum from [{},{}] is: {}\n'.format(2, 2, rng.query(2, 2))) 89 | 90 | # Prints: The sum from [3,4] is: 9 91 | print('The sum from [{},{}] is: {}\n'.format(3, 4, rng.query(3, 4))) 92 | 93 | # Prints: The sum from [1,6] is: 27 94 | print('The sum from [{},{}] is: {}\n'.format(1, 6, rng.query(1, 6))) 95 | -------------------------------------------------------------------------------- /src/main/python/algorithms/other/UniqueCombinations.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file UniqueCombinations.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 30 Jun 2020 6 | * @version 0.1 7 | * @brief UniqueCombinations implementation 8 | * This file shows you how to generate all the unique combinations of a set even though some 9 | * elements may be repeated. For example, if your set is {2, 2, 3, 3, 3} and you care only about 10 | * sets of size two (r = 2) then the unique sets are {{2,2}, {2,3}, {3,3}}. 11 | * 12 | *

Time Complexity: O( n choose r ) 13 | ''' 14 | 15 | import math 16 | 17 | class UniqueCombinations(): 18 | 19 | def __init__(self): 20 | pass 21 | 22 | 23 | def combinations(self, set, r): 24 | if set is None: 25 | return 26 | if r < 0: 27 | return 28 | 29 | # Sort the numbers so we can easily skip duplicates. 30 | set.sort() 31 | 32 | used = [False]*len(set) 33 | self.__combinations(0, r, used, set) 34 | 35 | 36 | def __combinations(self, at, r, used, set): 37 | 38 | n = len(set) 39 | 40 | # We select 'r' elements so we found a valid subset! 41 | if r == 0: 42 | 43 | subset = [] 44 | for i in range(0, n): 45 | if used[i]: 46 | subset.append(set[i]) 47 | print(subset) 48 | 49 | else: 50 | for i in range(at, n): 51 | 52 | # Since the elements are sorted we can skip duplicate 53 | # elements to ensure the uniqueness of our output. 54 | if i > at and set[i - 1] == set[i]: 55 | continue 56 | 57 | used[i] = True 58 | self.__combinations(i + 1, r - 1, used, set) 59 | used[i] = False 60 | 61 | 62 | 63 | if __name__ == '__main__': 64 | """ 65 | Example usage 66 | """ 67 | uc = UniqueCombinations() 68 | 69 | # Example #1 70 | r = 2 71 | set = [2, 3, 3, 2, 3] 72 | uc.combinations(set, r) 73 | # Prints: 74 | # [2, 2] 75 | # [2, 3] 76 | # [3, 3] 77 | 78 | print() 79 | 80 | r = 3 81 | set = [1, 2, 2, 2, 3, 3, 4, 4] 82 | uc.combinations(set, r) 83 | # Prints: 84 | # [1, 2, 2] 85 | # [1, 2, 3] 86 | # [1, 2, 4] 87 | # [1, 3, 3] 88 | # [1, 3, 4] 89 | # [1, 4, 4] 90 | # [2, 2, 2] 91 | # [2, 2, 3] 92 | # [2, 2, 4] 93 | # [2, 3, 3] 94 | # [2, 3, 4] 95 | # [2, 4, 4] 96 | # [3, 3, 4] 97 | # [3, 4, 4] 98 | -------------------------------------------------------------------------------- /src/main/python/algorithms/search/BinarySearch.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file BinarySearch.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief BinarySearch implementation 8 | ''' 9 | 10 | import math 11 | 12 | class BinarySearch(): 13 | 14 | def __init__(self): 15 | # Comparing double values directly is bad practice. 16 | # Using a small epsilon value is the preferred approach 17 | self.EPS = 0.00000001 18 | 19 | def binarySearch(self, lo, hi, target, function): 20 | 21 | if hi <= lo: 22 | raise Exception("hi should be greater than lo") 23 | 24 | mid = 0 25 | while True: 26 | 27 | # Find the middle point 28 | mid = (hi + lo) / 2.0 29 | 30 | # Compute the value of our function for the middle point 31 | # Note that f can be any function not just the square root function 32 | value = function(mid) 33 | 34 | if value > target: 35 | hi = mid 36 | else: 37 | lo = mid 38 | 39 | if (hi - lo) > self.EPS: 40 | break 41 | 42 | return mid 43 | 44 | 45 | # ToDo: The validity of the implementation must be checked! 46 | if __name__ == '__main__': 47 | """ 48 | Example usage 49 | """ 50 | bs = BinarySearch() 51 | 52 | # EXAMPLE #1 53 | # Suppose we want to know what the square root of 875 is and 54 | # we have no knowledge of the wonderful Math.sqrt() function. 55 | # One approach is to use a binary search because we know that 56 | # the square root of 875 is bounded in the region: [0, 875]. 57 | # 58 | # We can define our function to be f(x) = x*x and our target 59 | # value to be 875. As we binary search on f(x) approaching 60 | # successively closer values of 875 we get better and better 61 | # values of x (the square root of 875) 62 | 63 | lo = 0.0 64 | hi = 875.0 65 | target = 875.0 66 | sqr_fun = lambda x: x * x 67 | 68 | sqrtVal = bs.binarySearch(lo, hi, target, sqr_fun) 69 | print('sqrt({:.2f}) = {:.5f}, x^2 = {:.5f}\n'.format(target, sqrtVal, (sqrtVal * sqrtVal))) 70 | 71 | # EXAMPLE #2 72 | # Suppose we want to find the radius of a sphere with volume 100m^3 using 73 | # a binary search. We know that for a sphere the volume is given by 74 | # V = (4/3)*pi*r^3, so all we have to do is binary search on the radius. 75 | # 76 | # Note: this is a silly example because you could just solve for r, but it 77 | # shows how binary search can be a powerful technique. 78 | 79 | radiusLowerBound = 0 80 | radiusUpperBound = 1000 81 | volume = 100.0 82 | sphereVolumeFunction = lambda r: (4.0 / 3.0) * math.pi * r * r * r 83 | 84 | sphereRadius = bs.binarySearch(radiusLowerBound, radiusUpperBound, volume, sphereVolumeFunction) 85 | 86 | print('Sphere radius = {:.5f}\n'.format(sphereRadius)) 87 | -------------------------------------------------------------------------------- /src/main/python/algorithms/search/InterpolationSearch.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file InterpolationSearch.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief An implementation of interpolation search 8 | ''' 9 | 10 | import math 11 | 12 | class InterpolationSearch(): 13 | """ 14 | A fast alternative to a binary search when the elements are uniformly distributed. This 15 | algorithm runs in a time complexity of ~O(log(log(n))). 16 | """ 17 | def __init__(self): 18 | pass 19 | 20 | def interpolationSearch(self, nums, val): 21 | """ 22 | @param nums - an ordered list containing uniformly distributed values. 23 | @param val - the value we're looking for in 'nums' 24 | """ 25 | lo = 0 26 | mid = 0 27 | hi = len(nums) - 1 28 | 29 | while nums[lo] <= val and nums[hi] >= val: 30 | mid = lo + ((val - nums[lo]) * (hi - lo)) // (nums[hi] - nums[lo]) 31 | if nums[mid] < val: 32 | lo = mid + 1 33 | elif nums[mid] > val: 34 | hi = mid - 1 35 | else: 36 | return mid 37 | 38 | if nums[lo] == val: 39 | return lo 40 | return -1 41 | 42 | 43 | if __name__ == '__main__': 44 | """ 45 | Example usage 46 | """ 47 | s = InterpolationSearch() 48 | 49 | values = [10, 20, 25, 35, 50, 70, 85, 100, 110, 120, 125] 50 | 51 | # Since 25 exists in the values array the interpolation search 52 | # returns that it has found 25 at the index 2 53 | print(s.interpolationSearch(values, 25)) 54 | 55 | # 111 does not exist so we get -1 as an index value 56 | print(s.interpolationSearch(values, 111)) 57 | -------------------------------------------------------------------------------- /src/main/python/algorithms/search/TernarySearch.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file TernarySearch.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief An implementation of Ternary search 8 | * Ternary search is similar to binary search except that it works on a function which decreases and 9 | * then increases. This implementation of ternary search returns the input value corresponding with 10 | * the minimum output value of the function you're searching on. 11 | ''' 12 | 13 | import math 14 | 15 | class TernarySearch(): 16 | """ 17 | """ 18 | def __init__(self): 19 | # Define a very small epsilon value to compare double values 20 | self.EPS = 0.000000001 21 | 22 | 23 | def ternarySearch(self, low, high, function): 24 | """ 25 | Perform a ternary search on the interval low to high. 26 | Remember that your function must be a continuous unimodal 27 | function, this means a function which decreases then increases (U shape) 28 | """ 29 | best = None 30 | while True: 31 | mid1 = (2 * low + high) // 3 32 | mid2 = (low + 2 * high) // 3 33 | res1 = function(mid1) 34 | res2 = function(mid2) 35 | if res1 > res2: 36 | low = mid1 37 | else: 38 | high = mid2 39 | if best is not None and abs(best - mid1) < self.EPS: 40 | break 41 | best = mid1 42 | 43 | return best 44 | 45 | 46 | if __name__ == '__main__': 47 | """ 48 | Example usage 49 | """ 50 | ts = TernarySearch() 51 | 52 | # Search for the lowest point on the function x^2 + 3x + 5 53 | # using a ternary search on the interval [-100, +100] 54 | function = lambda x: x * x + 3 * x + 5 55 | root = ts.ternarySearch(-100.0, +100.0, function) 56 | print('{:.4f}\n'.format(root)) 57 | -------------------------------------------------------------------------------- /src/main/python/algorithms/search/TernarySearchDiscrete.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file TernarySearchDiscrete.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief An implementation of Ternary search 8 | * Ternary search is similar to binary search except that it works on a function which decreases and 9 | * then increases. This implementation of ternary search works on discrete values and returns the 10 | * input value corresponding with the minimum output value of the function you're searching on. 11 | * 12 | *

Time Complexity: O(log(high - low)). 13 | * 14 | *

NOTE: You can also work with a function which increases and then decreases, simply negate your 15 | * function :) 16 | ''' 17 | 18 | import math 19 | 20 | # A discrete function is just a set of data points. 21 | function = [16, 12, 10, 3, 6, 7, 9, 10, 11, 12, 13, 17] 22 | 23 | 24 | # Define your own function on whatever you're attempting to ternary 25 | # search. Remember that your function must be a discrete and a unimodal 26 | # function, this means a function which decreases then increases (U shape) 27 | f = lambda i: function[i] 28 | 29 | 30 | class TernarySearchDiscrete(): 31 | """ 32 | """ 33 | def __init__(self): 34 | # Define a very small epsilon value to compare double values. 35 | self.EPS = 0.000000001 36 | 37 | 38 | def discreteTernarySearch(self, lo, hi): 39 | while lo != hi: 40 | if hi - lo == 1: 41 | return min(f(lo), f(hi)) 42 | if hi - lo == 2: 43 | return min(f(lo), min(f(lo + 1), f(hi))) 44 | 45 | mid1 = (2 * lo + hi) // 3 46 | mid2 = (lo + 2 * hi) // 3 47 | res1 = f(mid1) 48 | res2 = f(mid2) 49 | if abs(res1 - res2) < 0.000000001: 50 | lo = mid1 51 | hi = mid2 52 | elif res1 > res2: 53 | lo = mid1 54 | else: 55 | hi = mid2 56 | 57 | return lo 58 | 59 | 60 | 61 | if __name__ == '__main__': 62 | """ 63 | Example usage 64 | """ 65 | ts = TernarySearchDiscrete() 66 | 67 | lo = 0 68 | hi = len(function) - 1 69 | 70 | # Use ternary search to find the minimum value on the 71 | # whole interval of out function. 72 | minValue = ts.discreteTernarySearch(lo, hi) 73 | print('{:.4f}\n'.format(minValue)) 74 | -------------------------------------------------------------------------------- /src/main/python/algorithms/sorting/BubbleSort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file BubbleSort.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 27 Jun 2020 6 | * @version 0.1 7 | * @brief Bubble sort implementation 8 | ''' 9 | 10 | 11 | class BubbleSort(): 12 | 13 | def __init__(self): 14 | pass 15 | 16 | 17 | def sort(self, ar): 18 | """ 19 | Sort the array using bubble sort. The idea behind 20 | bubble sort is to look for adjacent indexes which 21 | are out of place and interchange their elements 22 | until the entire array is sorted. 23 | """ 24 | if ar == None: 25 | return 26 | 27 | sorted = False 28 | while True: 29 | sorted = True 30 | for i in range(1, len(ar)): 31 | if ar[i] < ar[i - 1]: 32 | self.swap(ar, i - 1, i) 33 | sorted = False 34 | if sorted: 35 | break 36 | 37 | 38 | def swap(self, ar, i, j): 39 | tmp = ar[i] 40 | ar[i] = ar[j] 41 | ar[j] = tmp 42 | 43 | 44 | if __name__ == '__main__': 45 | """ 46 | Example usage 47 | """ 48 | array = [10, 4, 6, 8, 13, 2, 3] 49 | sorter = BubbleSort() 50 | sorter.sort(array) 51 | # Prints: 52 | # [2, 3, 4, 6, 8, 10, 13] 53 | print(array) 54 | -------------------------------------------------------------------------------- /src/main/python/algorithms/sorting/BucketSort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file BucketSort.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 27 Jun 2020 6 | * @version 0.1 7 | * @brief Bucket sort implementation 8 | ''' 9 | 10 | import sys 11 | 12 | class BucketSort(): 13 | 14 | def __init__(self): 15 | pass 16 | 17 | 18 | def sort(self, values): 19 | minValue = sys.maxsize 20 | maxValue = -sys.maxsize - 1 21 | for i in range(0, len(values)): 22 | if values[i] < minValue: 23 | minValue = values[i] 24 | if values[i] > maxValue: 25 | maxValue = values[i] 26 | 27 | self.bucketSort(values, minValue, maxValue) 28 | 29 | 30 | def bucketSort(self, ar, minValue, maxValue): 31 | """ 32 | Performs a bucket sort of an array in which all the elements are 33 | bounded in the range [minValue, maxValue]. For bucket sort to give linear 34 | performance the elements need to be uniformly distributed 35 | """ 36 | if ar == None or len(ar) == 0 or minValue == maxValue: 37 | return None 38 | 39 | # N is number elements and M is the range of values 40 | N = len(ar) 41 | M = maxValue - minValue + 1 42 | numBuckets = M // N + 1 43 | buckets = [] 44 | for i in range(0, numBuckets): 45 | buckets.append([]) 46 | 47 | # Place each element in a bucket 48 | for i in range(0, N): 49 | bi = (ar[i] - minValue) // M 50 | buckets[bi].append(ar[i]) 51 | 52 | 53 | # Sort buckets and stitch together answer 54 | j = 0 55 | for bi in range(0, numBuckets): 56 | bucket = buckets[bi] 57 | if bucket is not None: 58 | bucket.sort() 59 | for k in range(0, len(bucket)): 60 | ar[j] = bucket[k] 61 | j += 1 62 | 63 | 64 | 65 | if __name__ == '__main__': 66 | """ 67 | Example usage 68 | """ 69 | sorter = BucketSort() 70 | 71 | array = [10, 4, 6, 8, 13, 2, 3] 72 | sorter.sort(array) 73 | # Prints: 74 | # [2, 3, 4, 6, 8, 10, 13] 75 | print(array) 76 | 77 | array = [10, 10, 10, 10, 10] 78 | sorter.sort(array); 79 | # Prints: 80 | # [10, 10, 10, 10, 10] 81 | print(array) 82 | -------------------------------------------------------------------------------- /src/main/python/algorithms/sorting/CountingSort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file CountingSort.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 27 Jun 2020 6 | * @version 0.1 7 | * @brief Counting sort implementation 8 | ''' 9 | 10 | import sys 11 | 12 | class CountingSort(): 13 | 14 | def __init__(self): 15 | pass 16 | 17 | 18 | def sort(self, values): 19 | minValue = sys.maxsize 20 | maxValue = -sys.maxsize - 1 21 | for i in range(0, len(values)): 22 | if values[i] < minValue: 23 | minValue = values[i] 24 | if values[i] > maxValue: 25 | maxValue = values[i] 26 | 27 | self.countingSort(values, minValue, maxValue) 28 | 29 | 30 | def countingSort(self, ar, minVal, maxVal): 31 | """ 32 | Sorts values in the range of [minVal, maxVal] in O(n+maxVal-maxVal) 33 | """ 34 | sz = maxVal - minVal + 1 35 | b = [0]*sz 36 | for i in range(0, len(ar)): 37 | b[ar[i] - minVal] += 1 38 | k = 0 39 | for i in range(0, sz): 40 | while b[i] > 0: 41 | b[i] -= 1 42 | ar[k] = i + minVal 43 | k += 1 44 | 45 | 46 | 47 | if __name__ == '__main__': 48 | """ 49 | Example usage 50 | """ 51 | sorter = CountingSort() 52 | nums = [+4, -10, +0, +6, +1, -5, -5, +1, +1, -2, 0, +6, +8, -7, +10] 53 | sorter.sort(nums) 54 | 55 | # Prints: 56 | # [-10, -7, -5, -5, -2, 0, 0, 1, 1, 1, 4, 6, 6, 8, 10] 57 | print(nums) 58 | -------------------------------------------------------------------------------- /src/main/python/algorithms/sorting/Heapsort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file Heapsort.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 27 Jun 2020 6 | * @version 0.1 7 | * @brief heap sort implementation 8 | ''' 9 | 10 | import sys 11 | 12 | class Heapsort(): 13 | 14 | def __init__(self): 15 | pass 16 | 17 | 18 | def sort(self, values): 19 | self.heapsort(values) 20 | 21 | 22 | def heapsort(self, ar): 23 | if ar == None: 24 | return None 25 | n = len(ar) 26 | 27 | # Heapify, converts array into binary heap O(n), see: 28 | # http://www.cs.umd.edu/~meesh/351/mount/lectures/lect14-heapsort-analysis-part.pdf 29 | for i in range(max(0, (n // 2) - 1), -1, -1): 30 | self.sink(ar, n, i) 31 | 32 | # Sorting bit 33 | for i in range(n - 1, -1, -1): 34 | self.swap(ar, 0, i) 35 | self.sink(ar, i, 0) 36 | 37 | 38 | 39 | def sink(self, ar, n, i): 40 | while True: 41 | left = 2 * i + 1 # Left node 42 | right = 2 * i + 2 # Right node 43 | largest = i 44 | 45 | # Right child is larger than parent 46 | if right < n and ar[right] > ar[largest]: 47 | largest = right 48 | 49 | # Left child is larger than parent 50 | if left < n and ar[left] > ar[largest]: 51 | largest = left 52 | 53 | # Move down the tree following the largest node 54 | if largest != i: 55 | self.swap(ar, largest, i) 56 | i = largest 57 | else: 58 | break 59 | 60 | 61 | def swap(self, ar, i, j): 62 | tmp = ar[i] 63 | ar[i] = ar[j] 64 | ar[j] = tmp 65 | 66 | 67 | 68 | if __name__ == '__main__': 69 | """ 70 | Example usage 71 | """ 72 | sorter = Heapsort() 73 | array = [10, 4, 6, 4, 8, -13, 2, 3] 74 | sorter.sort(array) 75 | # Prints: 76 | # [-13, 2, 3, 4, 4, 6, 8, 10] 77 | print(array) 78 | -------------------------------------------------------------------------------- /src/main/python/algorithms/sorting/InsertionSort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file InsertionSort.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 27 Jun 2020 6 | * @version 0.1 7 | * @brief Insertion sort implementation 8 | ''' 9 | 10 | import sys 11 | 12 | class InsertionSort(): 13 | 14 | def __init__(self): 15 | pass 16 | 17 | 18 | def sort(self, values): 19 | self.insertionSort(values) 20 | 21 | 22 | def insertionSort(self, ar): 23 | """ 24 | Sort the given array using insertion sort. The idea behind 25 | insertion sort is that at the array is already sorted from 26 | [0, i] and you want to add the element at position i+1, so 27 | you 'insert' it at the appropriate location. 28 | """ 29 | if ar == None: 30 | return 31 | 32 | for i in range(1, len(ar)): 33 | j = i 34 | while j > 0 and ar[j] < ar[j - 1]: 35 | self.swap(ar, j - 1, j) 36 | j -= 1 37 | 38 | 39 | def swap(self, ar, i, j): 40 | tmp = ar[i] 41 | ar[i] = ar[j] 42 | ar[j] = tmp 43 | 44 | 45 | if __name__ == '__main__': 46 | """ 47 | Example usage 48 | """ 49 | sorter = InsertionSort() 50 | array = [10, 4, 6, 8, 13, 2, 3] 51 | sorter.sort(array) 52 | # Prints: 53 | # [2, 3, 4, 6, 8, 10, 13] 54 | print(array) 55 | -------------------------------------------------------------------------------- /src/main/python/algorithms/sorting/MergeSort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file MergeSort.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 27 Jun 2020 6 | * @version 0.1 7 | * @brief Merge sort implementation 8 | ''' 9 | 10 | import sys 11 | 12 | class MergeSort(): 13 | """ 14 | Mergesort implements InplaceSort for ease of testings, but in reality 15 | it is not really a good fit for an inplace sorting algorithm. 16 | """ 17 | 18 | def __init__(self): 19 | pass 20 | 21 | 22 | def sort(self, values): 23 | return self.mergesort(values) 24 | 25 | 26 | def mergesort(self, ar): 27 | """ 28 | Base case is when a single element (which is already sorted) 29 | """ 30 | n = len(ar) 31 | if n <= 1: 32 | return ar 33 | 34 | # Split array into two parts and recursively sort them 35 | left = self.mergesort(ar[:n // 2]) 36 | right = self.mergesort(ar[n // 2::]) 37 | 38 | # Combine the two arrays into one larger array 39 | return self.merge(left, right) 40 | 41 | 42 | def merge(self, ar1, ar2): 43 | """ 44 | Merge two sorted arrays into a larger sorted array 45 | """ 46 | n1 = len(ar1) 47 | n2 = len(ar2) 48 | n = n1 + n2 49 | i1 = 0 50 | i2 = 0 51 | ar = [0]*n 52 | 53 | for i in range(0, n): 54 | if i1 == n1: 55 | ar[i] = ar2[i2] 56 | i2 += 1 57 | elif i2 == n2: 58 | ar[i] = ar1[i1] 59 | i1 += 1 60 | else: 61 | if ar1[i1] < ar2[i2]: 62 | ar[i] = ar1[i1] 63 | i1 += 1 64 | else: 65 | ar[i] = ar2[i2] 66 | i2 += 1 67 | 68 | return ar 69 | 70 | 71 | 72 | if __name__ == '__main__': 73 | """ 74 | Example usage 75 | """ 76 | array = [10, 4, 6, 4, 8, -13, 2, 3] 77 | sorter = MergeSort() 78 | array = sorter.sort(array) 79 | # Prints: 80 | # [-13, 2, 3, 4, 4, 6, 8, 10] 81 | print(array) 82 | -------------------------------------------------------------------------------- /src/main/python/algorithms/sorting/QuickSort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file QuickSort.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 28 Jun 2020 6 | * @version 0.1 7 | * @brief Quick sort implementation 8 | ''' 9 | 10 | import sys 11 | 12 | class QuickSort(): 13 | """ 14 | Mergesort implements InplaceSort for ease of testings, but in reality 15 | it is not really a good fit for an inplace sorting algorithm. 16 | """ 17 | 18 | def __init__(self): 19 | pass 20 | 21 | 22 | def sort(self, values): 23 | if values == None: 24 | return 25 | self.quicksort(values, 0, len(values)-1) 26 | 27 | 28 | def quicksort(self, ar, lo, hi): 29 | """ 30 | Sort interval [lo, hi] inplace recursively 31 | low --> Starting index, high --> Ending index 32 | https://www.geeksforgeeks.org/quick-sort/ 33 | """ 34 | if lo < hi: 35 | # pi is partitioning index, ar[pi] is now at right place 36 | splitPoint = self.partition(ar, lo, hi) 37 | self.quicksort(ar, lo, splitPoint - 1) # Before pi 38 | self.quicksort(ar, splitPoint + 1, hi) # After pi 39 | 40 | 41 | def partition(self, ar, lo, hi): 42 | """ 43 | Performs Hoare partition algorithm for quicksort 44 | This function takes last element as pivot, places 45 | the pivot element at its correct position in sorted 46 | array, and places all smaller (smaller than pivot) 47 | to left of pivot and all greater elements to right 48 | of pivot 49 | """ 50 | # pivot (Element to be placed at right position) 51 | pivot = ar[hi] 52 | 53 | i = lo - 1 # Index of smaller element 54 | 55 | for j in range(lo, hi): 56 | # If current element is smaller than the pivot 57 | if ar[j] < pivot: 58 | i += 1 # increment index of smaller element 59 | self.swap(ar, i, j) 60 | 61 | self.swap(ar, i + 1, hi) 62 | return i + 1 63 | 64 | 65 | def swap(self, ar, i, j): 66 | tmp = ar[i] 67 | ar[i] = ar[j] 68 | ar[j] = tmp 69 | 70 | 71 | if __name__ == '__main__': 72 | """ 73 | Example usage 74 | """ 75 | sorter = QuickSort() 76 | array = [10, 4, 6, 4, 8, -13, 2, 3] 77 | sorter.sort(array); 78 | # Prints: 79 | # [-13, 2, 3, 4, 4, 6, 8, 10] 80 | print(array) 81 | -------------------------------------------------------------------------------- /src/main/python/algorithms/sorting/QuickSort3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file QuickSort3.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief Quick sort implementation 8 | * QuickSort3 or Dutch National Flag algorithm is similar to the QuickSort algorithm but has an 9 | * improved partitioning algorithm. QuickSort is quite slow in the case where very few unique 10 | * elements exist in the array so the QuickSort3 algorithm is used at that time. 11 | ''' 12 | 13 | import sys 14 | import random 15 | 16 | class QuickSort3(): 17 | """ 18 | Mergesort implements InplaceSort for ease of testings, but in reality 19 | it is not really a good fit for an inplace sorting algorithm. 20 | """ 21 | def __init__(self): 22 | pass 23 | 24 | 25 | def sort(self, values): 26 | if values == None: 27 | return 28 | self.quickSort3(values) 29 | 30 | 31 | def quickSort3(self, ar): 32 | self.randomizedQuickSort(ar, 0, len(ar) - 1) 33 | 34 | 35 | def partition3(self, a, l, r): 36 | """ 37 | partiton array in such a way that all the elements whose value is equal to 38 | pivot are grouped together 39 | """ 40 | j = 0 41 | k = 0 42 | if r - l <= 1: 43 | if a[r] < a[l]: 44 | self.swap(a, l, r) 45 | 46 | j = l 47 | k = r 48 | m = [j, k] 49 | return m 50 | 51 | mid = l 52 | p = a[r] 53 | while mid <= r: 54 | if a[mid] < p: 55 | self.swap(a, l, mid) 56 | l += 1 57 | mid += 1 58 | elif a[mid] == p: 59 | mid += 1 60 | else: 61 | self.swap(a, mid, r) 62 | r -= 1 63 | 64 | j = l - 1 65 | k = mid 66 | m = [j, k] 67 | return m 68 | 69 | 70 | def randomizedQuickSort(self, a, l, r): 71 | """ 72 | Sort interval [lo, hi] inplace recursively 73 | This chooses random pivot value thus improving time complexity 74 | """ 75 | if l >= r: 76 | return 77 | 78 | k = random.randint(0, r - l + 1) + 1 79 | t = a[l] 80 | a[l] = a[k] 81 | a[k] = t 82 | # use partition3 83 | m = self.partition3(a, l, r) 84 | self.randomizedQuickSort(a, l, m[0]) 85 | self.randomizedQuickSort(a, m[1], r) 86 | 87 | 88 | def swap(self, ar, i, j): 89 | tmp = ar[i] 90 | ar[i] = ar[j] 91 | ar[j] = tmp 92 | 93 | 94 | 95 | if __name__ == '__main__': 96 | """ 97 | Example usage 98 | """ 99 | sorter = QuickSort3() 100 | array = [10, 4, 6, 4, 8, -13, 2, 3] 101 | sorter.sort(array) 102 | # Prints: 103 | # [-13, 2, 3, 4, 4, 6, 8, 10] 104 | print(array) 105 | -------------------------------------------------------------------------------- /src/main/python/algorithms/sorting/RadixSort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file RadixSort.py 3 | * @author (original JAVA) EAlexa and William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief Radix sort implementation 8 | * See https://en.wikipedia.org/wiki/Radix_sort for details on runtime and complexity Radix sorts 9 | * operates in O(nw) time, where n is the number of keys, and w is the key length where w is 10 | * constant on primitive types like Integer which gives it a better performance than other 11 | * compare-based sort algorithms, like i.e. QuickSort 12 | ''' 13 | 14 | import math 15 | 16 | class RadixSort(): 17 | """ 18 | Mergesort implements InplaceSort for ease of testings, but in reality 19 | it is not really a good fit for an inplace sorting algorithm. 20 | """ 21 | def __init__(self): 22 | pass 23 | 24 | 25 | def sort(self, values): 26 | if values == None: 27 | return 28 | return self.radixSort(values) 29 | 30 | 31 | def getMax(self, array): 32 | maxNum = array[0] 33 | for i in range(0, len(array)): 34 | if array[i] > maxNum: 35 | maxNum = array[i] 36 | 37 | return maxNum 38 | 39 | 40 | def calculateNumberOfDigits(self, number): 41 | return int(math.log(number, 10) + 1) 42 | 43 | 44 | def radixSort(self, numbers): 45 | """ 46 | Requires all numbers to be greater than or equal to 1 47 | """ 48 | if numbers == None or len(numbers) <= 1: 49 | return 50 | 51 | maximum = self.getMax(numbers) 52 | numberOfDigits = self.calculateNumberOfDigits(maximum) 53 | placeValue = 1 54 | while numberOfDigits > 0: 55 | numberOfDigits -= 1 56 | numbers = self.countSort(numbers, placeValue) 57 | placeValue *= 10 58 | 59 | return numbers 60 | 61 | 62 | def countSort(self, numbers, placeValue): 63 | rangeParm = 10 64 | 65 | frequency = [0]*rangeParm 66 | sortedValues = [None]*len(numbers) 67 | 68 | for i in range(0, len(numbers)): 69 | digit = (numbers[i] // placeValue) % rangeParm 70 | frequency[digit] += 1 71 | 72 | 73 | for i in range(1, rangeParm): 74 | frequency[i] += frequency[i - 1] 75 | 76 | 77 | for i in range(len(numbers) - 1, -1, -1): 78 | digit = (numbers[i] // placeValue) % rangeParm 79 | sortedValues[frequency[digit] - 1] = numbers[i] 80 | frequency[digit] -= 1 81 | 82 | return sortedValues[:len(numbers)] 83 | 84 | 85 | 86 | if __name__ == '__main__': 87 | """ 88 | Example usage 89 | """ 90 | sorter = RadixSort() 91 | numbers = [387, 468, 134, 123, 68, 221, 769, 37, 7, 890, 1, 587] 92 | numbers = sorter.sort(numbers) 93 | # Prints: 94 | # [1, 7, 37, 68, 123, 134, 221, 387, 468, 587, 769, 890] 95 | print(numbers) 96 | -------------------------------------------------------------------------------- /src/main/python/algorithms/sorting/SelectionSort.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file SelectionSort.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief Selection sort implementation 8 | ''' 9 | 10 | 11 | class SelectionSort(): 12 | """ 13 | """ 14 | def __init__(self): 15 | pass 16 | 17 | 18 | def sort(self, values): 19 | if values == None: 20 | return 21 | self.selectionSort(values) 22 | 23 | 24 | def selectionSort(self, array): 25 | N = len(array) 26 | 27 | for i in range(0, N): 28 | # Find the index beyond i with a lower value than i 29 | swapIndex = i 30 | for j in range(i + 1, N): 31 | if array[j] < array[swapIndex]: 32 | swapIndex = j 33 | 34 | self.swap(array, i, swapIndex) 35 | 36 | 37 | def swap(self, ar, i, j): 38 | tmp = ar[i] 39 | ar[i] = ar[j] 40 | ar[j] = tmp 41 | 42 | 43 | if __name__ == '__main__': 44 | """ 45 | Example usage 46 | """ 47 | sorter = SelectionSort() 48 | array = [10, 4, 6, 8, 13, 2, 3] 49 | sorter.sort(array) 50 | # Prints: 51 | # [2, 3, 4, 6, 8, 10, 13] 52 | print(array) 53 | -------------------------------------------------------------------------------- /src/test/cpp/algorithms/datastructures/queue/QueueTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file QueueTest.cpp 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 03 July 2020 6 | * @version 0.1 7 | * @brief A queue unit test. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace dsa { 24 | 25 | const int LOOPS = 10000; 26 | const int TEST_SZ = 30; 27 | const int NUM_NULLS = TEST_SZ / 5; 28 | const int MAX_RAND_NUM = 250; 29 | 30 | template 31 | using queuePtr = std::shared_ptr>; 32 | 33 | enum class QueueImpl : int { LinkedList, Array }; 34 | 35 | 36 | 37 | class QueueTest : public ::testing::Test { 38 | 39 | protected: 40 | 41 | std::vector> queues; 42 | 43 | QueueTest() { 44 | queues.push_back(std::make_shared>(static_cast(QueueImpl::LinkedList))); 45 | queues.push_back(std::make_shared>(static_cast(QueueImpl::Array), 10)); 46 | } 47 | 48 | virtual ~QueueTest() { 49 | for (queuePtr& queue : queues) { 50 | queue = nullptr; 51 | } 52 | } 53 | 54 | virtual void SetUp() { 55 | 56 | } 57 | 58 | virtual void TearDown() { 59 | for (queuePtr& queue : queues) { 60 | queue->clear(); 61 | } 62 | } 63 | 64 | }; 65 | 66 | #if 1 67 | TEST_F(QueueTest, testEmptyQueue) { 68 | for (queuePtr& queue : queues) { 69 | ASSERT_TRUE(queue->isEmpty()); 70 | ASSERT_EQ(queue->size(), 0); 71 | } 72 | } 73 | 74 | 75 | TEST_F(QueueTest, testPollOnEmpty) { 76 | try { 77 | for (queuePtr& queue : queues) { 78 | queue->poll(); 79 | } 80 | } 81 | catch(std::runtime_error const &err) { 82 | EXPECT_EQ(err.what(), std::string("Queue Empty")); 83 | } 84 | catch(...) { 85 | FAIL() << "Expected std::runtime_error Queue Empty"; 86 | } 87 | 88 | } 89 | 90 | 91 | TEST_F(QueueTest, testPeekOnEmpty) { 92 | try { 93 | for (queuePtr& queue : queues) { 94 | queue->peek(); 95 | } 96 | } 97 | catch(std::runtime_error const &err) { 98 | EXPECT_EQ(err.what(), std::string("Queue Empty")); 99 | } 100 | catch(...) { 101 | FAIL() << "Expected std::runtime_error Queue Empty"; 102 | } 103 | 104 | } 105 | 106 | 107 | TEST_F(QueueTest, testOffer) { 108 | for (queuePtr& queue : queues) { 109 | queue->offer(2); 110 | EXPECT_EQ(queue->size(), 1); 111 | } 112 | } 113 | 114 | 115 | TEST_F(QueueTest, testPeek) { 116 | for (queuePtr& queue : queues) { 117 | queue->offer(2); 118 | EXPECT_EQ(2, queue->peek()); 119 | EXPECT_EQ(queue->size(), 1); 120 | } 121 | } 122 | 123 | 124 | TEST_F(QueueTest, testPoll) { 125 | for (queuePtr& queue : queues) { 126 | queue->offer(2); 127 | EXPECT_EQ(2, queue->poll()); 128 | EXPECT_EQ(queue->size(), 0); 129 | } 130 | } 131 | 132 | 133 | TEST_F(QueueTest, testExhaustively) { 134 | for (queuePtr& queue : queues) { 135 | ASSERT_TRUE(queue->isEmpty()); 136 | queue->offer(1); 137 | ASSERT_FALSE(queue->isEmpty()); 138 | queue->offer(2); 139 | EXPECT_EQ(queue->size(), 2); 140 | EXPECT_EQ(1, queue->peek()); 141 | EXPECT_EQ(queue->size(), 2); 142 | EXPECT_EQ(1, (int) queue->poll()); 143 | EXPECT_EQ(queue->size(), 1); 144 | EXPECT_EQ(2, (int) queue->peek()); 145 | EXPECT_EQ(queue->size(), 1); 146 | EXPECT_EQ(2, (int) queue->poll()); 147 | EXPECT_EQ(queue->size(), 0); 148 | ASSERT_TRUE(queue->isEmpty()); 149 | 150 | } 151 | } 152 | #endif 153 | 154 | } // namespace dsa 155 | -------------------------------------------------------------------------------- /src/test/cpp/algorithms/datastructures/stack/StackTest.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akzare/Algorithms/8d2c677c67fd05cbf9c7c87e4a8516a694481973/src/test/cpp/algorithms/datastructures/stack/StackTest.cpp -------------------------------------------------------------------------------- /src/test/cpp/algorithms/dp/DpTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file DpTest.cpp 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 14 July 2020 6 | * @version 0.1 7 | * @brief Test all dynamic programming algorithms under various constraints. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace dsa { 32 | 33 | TEST(LongestPalindromeSubsequenceTest, testSample) { 34 | EXPECT_EQ(LongestPalindromeSubsequence::lps("bbbab"), 4); // Outputs 4 since "bbbb" is valid soln 35 | EXPECT_EQ(LongestPalindromeSubsequence::lps("bccd"), 2); // Outputs 2 since "cc" is valid soln 36 | } 37 | 38 | 39 | TEST(MaximumSubarrayTest, testSample) { 40 | EXPECT_EQ(MaximumSubarray::maximumSubarrayValue(std::vector{-5}), -5); 41 | EXPECT_EQ(MaximumSubarray::maximumSubarrayValue(std::vector{-5, -4, -10, -3, -1, -12, -6}), -1); 42 | EXPECT_EQ(MaximumSubarray::maximumSubarrayValue(std::vector{1, 2, 1, -7, 2, -1, 40, -89}), 41); 43 | } 44 | 45 | 46 | TEST(LongestIncreasingSubsequenceTest, testSample) { 47 | EXPECT_EQ(LongestIncreasingSubsequence::lis(std::vector{1, 3, 2, 4, 3}), 3); // 3 48 | EXPECT_EQ(LongestIncreasingSubsequence::lis(std::vector{2, 7, 4, 3, 8}), 3); // 3 49 | EXPECT_EQ(LongestIncreasingSubsequence::lis(std::vector{5, 4, 3, 2, 1}), 1); // 1 50 | EXPECT_EQ(LongestIncreasingSubsequence::lis(std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9}), 9); // 9 51 | } 52 | 53 | 54 | TEST(LongestCommonSubstringTest, testSample) { 55 | { 56 | std::vector A{'A', 'X', 'B', 'C', 'Y'}; 57 | std::vector B{'Z', 'A', 'Y', 'W', 'B', 'C'}; 58 | EXPECT_EQ(LongestCommonSubstring::lcs(A, B), "ABC"); 59 | } 60 | 61 | { 62 | std::vector A{'3', '9', '8', '3', '9', '7', '9', '7', '0'}; 63 | std::vector B{'3', '3', '9', '9', '9', '1', '7', '2', '0', '6'}; 64 | EXPECT_EQ(LongestCommonSubstring::lcs(A, B), "339970"); 65 | } 66 | } 67 | 68 | 69 | TEST(Knapsack01Test, testSample) { 70 | { 71 | int capacity = 10; 72 | std::vector V{1, 4, 8, 5}; 73 | std::vector W{3, 3, 5, 6}; 74 | std::vector itemsSel; 75 | std::vector itemsSelExpect{2, 1}; 76 | EXPECT_EQ(Knapsack_01::knapsack(capacity, W, V, itemsSel), 12); 77 | EXPECT_EQ(itemsSel, itemsSelExpect); 78 | } 79 | 80 | { 81 | int capacity = 7; 82 | std::vector V{2, 2, 4, 5, 3}; 83 | std::vector W{3, 1, 3, 4, 2}; 84 | std::vector itemsSel; 85 | std::vector itemsSelExpect{4, 3, 1}; 86 | EXPECT_EQ(Knapsack_01::knapsack(capacity, W, V, itemsSel), 10); 87 | EXPECT_EQ(itemsSel, itemsSelExpect); 88 | } 89 | } 90 | 91 | 92 | TEST(UnboundedKnapsackTest, testSample) { 93 | std::vector W{3, 6, 2}; 94 | std::vector V{5, 20, 3}; 95 | int knapsackValue = KnapsackUnbounded::unboundedKnapsackSpaceEfficient(10, W, V); 96 | std::cout << "Maximum knapsack value: " << knapsackValue << std::endl; 97 | EXPECT_EQ(knapsackValue, 26); 98 | } 99 | 100 | 101 | TEST(JosephusProblemTest, testSample) { 102 | int n = 41, k = 2; 103 | EXPECT_EQ(JosephusProblem::josephus(n, k), 18); 104 | 105 | n = 25; 106 | k = 18; 107 | EXPECT_EQ(JosephusProblem::josephus(n, k), 1); 108 | 109 | n = 5; 110 | k = 2; 111 | EXPECT_EQ(JosephusProblem::josephus(n, k), 2); 112 | } 113 | 114 | 115 | TEST(CoinChangeTest, testSample) { 116 | const std::vector coins{2, 6, 1}; 117 | EXPECT_EQ(CoinChange::coinChange(coins, 17), 5); 118 | EXPECT_EQ(CoinChange::coinChangeSpaceEfficient(coins, 17), 5); 119 | EXPECT_EQ(CoinChange::coinChangeRecursive(coins, 17), 5); 120 | } 121 | 122 | } // namespace dsa 123 | -------------------------------------------------------------------------------- /src/test/cpp/algorithms/graphtheory/BridgesAdjacencyListTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file BridgesAdjacencyListTest.cpp 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 11 July 2020 6 | * @version 0.1 7 | * @brief Bridges on an undirected graph unit test. 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace dsa { 24 | 25 | std::set> getSortedBridges(const std::vector& bridgeNodes) { 26 | std::set> bridges; 27 | for (unsigned i = 0; i < bridgeNodes.size(); i += 2) { 28 | int node1 = bridgeNodes[i]; 29 | int node2 = bridgeNodes[i + 1]; 30 | std::pair pair; 31 | if (node1 < node2) { 32 | pair = std::make_pair(node1, node2); 33 | } else { 34 | pair = std::make_pair(node2, node1); 35 | } 36 | bridges.insert(pair); 37 | } 38 | return std::move(bridges); 39 | } 40 | 41 | 42 | // Every edge should be a bridge if the input a tree 43 | TEST(BridgesAdjacencyListTest, testTreeCase) { 44 | Graph graph(12); 45 | graph.addUndirectedEdge(1, 0); 46 | graph.addUndirectedEdge(0, 2); 47 | graph.addUndirectedEdge(2, 5); 48 | graph.addUndirectedEdge(5, 6); 49 | graph.addUndirectedEdge(5, 11); 50 | graph.addUndirectedEdge(5, 4); 51 | graph.addUndirectedEdge(4, 10); 52 | graph.addUndirectedEdge(4, 3); 53 | graph.addUndirectedEdge(3, 7); 54 | graph.addUndirectedEdge(7, 8); 55 | graph.addUndirectedEdge(7, 9); 56 | 57 | std::unique_ptr solver = std::make_unique(&graph); 58 | std::set> sortedBridges = getSortedBridges(solver->findBridges()); 59 | 60 | const std::set> expected{ 61 | std::make_pair(0, 1), 62 | std::make_pair(0, 2), 63 | std::make_pair(2, 5), 64 | std::make_pair(5, 6), 65 | std::make_pair(5, 11), 66 | std::make_pair(4, 5), 67 | std::make_pair(4, 10), 68 | std::make_pair(3, 4), 69 | std::make_pair(3, 7), 70 | std::make_pair(7, 8), 71 | std::make_pair(7, 9)}; 72 | 73 | EXPECT_EQ(sortedBridges, expected); 74 | 75 | } 76 | 77 | 78 | // Every edge should be a bridge if the input a tree 79 | TEST(BridgesAdjacencyListTest, graphWithCyclesTest) { 80 | Graph graph(12); 81 | graph.addUndirectedEdge(1, 0); 82 | graph.addUndirectedEdge(0, 2); 83 | graph.addUndirectedEdge(3, 1); 84 | graph.addUndirectedEdge(2, 5); 85 | graph.addUndirectedEdge(5, 6); 86 | graph.addUndirectedEdge(5, 11); 87 | graph.addUndirectedEdge(5, 4); 88 | graph.addUndirectedEdge(4, 10); 89 | graph.addUndirectedEdge(4, 3); 90 | graph.addUndirectedEdge(3, 7); 91 | graph.addUndirectedEdge(7, 8); 92 | graph.addUndirectedEdge(7, 9); 93 | graph.addUndirectedEdge(11, 6); 94 | 95 | std::unique_ptr solver = std::make_unique(&graph); 96 | std::set> sortedBridges = getSortedBridges(solver->findBridges()); 97 | 98 | const std::set> expected{ 99 | std::make_pair(3, 7), std::make_pair(7, 8), std::make_pair(7, 9), std::make_pair(4, 10)}; 100 | 101 | EXPECT_EQ(sortedBridges, expected); 102 | } 103 | 104 | 105 | TEST(BridgesAdjacencyListTest, testGraphInSlides) { 106 | Graph graph(9); 107 | graph.addUndirectedEdge(0, 1); 108 | graph.addUndirectedEdge(1, 2); 109 | graph.addUndirectedEdge(2, 3); 110 | graph.addUndirectedEdge(2, 5); 111 | graph.addUndirectedEdge(2, 0); 112 | graph.addUndirectedEdge(3, 4); 113 | graph.addUndirectedEdge(5, 6); 114 | graph.addUndirectedEdge(6, 7); 115 | graph.addUndirectedEdge(7, 8); 116 | graph.addUndirectedEdge(8, 5); 117 | 118 | std::unique_ptr solver = std::make_unique(&graph); 119 | std::set> sortedBridges = getSortedBridges(solver->findBridges()); 120 | 121 | const std::set> expected{ 122 | std::make_pair(2, 3), std::make_pair(3, 4), std::make_pair(2, 5)}; 123 | 124 | EXPECT_EQ(sortedBridges, expected); 125 | } 126 | 127 | 128 | TEST(BridgesAdjacencyListTest, testDisconnectedGraph) { 129 | Graph graph(11); 130 | graph.addUndirectedEdge(0, 1); 131 | graph.addUndirectedEdge(2, 1); 132 | graph.addUndirectedEdge(3, 4); 133 | graph.addUndirectedEdge(5, 7); 134 | graph.addUndirectedEdge(5, 6); 135 | graph.addUndirectedEdge(6, 7); 136 | graph.addUndirectedEdge(8, 7); 137 | graph.addUndirectedEdge(8, 9); 138 | graph.addUndirectedEdge(8, 10); 139 | 140 | std::unique_ptr solver = std::make_unique(&graph); 141 | std::set> sortedBridges = getSortedBridges(solver->findBridges()); 142 | 143 | const std::set> expected{ 144 | std::make_pair(0, 1), 145 | std::make_pair(1, 2), 146 | std::make_pair(3, 4), 147 | std::make_pair(7, 8), 148 | std::make_pair(8, 9), 149 | std::make_pair(8, 10)}; 150 | 151 | EXPECT_EQ(sortedBridges, expected); 152 | } 153 | 154 | } // namespace dsa 155 | -------------------------------------------------------------------------------- /src/test/cpp/algorithms/graphtheory/TarjanSccSolverAdjacencyListTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file TarjanSccSolverAdjacencyListTest.cpp 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 11 July 2020 6 | * @version 0.1 7 | * @brief A Tarjan's Strongly Connected Components unit test. 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace dsa { 24 | 25 | TEST(TarjanSccSolverAdjacencyListTest, singletonCase) { 26 | int n = 1; 27 | Graph graph(n); 28 | 29 | std::unique_ptr solver = std::make_unique(&graph); 30 | std::set> sccList = solver->getSccs(); 31 | std::set> expected{{0}}; 32 | EXPECT_EQ(sccList, expected); 33 | EXPECT_EQ(solver->sccCount(), 1); 34 | solver = nullptr; 35 | } 36 | 37 | 38 | TEST(TarjanSccSolverAdjacencyListTest, testTwoDisjointComponents) { 39 | // TarjanScc_test(); 40 | 41 | int n = 5; 42 | Graph graph(n); 43 | 44 | graph.addDirectedEdge(0, 1); 45 | graph.addDirectedEdge(1, 0); 46 | graph.addDirectedEdge(2, 3); 47 | graph.addDirectedEdge(3, 4); 48 | graph.addDirectedEdge(4, 2); 49 | 50 | std::unique_ptr solver = std::make_unique(&graph); 51 | std::set> sccList = solver->getSccs(); 52 | 53 | // std::cout << "Number of Strongly Connected Components: " << solver->sccCount() << std::endl; 54 | // TarjanSccSolverAdjacencyList::printSCCList(sccList); 55 | 56 | std::set> expectedSccs{{0, 1}, {2, 3, 4}}; 57 | EXPECT_EQ(solver->sccCount(), expectedSccs.size()); 58 | EXPECT_EQ(sccList, expectedSccs); 59 | solver = nullptr; 60 | } 61 | 62 | 63 | TEST(TarjanSccSolverAdjacencyListTest, testButterflyCase) { 64 | int n = 5; 65 | Graph graph(n); 66 | 67 | graph.addDirectedEdge(0, 1); 68 | graph.addDirectedEdge(1, 2); 69 | graph.addDirectedEdge(2, 3); 70 | graph.addDirectedEdge(3, 1); 71 | graph.addDirectedEdge(1, 4); 72 | graph.addDirectedEdge(4, 0); 73 | 74 | std::unique_ptr solver = std::make_unique(&graph); 75 | std::set> sccList = solver->getSccs(); 76 | 77 | std::set> expectedSccs{{0, 1, 2, 3, 4}}; 78 | EXPECT_EQ(solver->sccCount(), expectedSccs.size()); 79 | EXPECT_EQ(sccList, expectedSccs); 80 | solver = nullptr; 81 | } 82 | 83 | 84 | TEST(TarjanSccSolverAdjacencyListTest, testFirstGraphInSlides) { 85 | int n = 9; 86 | Graph graph(n); 87 | 88 | graph.addDirectedEdge(0, 1); 89 | graph.addDirectedEdge(1, 0); 90 | graph.addDirectedEdge(0, 8); 91 | graph.addDirectedEdge(8, 0); 92 | graph.addDirectedEdge(8, 7); 93 | graph.addDirectedEdge(7, 6); 94 | graph.addDirectedEdge(6, 7); 95 | graph.addDirectedEdge(1, 7); 96 | graph.addDirectedEdge(2, 1); 97 | graph.addDirectedEdge(2, 6); 98 | graph.addDirectedEdge(5, 6); 99 | graph.addDirectedEdge(2, 5); 100 | graph.addDirectedEdge(5, 3); 101 | graph.addDirectedEdge(3, 2); 102 | graph.addDirectedEdge(4, 3); 103 | graph.addDirectedEdge(4, 5); 104 | 105 | std::unique_ptr solver = std::make_unique(&graph); 106 | std::set> sccList = solver->getSccs(); 107 | 108 | std::cout << "Number of Strongly Connected Components: " << solver->sccCount() << std::endl; 109 | TarjanSccSolverAdjacencyList::printSCCList(sccList); 110 | 111 | std::set> expectedSccs{{0, 1, 8}, {7, 6}, {2, 3, 5}, {4}}; 112 | EXPECT_EQ(solver->sccCount(), expectedSccs.size()); 113 | EXPECT_EQ(sccList, expectedSccs); 114 | solver = nullptr; 115 | } 116 | 117 | 118 | TEST(TarjanSccSolverAdjacencyListTest, testLastGraphInSlides) { 119 | int n = 8; 120 | Graph graph(n); 121 | 122 | graph.addDirectedEdge(6, 0); 123 | graph.addDirectedEdge(6, 2); 124 | graph.addDirectedEdge(3, 4); 125 | graph.addDirectedEdge(6, 4); 126 | graph.addDirectedEdge(2, 0); 127 | graph.addDirectedEdge(0, 1); 128 | graph.addDirectedEdge(4, 5); 129 | graph.addDirectedEdge(5, 6); 130 | graph.addDirectedEdge(3, 7); 131 | graph.addDirectedEdge(7, 5); 132 | graph.addDirectedEdge(1, 2); 133 | graph.addDirectedEdge(7, 3); 134 | graph.addDirectedEdge(5, 0); 135 | 136 | std::unique_ptr solver = std::make_unique(&graph); 137 | std::set> sccList = solver->getSccs(); 138 | std::set> expectedSccs{{0, 2, 1}, {3, 7}, {6, 5, 4}}; 139 | EXPECT_EQ(solver->sccCount(), expectedSccs.size()); 140 | EXPECT_EQ(sccList, expectedSccs); 141 | solver = nullptr; 142 | } 143 | 144 | } // namespace dsa 145 | -------------------------------------------------------------------------------- /src/test/cpp/algorithms/graphtheory/treealgorithms/RootingTreeTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file MathTest.cpp 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 15 July 2020 6 | * @version 0.1 7 | * @brief Math Unit Test. 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace dsa { 25 | 26 | 27 | TEST(RootingTreeTest, testSimpleRooting1) { 28 | Graph graph(9); 29 | graph.addUndirectedEdge(0, 1); 30 | graph.addUndirectedEdge(2, 1); 31 | graph.addUndirectedEdge(2, 3); 32 | graph.addUndirectedEdge(3, 4); 33 | graph.addUndirectedEdge(5, 3); 34 | graph.addUndirectedEdge(2, 6); 35 | graph.addUndirectedEdge(6, 7); 36 | graph.addUndirectedEdge(6, 8); 37 | // Graph 1 rooted at 6 should look like: 38 | // 6 39 | // 2 7 8 40 | // 1 3 41 | // 0 4 5 42 | 43 | std::unique_ptr node6 = std::make_unique(&graph, 6); 44 | 45 | // Layer 0: [6] 46 | EXPECT_EQ((*node6)().id(), 6); 47 | EXPECT_EQ((*node6)().parent(), nullptr); 48 | 49 | 50 | std::unordered_set children_root = node6->children(); 51 | std::set expectedIds_node6{2,7,8}; 52 | std::set expectedIds_node2{1,3}; 53 | std::set expectedIds_node3{4,5}; 54 | std::set expectedIds_node1{0}; 55 | std::set asIsIds_node6; 56 | std::set asIsIds_node2; 57 | std::set asIsIds_node3; 58 | std::set asIsIds_node1; 59 | for (auto c : children_root) { // Layer 1 node 6(root): [2, 7, 8] 60 | asIsIds_node6.insert((*c).id()); 61 | if ((*c).id() == 2) { // Layer 2 node 2: [1, 3] 62 | std::unordered_set children_node2 = (*c).children(); 63 | for (auto c2 : children_node2) { 64 | asIsIds_node2.insert((*c2).id()); 65 | if ((*c2).id() == 3) { // Layer 3 node 3: [4, 5] 66 | std::unordered_set children_node3 = (*c2).children(); 67 | for (auto c3 : children_node3) { 68 | asIsIds_node3.insert((*c3).id()); 69 | } 70 | } 71 | if ((*c2).id() == 1) { // Layer 3 node 1: [0] 72 | std::unordered_set children_node1 = (*c2).children(); 73 | for (auto c1 : children_node1) { 74 | asIsIds_node1.insert((*c1).id()); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | 81 | EXPECT_EQ(asIsIds_node6, expectedIds_node6); 82 | EXPECT_EQ(asIsIds_node2, expectedIds_node2); 83 | EXPECT_EQ(asIsIds_node3, expectedIds_node3); 84 | EXPECT_EQ(asIsIds_node1, expectedIds_node1); 85 | 86 | // TODO(williamfiset): also verify the parent pointers are pointing at the correct nodes. 87 | } 88 | 89 | 90 | TEST(RootingTreeTest, testSimpleRootingPrint) { 91 | Graph graph(9); 92 | 93 | graph.addUndirectedEdge(0, 1); 94 | graph.addUndirectedEdge(2, 1); 95 | graph.addUndirectedEdge(2, 3); 96 | graph.addUndirectedEdge(3, 4); 97 | graph.addUndirectedEdge(5, 3); 98 | graph.addUndirectedEdge(2, 6); 99 | graph.addUndirectedEdge(6, 7); 100 | graph.addUndirectedEdge(6, 8); 101 | 102 | // Rooted at 6 the tree should look like: 103 | // 6 104 | // 2 7 8 105 | // 1 3 106 | // 0 4 5 107 | 108 | RootingTree *root = new RootingTree(&graph, 6); 109 | 110 | // Layer 0: [6] 111 | std::cout << "Layer 0: [6]: "; 112 | std::cout << (*root) << std::endl; 113 | 114 | 115 | #define PRINT_CHILDREN(r) \ 116 | do { \ 117 | std::cout << "["; \ 118 | for (auto c : r) std::cout << (*c) << ","; \ 119 | std::cout << "]"; \ 120 | } while(0) 121 | 122 | 123 | // Layer 1: [2, 7, 8] 124 | std::unordered_set children_root = root->children(); 125 | std::cout << "Layer 1: [2, 7, 8]: "; 126 | PRINT_CHILDREN(children_root); 127 | std::cout << std::endl; 128 | 129 | 130 | // Layer 2: [1, 3] 131 | int expectedId = 2; 132 | auto idComparer = [&expectedId](auto c2) -> bool { return ((*c2).id() == expectedId); }; 133 | auto itr = std::find_if(children_root.begin(), children_root.end(), idComparer); 134 | std::unordered_set children_layer2 = (*itr)->children(); 135 | std::cout << "Layer 2: [1, 3]: "; 136 | PRINT_CHILDREN(children_layer2); 137 | std::cout << std::endl; 138 | 139 | 140 | // Layer 3: [0], [4, 5] 141 | expectedId = 3; 142 | itr = std::find_if(children_layer2.begin(), children_layer2.end(), idComparer); 143 | std::unordered_set children_layer3 = (*itr)->children(); 144 | std::cout << "Layer 3: [4, 5]: "; 145 | PRINT_CHILDREN(children_layer3); 146 | std::cout << std::endl; 147 | 148 | delete root; 149 | } 150 | 151 | } // namespace dsa 152 | -------------------------------------------------------------------------------- /src/test/cpp/algorithms/math/MathTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file MathTest.cpp 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 15 July 2020 6 | * @version 0.1 7 | * @brief Math Unit Test. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace dsa { 28 | 29 | namespace math { 30 | 31 | TEST(MathTest, testGCD) { 32 | EXPECT_EQ(GCD::gcd(12, 18), 6); // 6 33 | EXPECT_EQ(GCD::gcd(-12, 18), 6); // 6 34 | EXPECT_EQ(GCD::gcd(12, -18), 6); // 6 35 | EXPECT_EQ(GCD::gcd(-12, -18), 6); // 6 36 | 37 | EXPECT_EQ(GCD::gcd(5, 0), 5); // 5 38 | EXPECT_EQ(GCD::gcd(0, 5), 5); // 5 39 | EXPECT_EQ(GCD::gcd(-5, 0), 5); // 5 40 | EXPECT_EQ(GCD::gcd(0, -5), 5); // 5 41 | EXPECT_EQ(GCD::gcd(0, 0), 0); // 0 42 | } 43 | 44 | 45 | TEST(MathTest, testisPrime) { 46 | EXPECT_TRUE(IsPrime::isPrime(5)); 47 | EXPECT_TRUE(IsPrime::isPrime(31)); 48 | EXPECT_TRUE(IsPrime::isPrime(1433)); 49 | // std::cout << IsPrime::isPrime(876385777553687833L) << std::endl; 50 | } 51 | 52 | 53 | TEST(MathTest, testLCM) { 54 | EXPECT_EQ(LCM::lcm(12, 18), 36); // 36 55 | EXPECT_EQ(LCM::lcm(-12, 18), 36); // 36 56 | EXPECT_EQ(LCM::lcm(12, -18), 36); // 36 57 | EXPECT_EQ(LCM::lcm(-12, -18), 36); // 36 58 | } 59 | 60 | 61 | TEST(PrimeFactorizationTest, testPF) { 62 | #define PRINT_FACTORIZATION(r) \ 63 | do { \ 64 | std::cout << "["; \ 65 | for (auto pf : PrimeFactorization::primeFactorization(r)) std::cout << pf << ","; \ 66 | std::cout << "]"; \ 67 | } while(0) 68 | 69 | { 70 | // PRINT_FACTORIZATION(7); // [7] 71 | const std::multiset v{7}; 72 | EXPECT_EQ(PrimeFactorization::primeFactorization(7), v); 73 | } 74 | 75 | { 76 | // PRINT_FACTORIZATION(100); // [2,2,5,5] 77 | const std::multiset v{2,2,5,5}; 78 | EXPECT_EQ(PrimeFactorization::primeFactorization(100), v); 79 | } 80 | 81 | { 82 | // PRINT_FACTORIZATION(666); // [2,3,3,37] 83 | const std::multiset v{2,3,3,37}; 84 | EXPECT_EQ(PrimeFactorization::primeFactorization(666), v); 85 | } 86 | 87 | { 88 | // PRINT_FACTORIZATION(872342345); // [5, 7, 7, 67, 19, 2797] 89 | const std::multiset v{5,7,7,67,19,2797}; 90 | EXPECT_EQ(PrimeFactorization::primeFactorization(872342345), v); 91 | } 92 | } 93 | 94 | } // namespace math 95 | 96 | } // namespace dsa 97 | -------------------------------------------------------------------------------- /src/test/cpp/algorithms/other/BitManipulationsTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file BitManipulationsTest.cpp 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 13 July 2020 6 | * @version 0.1 7 | * @brief Bit manipulation operations unit test. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace dsa { 25 | 26 | TEST(BitManipulationsTest, testSetBit) { 27 | EXPECT_EQ(BitManipulations::setBit(0, 0), 0b1); 28 | EXPECT_EQ(BitManipulations::setBit(0, 1), 0b10); 29 | EXPECT_EQ(BitManipulations::setBit(0, 2), 0b100); 30 | EXPECT_EQ(BitManipulations::setBit(0, 3), 0b1000); 31 | EXPECT_EQ(BitManipulations::setBit(0, 4), 0b10000); 32 | EXPECT_EQ(BitManipulations::setBit(0, 5), 0b100000); 33 | } 34 | 35 | 36 | TEST(BitManipulationsTest, testPowerOfTwo) { 37 | EXPECT_FALSE(BitManipulations::isPowerOfTwo(0)); 38 | EXPECT_FALSE(BitManipulations::isPowerOfTwo(-1)); 39 | EXPECT_FALSE(BitManipulations::isPowerOfTwo(7)); 40 | EXPECT_FALSE(BitManipulations::isPowerOfTwo(9)); 41 | EXPECT_FALSE(BitManipulations::isPowerOfTwo(123456789)); 42 | 43 | EXPECT_TRUE(BitManipulations::isPowerOfTwo(1)); 44 | EXPECT_TRUE(BitManipulations::isPowerOfTwo(2)); 45 | EXPECT_TRUE(BitManipulations::isPowerOfTwo(4)); 46 | EXPECT_TRUE(BitManipulations::isPowerOfTwo(2048)); 47 | EXPECT_TRUE(BitManipulations::isPowerOfTwo(1 << 20)); 48 | } 49 | 50 | 51 | TEST(BitManipulationsTest, testClearBit) { 52 | EXPECT_EQ(BitManipulations::clearBit(0b0000, 1), 0); 53 | EXPECT_EQ(BitManipulations::clearBit(0b0100, 2), 0); 54 | EXPECT_EQ(BitManipulations::clearBit(0b0001, 0), 0); 55 | EXPECT_EQ(BitManipulations::clearBit(0b1111, 0), 14); 56 | } 57 | 58 | 59 | TEST(UniqueCombinationsTest, testCombinations) { 60 | UniqueCombunations_test(); 61 | } 62 | 63 | } // namespace dsa 64 | -------------------------------------------------------------------------------- /src/test/cpp/algorithms/sorting/SortingTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file SortingTest.cpp 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to C++) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 13 July 2020 6 | * @version 0.1 7 | * @brief Test all sorting algorithms under various constraints. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace dsa { 29 | 30 | namespace sortingtest { 31 | 32 | std::vector genRandIntVec(int start_in, int end_in, int num_in) 33 | { 34 | std::vector randvec; 35 | // engine only provides a source of randomness 36 | std::mt19937_64 rng; 37 | // initialize the random number generator with time-dependent seed 38 | uint64_t timeSeed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); 39 | std::seed_seq ss{uint32_t(timeSeed & 0xffffffff), uint32_t(timeSeed>>32)}; 40 | rng.seed(ss); 41 | std::uniform_int_distribution dist(start_in, end_in); 42 | 43 | for(int i=0; i < num_in; ++i) { 44 | randvec.push_back(dist(rng)); 45 | } 46 | 47 | return std::move(randvec); 48 | } 49 | 50 | 51 | // ToDo: QuickSort3 does not pass the test! 52 | std::array&)>, 4> sortingAlgorithms = {{ 53 | &BubbleSort::sort, 54 | &BucketSort::sort, 55 | &CountingSort::sort, 56 | &Heapsort::sort, 57 | // &QuickSort3::sort 58 | }}; 59 | 60 | 61 | TEST(SortingTest, verifySortingAlgorithms_smallPositiveIntegersOnly) { 62 | // BubbleSort_test(); 63 | 64 | for (int size = 0; size < 100; size++) { 65 | for (auto algorithm : sortingAlgorithms) { 66 | std::vector rand_vec = genRandIntVec(0, 51, size); 67 | std::vector copy_rand_vec = rand_vec; 68 | 69 | std::sort(rand_vec.begin(), rand_vec.end()); 70 | algorithm(copy_rand_vec); 71 | 72 | EXPECT_EQ(rand_vec, copy_rand_vec); 73 | } 74 | } 75 | } 76 | 77 | 78 | TEST(SortingTest, verifySortingAlgorithms_smallNegativeIntegersOnly) { 79 | for (int size = 0; size < 100; size++) { 80 | for (auto algorithm : sortingAlgorithms) { 81 | std::vector rand_vec = genRandIntVec(-50, 51, size); 82 | std::vector copy_rand_vec = rand_vec; 83 | 84 | std::sort(rand_vec.begin(), rand_vec.end()); 85 | algorithm(copy_rand_vec); 86 | 87 | EXPECT_EQ(rand_vec, copy_rand_vec); 88 | } 89 | } 90 | } 91 | 92 | } // namespace sortingtest 93 | 94 | } // namespace dsa 95 | -------------------------------------------------------------------------------- /src/test/python/algorithms/datastructures/queue/IntQueueTest.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file IntQueueTest.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 23 Jun 2020 6 | * @version 0.1 7 | * @brief An IntQueue unit test. 8 | ''' 9 | 10 | import unittest 11 | from collections import deque 12 | import array as arr 13 | import random 14 | from LinkedQueue import LinkedQueue 15 | from ArrayQueue import ArrayQueue 16 | from IntQueue import IntQueue 17 | 18 | 19 | class IntQueueTest(unittest.TestCase): 20 | 21 | def setUp(self): 22 | pass 23 | 24 | 25 | def test_EmptyQueue(self): 26 | queue = IntQueue(2) 27 | self.assertTrue(queue.isEmpty()) 28 | self.assertEqual(queue.size(), 0) 29 | 30 | 31 | def test_offerOneElement(self): 32 | queue = IntQueue(1) 33 | queue.offer(77) 34 | self.assertEqual(queue.size(), 1) 35 | 36 | 37 | def test_All(self): 38 | n = 5 39 | queue = IntQueue(10) 40 | self.assertTrue(queue.isEmpty()) 41 | for i in range(1, n+1): 42 | queue.offer(i) 43 | self.assertFalse(queue.isEmpty()) 44 | 45 | for i in range(1, n+1): 46 | self.assertEqual(i, int(queue.peek())) 47 | self.assertEqual(i, int(queue.poll())) 48 | self.assertEqual(queue.size(), n - i) 49 | 50 | self.assertTrue(queue.isEmpty()) 51 | n = 8 52 | for i in range(1, n+1): 53 | queue.offer(i) 54 | self.assertFalse(queue.isEmpty()) 55 | 56 | for i in range(1, n+1): 57 | self.assertEqual(i, int(queue.peek())) 58 | self.assertEqual(i, int(queue.poll())) 59 | self.assertEqual(queue.size(), n - i) 60 | 61 | self.assertTrue(queue.isEmpty()) 62 | n = 9; 63 | for i in range(1, n+1): 64 | queue.offer(i) 65 | self.assertFalse(queue.isEmpty()) 66 | 67 | for i in range(1, n+1): 68 | self.assertEqual(i, int(queue.peek())) 69 | self.assertEqual(i, int(queue.poll())) 70 | self.assertEqual(queue.size(), n - i) 71 | 72 | self.assertTrue(queue.isEmpty()) 73 | n = 10 74 | for i in range(1, n+1): 75 | queue.offer(i) 76 | self.assertFalse(queue.isEmpty()) 77 | 78 | for i in range(1, n+1): 79 | self.assertEqual(i, int(queue.peek())) 80 | self.assertEqual(i, int(queue.poll())) 81 | self.assertEqual(queue.size(), n - i); 82 | 83 | self.assertTrue(queue.isEmpty()) 84 | 85 | 86 | def test_PeekOneElement(self): 87 | queue = IntQueue(1) 88 | queue.offer(77) 89 | self.assertTrue(queue.peek() == 77) 90 | self.assertEqual(queue.size(), 1) 91 | 92 | 93 | def test_pollOneElement(self): 94 | queue = IntQueue(1) 95 | queue.offer(77) 96 | self.assertTrue(queue.poll() == 77) 97 | self.assertEqual(queue.size(), 0) 98 | 99 | 100 | def test_Random(self): 101 | for qSize in range(1, 51): 102 | intQ = IntQueue(qSize) 103 | arrayDeque = deque() 104 | 105 | self.assertEqual(len(arrayDeque) == 0, intQ.isEmpty()) 106 | self.assertEqual(len(arrayDeque), intQ.size()) 107 | 108 | for operations in range(0, 5000): 109 | r = random.random() 110 | 111 | if r < 0.60: 112 | elem = random.randrange(1000) 113 | if len(arrayDeque) < qSize: 114 | arrayDeque.append(elem) 115 | intQ.offer(elem) 116 | 117 | else: 118 | if len(arrayDeque) != 0: 119 | self.assertEqual(int(arrayDeque.popleft()), int(intQ.poll())) 120 | 121 | self.assertEqual(len(arrayDeque) == 0, intQ.isEmpty()) 122 | self.assertEqual(len(arrayDeque), intQ.size()) 123 | 124 | if __name__ == '__main__': 125 | unittest.main() -------------------------------------------------------------------------------- /src/test/python/algorithms/datastructures/queue/QueueTest.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file QueueTest.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 23 Jun 2020 6 | * @version 0.1 7 | * @brief A queue unit test. 8 | ''' 9 | 10 | import unittest 11 | from collections import deque 12 | import array as arr 13 | import random 14 | from LinkedQueue import LinkedQueue 15 | from ArrayQueue import ArrayQueue 16 | from IntQueue import IntQueue 17 | 18 | 19 | class QueueTest(unittest.TestCase): 20 | 21 | def setUp(self): 22 | self.queues = [] 23 | self.queues.append(LinkedQueue()) 24 | self.queues.append(ArrayQueue(0, 3)) 25 | self.queues.append(IntQueue(2)) 26 | 27 | 28 | def tearDown(self): 29 | for queue in self.queues: 30 | while not queue.isEmpty(): 31 | queue.poll() 32 | 33 | 34 | def test_EmptyQueue(self): 35 | for queue in self.queues: 36 | self.assertTrue(queue.isEmpty()) 37 | self.assertEqual(queue.size(), 0) 38 | 39 | 40 | def test_PollOnEmpty(self): 41 | for queue in self.queues: 42 | with self.assertRaises(Exception): 43 | queue.poll() 44 | 45 | 46 | def test_PeekOnEmpty(self): 47 | for queue in self.queues: 48 | with self.assertRaises(Exception): 49 | queue.peek() 50 | 51 | 52 | def test_Offer(self): 53 | for queue in self.queues: 54 | queue.offer(2) 55 | self.assertEqual(queue.size(), 1) 56 | 57 | 58 | def test_Peek(self): 59 | for queue in self.queues: 60 | queue.offer(2); 61 | self.assertEqual(2, int(queue.peek())) 62 | self.assertEqual(queue.size(), 1) 63 | 64 | 65 | def test_Poll(self): 66 | for queue in self.queues: 67 | queue.offer(2) 68 | self.assertEqual(2, int(queue.poll())) 69 | self.assertEqual(queue.size(), 0) 70 | 71 | 72 | def test_Exhaustively(self): 73 | for queue in self.queues: 74 | self.assertTrue(queue.isEmpty()) 75 | queue.offer(1) 76 | self.assertFalse(queue.isEmpty()) 77 | queue.offer(2) 78 | self.assertEqual(queue.size(), 2) 79 | self.assertEqual(1, int(queue.peek())) 80 | self.assertEqual(queue.size(), 2) 81 | self.assertEqual(1, int(queue.poll())) 82 | self.assertEqual(queue.size(), 1) 83 | self.assertEqual(2, int(queue.peek())) 84 | self.assertEqual(queue.size(), 1) 85 | self.assertEqual(2, int(queue.poll())) 86 | self.assertEqual(queue.size(), 0) 87 | self.assertTrue(queue.isEmpty()) 88 | 89 | 90 | if __name__ == '__main__': 91 | unittest.main() -------------------------------------------------------------------------------- /src/test/python/algorithms/datastructures/stack/StackTest.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file StackTest.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 23 Jun 2020 6 | * @version 0.1 7 | * @brief A stack unit test. 8 | ''' 9 | 10 | import unittest 11 | from collections import deque 12 | import array as arr 13 | import random 14 | from ListStack import ListStack 15 | from ArrayStack import ArrayStack 16 | from IntStack import IntStack 17 | 18 | 19 | 20 | class StackTest(unittest.TestCase): 21 | 22 | 23 | def setUp(self): 24 | self.stacks = [] 25 | self.stacks.append(ListStack()) 26 | self.stacks.append(ArrayStack(0)) 27 | self.stacks.append(IntStack(2)) 28 | 29 | 30 | def tearDown(self): 31 | for stack in self.stacks: 32 | while not stack.isEmpty(): 33 | stack.pop() 34 | 35 | 36 | def test_EmptyStack(self): 37 | for stack in self.stacks: 38 | self.assertTrue(stack.isEmpty()); 39 | self.assertEqual(stack.size(), 0); 40 | 41 | 42 | def test_PopOnEmpty(self): 43 | for stack in self.stacks: 44 | with self.assertRaises(Exception): 45 | stack.pop() 46 | 47 | 48 | def test_PeekOnEmpty(self): 49 | for stack in self.stacks: 50 | with self.assertRaises(Exception): 51 | stack.peek() 52 | 53 | 54 | def test_Push(self): 55 | for stack in self.stacks: 56 | stack.push(2) 57 | self.assertEqual(stack.size(), 1) 58 | 59 | 60 | def test_Peek(self): 61 | for stack in self.stacks: 62 | stack.push(2) 63 | self.assertEqual(2, int(stack.peek())) 64 | self.assertEqual(stack.size(), 1) 65 | 66 | 67 | def test_Pop(self): 68 | for stack in self.stacks: 69 | stack.push(2); 70 | self.assertEqual(2, int(stack.pop())) 71 | self.assertEqual(stack.size(), 0); 72 | 73 | 74 | 75 | def test_Exhaustively(self): 76 | for stack in self.stacks: 77 | self.assertTrue(stack.isEmpty()) 78 | stack.push(1) 79 | self.assertFalse(stack.isEmpty()) 80 | stack.push(2) 81 | self.assertEqual(stack.size(), 2) 82 | self.assertEqual(2, int(stack.peek())) 83 | self.assertEqual(stack.size(), 2) 84 | self.assertEqual(2, int(stack.pop())) 85 | self.assertEqual(stack.size(), 1) 86 | self.assertEqual(1, int(stack.peek())) 87 | self.assertEqual(stack.size(), 1) 88 | self.assertEqual(1, int(stack.pop())) 89 | self.assertEqual(stack.size(), 0) 90 | self.assertTrue(stack.isEmpty()) 91 | 92 | 93 | if __name__ == '__main__': 94 | unittest.main() -------------------------------------------------------------------------------- /src/test/python/algorithms/other/BitManipulationsTest.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file BitManipulationsTest.py 3 | * @author (original JAVA) Micah Stairs 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief A BitManipulations unit test. 8 | ''' 9 | 10 | import unittest 11 | from collections import deque 12 | import random 13 | from BitManipulations import BitManipulations 14 | 15 | class BitManipulationsTest(unittest.TestCase): 16 | 17 | def setUp(self): 18 | self.bm = BitManipulations() 19 | 20 | 21 | 22 | def test_SetBit(self): 23 | self.assertEqual(self.bm.setBit(0, 0), 0b1) 24 | self.assertEqual(self.bm.setBit(0, 1), 0b10) 25 | self.assertEqual(self.bm.setBit(0, 2), 0b100) 26 | self.assertEqual(self.bm.setBit(0, 3), 0b1000) 27 | self.assertEqual(self.bm.setBit(0, 4), 0b10000) 28 | self.assertEqual(self.bm.setBit(0, 5), 0b100000) 29 | 30 | 31 | 32 | def test_PowerOfTwo(self): 33 | self.assertFalse(self.bm.isPowerOfTwo(0)) 34 | self.assertFalse(self.bm.isPowerOfTwo(-1)) 35 | self.assertFalse(self.bm.isPowerOfTwo(7)) 36 | self.assertFalse(self.bm.isPowerOfTwo(9)) 37 | self.assertFalse(self.bm.isPowerOfTwo(123456789)) 38 | 39 | self.assertTrue(self.bm.isPowerOfTwo(1)) 40 | self.assertTrue(self.bm.isPowerOfTwo(2)) 41 | self.assertTrue(self.bm.isPowerOfTwo(4)) 42 | self.assertTrue(self.bm.isPowerOfTwo(2048)) 43 | self.assertTrue(self.bm.isPowerOfTwo(1 << 20)) 44 | 45 | 46 | 47 | def test_ClearBit(self): 48 | self.assertEqual(self.bm.clearBit(0b0000, 1), 0) 49 | self.assertEqual(self.bm.clearBit(0b0100, 2), 0) 50 | self.assertEqual(self.bm.clearBit(0b0001, 0), 0) 51 | self.assertEqual(self.bm.clearBit(0b1111, 0), 14) 52 | 53 | 54 | if __name__ == '__main__': 55 | unittest.main() -------------------------------------------------------------------------------- /src/test/python/algorithms/other/LazyRangeAdderTest.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file LazyRangeAdderTest.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 30 Jun 2020 6 | * @version 0.1 7 | * @brief LazyRangeAdderTest unit test. 8 | ''' 9 | 10 | import unittest 11 | import copy 12 | from collections import deque 13 | import array as arr 14 | import random 15 | from LazyRangeAdder import LazyRangeAdder 16 | 17 | 18 | class LazyRangeAdderTest(unittest.TestCase): 19 | 20 | def setUp(self): 21 | pass 22 | 23 | 24 | def test_rangeUpdateTest1(self): 25 | la = LazyRangeAdder() 26 | a = [10, 5, 20, 40] 27 | la.lazyRangeAdder(a) 28 | la.add(0, 1, 10) 29 | la.add(1, 3, 20) 30 | la.add(2, 2, 30) 31 | la.done() 32 | expected = [20, 35, 70, 60] 33 | self.assertEqual(expected, a) 34 | 35 | 36 | 37 | def test_rangeUpdateTest2(self): 38 | la = LazyRangeAdder() 39 | a = [270, 311, 427, 535, 334, 193, 174] 40 | la.lazyRangeAdder(a) 41 | la.add(2, 5, 32) 42 | la.add(0, 4, 101) 43 | la.add(5, 6, -73) 44 | la.done() 45 | expected = [371, 412, 560, 668, 467, 152, 101] 46 | self.assertEqual(expected, a) 47 | 48 | 49 | 50 | def test_randomRangeAdditionTests(self): 51 | """ 52 | Try several different array sizes 53 | """ 54 | la = LazyRangeAdder() 55 | for n in range(1, 1000): 56 | 57 | arr1 = [0]*n 58 | self.randomFill(arr1) 59 | arr2 = copy.deepcopy(arr1) 60 | 61 | la.lazyRangeAdder(arr1) 62 | 63 | # Do 50 random range adds 64 | for i in range(0, 50): 65 | # Generate a random range 66 | l = self.randValue(0, n) 67 | r = self.randValue(0, n) 68 | l = min(l, r) 69 | r = max(l, r) 70 | 71 | x = self.randValue(-100, 100) 72 | la.add(l, r, x) 73 | self.slowRangeAdd(arr2, l, r, x) 74 | 75 | la.done() 76 | 77 | self.assertEqual(arr1, arr2) 78 | 79 | 80 | 81 | def slowRangeAdd(self, arr, l, r, x): 82 | """ 83 | Adds `x` to the range [l, r] in arr 84 | """ 85 | for i in range(l, r+1): 86 | arr[i] += x 87 | 88 | 89 | 90 | def randomFill(self, arr): 91 | for i in range(0, len(arr)): 92 | arr[i] = self.randValue(0, 1000) 93 | 94 | 95 | 96 | def randValue(self, min, max): 97 | """ 98 | Generates a random number between [min, max) 99 | """ 100 | return min + int(random.random() * ((max - min))) 101 | 102 | 103 | 104 | if __name__ == '__main__': 105 | unittest.main() -------------------------------------------------------------------------------- /src/test/python/algorithms/other/SlidingWindowMaximumTest.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file SlidingWindowMaximumTest.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 30 Jun 2020 6 | * @version 0.1 7 | * @brief SlidingWindowMaximumTest unit test. 8 | ''' 9 | 10 | import unittest 11 | import copy 12 | from collections import deque 13 | import array as arr 14 | import random 15 | import sys 16 | from SlidingWindowMaximum import SlidingWindowMaximum 17 | 18 | 19 | class SlidingWindowMaximumTest(unittest.TestCase): 20 | 21 | def setUp(self): 22 | self.TESTS = 1500 23 | 24 | 25 | def test_smallWindowTest(self): 26 | 27 | values = [1, 2, 1, 3, 0, 4] 28 | w = SlidingWindowMaximum(values) 29 | 30 | w.advance() 31 | self.assertEqual(1, w.getMax()) 32 | w.advance() 33 | self.assertEqual(2, w.getMax()) 34 | w.advance() 35 | self.assertEqual(2, w.getMax()) 36 | w.shrink() 37 | self.assertEqual(2, w.getMax()) 38 | w.shrink() 39 | self.assertEqual(1, w.getMax()) 40 | w.advance() 41 | self.assertEqual(3, w.getMax()) 42 | w.advance() 43 | self.assertEqual(3, w.getMax()) 44 | w.advance() 45 | self.assertEqual(4, w.getMax()) 46 | w.shrink() 47 | self.assertEqual(4, w.getMax()) 48 | w.shrink() 49 | self.assertEqual(4, w.getMax()) 50 | w.shrink() 51 | self.assertEqual(4, w.getMax()) 52 | 53 | 54 | 55 | def test_randomizedSlidingWindowTest(self): 56 | for sz in range(1, self.TESTS + 1): 57 | self.randomizedTest(sz) 58 | 59 | 60 | 61 | def fillRandom(self, ar): 62 | for i in range(0, len(ar)): 63 | if random.random() < 0.5: 64 | ar[i] = int(random.random() * 25) 65 | else: 66 | ar[i] = int(random.random() * -25) 67 | 68 | 69 | 70 | def randomizedTest(self, n): 71 | 72 | r = max(0.1, random.random()) 73 | ar = [0]*n; 74 | self.fillRandom(ar) 75 | 76 | window = SlidingWindowMaximum(ar) 77 | lo = 0 78 | hi = 0 79 | while hi < n: 80 | 81 | # increase hi 82 | if random.random() < r: 83 | window.advance() 84 | hi += 1 85 | 86 | # increase lo if we can 87 | else: 88 | if lo + 1 < hi: 89 | lo += 1 90 | window.shrink() 91 | 92 | # Ignore invalid queries 93 | if window.lo == window.hi: 94 | continue 95 | 96 | # Manually find the window maximum 97 | maxVal = -sys.maxsize - 1 98 | for i in range(lo, hi): 99 | maxVal = max(maxVal, ar[i]) 100 | # print("ar= ", ar) 101 | # print("lo= ", lo) 102 | # print("hi= ", hi) 103 | 104 | self.assertEqual(maxVal, window.getMax()) 105 | 106 | 107 | 108 | 109 | if __name__ == '__main__': 110 | unittest.main() -------------------------------------------------------------------------------- /src/test/python/algorithms/search/InterpolationSearchTest.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file InterpolationSearchTest.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 29 Jun 2020 6 | * @version 0.1 7 | * @brief An InterpolationSearch unit test. 8 | ''' 9 | 10 | import unittest 11 | from collections import deque 12 | import random 13 | from InterpolationSearch import InterpolationSearch 14 | 15 | class InterpolationSearchTest(unittest.TestCase): 16 | 17 | def setUp(self): 18 | self.s = InterpolationSearch() 19 | 20 | 21 | def test_Coverage1(self): 22 | arr = [0, 1, 2, 3, 4, 5] 23 | index = self.s.interpolationSearch(arr, 2) 24 | self.assertTrue(index == 2) 25 | 26 | 27 | def test_Coverage2(self): 28 | arr = [0, 1, 2, 3, 4, 5] 29 | index = self.s.interpolationSearch(arr, 5) 30 | self.assertTrue(index == 5) 31 | 32 | 33 | def testCoverage3(self): 34 | arr = [0, 1, 2, 3, 4, 5] 35 | index = self.s.interpolationSearch(arr, -1) 36 | self.assertTrue(index == -1) 37 | 38 | 39 | def testCoverage4(self): 40 | arr = [0, 1, 2, 3, 4, 5] 41 | index = self.s.interpolationSearch(arr, 8) 42 | self.assertTrue(index == -1) 43 | 44 | 45 | 46 | if __name__ == '__main__': 47 | unittest.main() -------------------------------------------------------------------------------- /src/test/python/algorithms/sorting/SortingTest.py: -------------------------------------------------------------------------------- 1 | ''' 2 | * @file SortingTest.py 3 | * @author (original JAVA) William Fiset, william.alexandre.fiset@gmail.com 4 | * (conversion to Python) Armin Zare Zadeh, ali.a.zarezadeh@gmail.com 5 | * @date 28 Jun 2020 6 | * @version 0.1 7 | * @brief A Sorting unit test. 8 | * Test all sorting algorithms under various constraints. 9 | * 10 | ''' 11 | 12 | import unittest 13 | import time 14 | from collections import deque 15 | import array as arr 16 | import random 17 | from enum import Enum, auto 18 | import copy 19 | 20 | from BubbleSort import BubbleSort 21 | from BucketSort import BucketSort 22 | from CountingSort import CountingSort 23 | from Heapsort import Heapsort 24 | from InsertionSort import InsertionSort 25 | from MergeSort import MergeSort 26 | from QuickSort import QuickSort 27 | from QuickSort3 import QuickSort3 28 | from RadixSort import RadixSort 29 | from SelectionSort import SelectionSort 30 | 31 | 32 | class SortingAlgorithm(Enum): 33 | BUBBLE_SORT = auto() 34 | BUCKET_SORT = auto() 35 | COUNTING_SORT = auto() 36 | HEAP_SORT = auto() 37 | INSERTION_SORT = auto() 38 | MERGE_SORT = auto() 39 | QUICK_SORT = auto() 40 | QUICK_SORT3 = auto() 41 | RADIX_SORT = auto() 42 | SELECTION_SORT = auto() 43 | 44 | 45 | # ToDo: CountingSort, MergeSort, QuickSort3, and RadixSort are not passing the test! 46 | class SortingTest(unittest.TestCase): 47 | 48 | def setUp(self): 49 | self.TEST_SZ = 40 50 | self.MAX_RAND_NUM = 250 51 | 52 | self.funList = {SortingAlgorithm.BUBBLE_SORT: BubbleSort, 53 | SortingAlgorithm.BUCKET_SORT: BucketSort, 54 | # SortingAlgorithm.COUNTING_SORT : CountingSort, 55 | SortingAlgorithm.HEAP_SORT : Heapsort, 56 | SortingAlgorithm.INSERTION_SORT : InsertionSort, 57 | # SortingAlgorithm.MERGE_SORT : MergeSort, 58 | SortingAlgorithm.QUICK_SORT : QuickSort, 59 | # SortingAlgorithm.QUICK_SORT3 : QuickSort3, 60 | # SortingAlgorithm.RADIX_SORT : RadixSort, 61 | SortingAlgorithm.SELECTION_SORT : SelectionSort 62 | } 63 | 64 | 65 | def test_verifySortingAlgorithms_smallPositiveIntegersOnly(self): 66 | for sz in range(0, 100): 67 | for algorithm in self.funList.keys(): 68 | sorter = self.funList.get(algorithm)() 69 | values = self.genRandList(sz, 0, 51) 70 | cpy = copy.deepcopy(values) 71 | 72 | values.sort() 73 | sorter.sort(cpy) 74 | 75 | self.assertEqual(values, cpy) 76 | 77 | 78 | def test_verifySortingAlgorithms_smallNegativeIntegersOnly(self): 79 | for sz in range(0, 100): 80 | for algorithm in self.funList.keys(): 81 | # Skip radix sort since our implementation doesn't handle negative numbers. 82 | if algorithm == SortingAlgorithm.RADIX_SORT: 83 | continue 84 | 85 | sorter = self.funList.get(algorithm)() 86 | values = self.genRandList(sz, -50, 51) 87 | cpy = copy.deepcopy(values) 88 | 89 | values.sort() 90 | sorter.sort(cpy) 91 | 92 | self.assertEqual(values, cpy) 93 | 94 | 95 | def test_benchmark(self): 96 | sz = 30000 97 | for algorithm in self.funList.keys(): 98 | sorter = self.funList.get(algorithm)() 99 | values = self.genRandList(sz, 0, 51) 100 | cpy = copy.deepcopy(values) 101 | 102 | start = time.process_time() 103 | values.sort() 104 | end = time.process_time() 105 | elspasedTimePython = end - start 106 | 107 | start = time.process_time() 108 | sorter.sort(cpy) 109 | end = time.process_time() 110 | elspasedTimeAlg = end - start 111 | 112 | if algorithm == SortingAlgorithm.BUBBLE_SORT: 113 | # BUBBLE_SORT time: 141.859375 vs std time: 0.015625 114 | print('BUBBLE_SORT time: {} vs std time: {}'.format(elspasedTimeAlg, elspasedTimePython)) 115 | elif algorithm == SortingAlgorithm.BUCKET_SORT: 116 | # BUCKET_SORT time: 0.015625 vs std time: 0.0 117 | print('BUCKET_SORT time: {} vs std time: {}'.format(elspasedTimeAlg, elspasedTimePython)) 118 | # elif algorithm == SortingAlgorithm.COUNTING_SORT: 119 | elif algorithm == SortingAlgorithm.HEAP_SORT: 120 | # HEAP_SORT time: 0.21875 vs std time: 0.015625 121 | print('HEAP_SORT time: {} vs std time: {}'.format(elspasedTimeAlg, elspasedTimePython)) 122 | elif algorithm == SortingAlgorithm.INSERTION_SORT: 123 | # INSERTION_SORT time: 87.15625 vs std time: 0.0 124 | print('INSERTION_SORT time: {} vs std time: {}'.format(elspasedTimeAlg, elspasedTimePython)) 125 | # elif algorithm == SortingAlgorithm.MERGE_SORT: 126 | elif algorithm == SortingAlgorithm.QUICK_SORT: 127 | # QUICK_SORT time: 0.578125 vs std time: 0.0 128 | print('QUICK_SORT time: {} vs std time: {}'.format(elspasedTimeAlg, elspasedTimePython)) 129 | # elif algorithm == SortingAlgorithm.QUICK_SORT3: 130 | # elif algorithm == SortingAlgorithm.RADIX_SORT: 131 | elif algorithm == SortingAlgorithm.SELECTION_SORT: 132 | # SELECTION_SORT time: 34.046875 vs std time: 0.0 133 | print('SELECTION_SORT time: {} vs std time: {}'.format(elspasedTimeAlg, elspasedTimePython)) 134 | 135 | 136 | def genRandList(self, sz, lo, hi): 137 | """ 138 | Generate a list of random numbers 139 | """ 140 | #Generate sz random numbers between lo and hi 141 | lst = [] 142 | for i in range(0, sz): 143 | n = random.randint(lo, hi) 144 | lst.append(n) 145 | 146 | random.shuffle(lst) 147 | return lst 148 | 149 | 150 | 151 | if __name__ == '__main__': 152 | unittest.main() --------------------------------------------------------------------------------