├── BinarySearchTree ├── Indexing and sorting │ └── bst.cpp ├── Map │ ├── Map.hpp │ └── main.cpp └── Set │ ├── Set.hpp │ └── main.cpp ├── Deque ├── ArrayDeque │ ├── Deque.hpp │ └── main.cpp └── LinkedDeque │ ├── LinkedDeque.hpp │ └── main.cpp ├── DisjointSet ├── UnionByHeight │ ├── UnionFind.cpp │ ├── UnionFind.h │ └── main.cpp └── UnionBySize │ ├── UnionFind.cpp │ ├── UnionFind.h │ └── main.cpp ├── DoublyLinkedList ├── DoublyLinkedList.hpp └── main.cpp ├── GraphMst └── main.cpp ├── GraphShortestPath ├── main.cpp └── sp.cpp ├── GraphTraversals └── traversals.cpp ├── LinearProbingHash ├── Map │ ├── HashMap.hpp │ └── main.cpp └── Set │ ├── HashSet.hpp │ └── main.cpp ├── Miscellaneous ├── LeastRecentlyUsedCache ├── Lists_tasks │ ├── README.md │ ├── Task1.cpp │ ├── Task2.cpp │ ├── Task3.cpp │ ├── Task4.cpp │ ├── Task5.cpp │ ├── Task6.cpp │ └── Task7.cpp ├── README.md ├── Tree_tasks │ ├── Binary_tree │ │ └── Binary_tree_tasks.cpp │ ├── General_tree │ │ └── general_tree_tasks.cpp │ └── README.md ├── checkValidBracketsString.cpp ├── generateBoolVectors - amorthized analysis.cpp ├── parentArrayTreeHeight.cpp ├── removeNodesSinglyLinkedList.cpp ├── singlyLinkedList-partition.cpp ├── singlyLinkedList_mergeSort.cpp ├── singlyLinkedList_quickSort.cpp ├── tree_print_by_levels_BFS.cpp └── tree_print_root_to_leaf_DFS.CPP ├── PriorityQueue ├── main.cpp ├── priorityQueue.hpp └── readme.md ├── Queue ├── CircularQueue │ ├── CircularQueue.hpp │ └── source.cpp ├── LinkedQueue │ ├── LinkedQueue.hpp │ └── source.cpp └── QueueWithTemplateContainer │ ├── Queue.hpp │ └── main.cpp ├── README.md ├── Searching ├── binary_search_iter.cpp ├── binary_search_rec.cpp ├── linear_search_iter.cpp └── linear_search_rec.cpp ├── SeparateChainingHash ├── Map │ ├── UnorderedMap.hpp │ └── main.cpp └── Set │ ├── UnorderedSet.hpp │ └── main.cpp ├── SeparateChainingHash_InsertionOrderPerserve ├── Map │ ├── InsertionOrderHashMap.hpp │ └── main.cpp └── Set │ ├── InsertionOrderHashSet.hpp │ └── main.cpp ├── SinglyLinkedList ├── SinglyLinkedList.hpp └── main.cpp ├── Sorting ├── bubbleSort.cpp ├── countSort.cpp ├── insertionSort.cpp ├── mergeSort.cpp ├── naiveMergeSort.cpp ├── quickSort.cpp ├── readme.md └── selectionSort.cpp ├── Stack ├── ArrayStack │ ├── ArrayStack.hpp │ └── main.cpp ├── LinkedStack │ ├── LinkedStack.hpp │ └── main.cpp └── StackWithTemplateContainer │ ├── StackWithContainer.hpp │ └── main.cpp └── Vector ├── iterator └── iterator.hpp ├── tests.cpp └── vector └── vector.hpp /BinarySearchTree/Indexing and sorting/bst.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | class BST 7 | { 8 | private: 9 | struct Node 10 | { 11 | T data; 12 | Node* left; 13 | Node* right; 14 | size_t subtreeSize; 15 | 16 | Node(const T& data, Node* left = nullptr, Node* right = nullptr) 17 | : data(data), left(left), right(right), subtreeSize(1) {} 18 | 19 | static size_t getSubtreeSize(const Node* ptr) 20 | { 21 | return ptr ? ptr->subtreeSize : 0; 22 | } 23 | }; 24 | 25 | Node* root; 26 | 27 | Node* insertRec(Node* node, const T& value) 28 | { 29 | if (!node) 30 | return new Node(value); 31 | else if (value < node->data) 32 | node->left = insertRec(node->left, value); 33 | else if (value > node->data) 34 | node->right = insertRec(node->right, value); 35 | 36 | node->subtreeSize = 1 + Node::getSubtreeSize(node->left) + Node::getSubtreeSize(node->right); 37 | return node; 38 | } 39 | 40 | const Node& getNodeByIndexRec(const Node& current, size_t index) const 41 | { 42 | size_t leftSubtreeSize = Node::getSubtreeSize(current.left); 43 | if (index == leftSubtreeSize) 44 | return current; 45 | else if (index < leftSubtreeSize) 46 | return getNodeByIndexRec(*current.left, index); 47 | else 48 | return getNodeByIndexRec(*current.right, index - leftSubtreeSize - 1); 49 | } 50 | 51 | size_t getIndexOfRec(const Node* node, const T& value) const 52 | { 53 | if (!node) 54 | return static_cast(-1); 55 | if (value == node->data) 56 | return Node::getSubtreeSize(node->left); 57 | else if (value < node->data) 58 | return getIndexOfRec(node->left, value); 59 | else 60 | { 61 | size_t leftSize = Node::getSubtreeSize(node->left); 62 | size_t rightIndex = getIndexOfRec(node->right, value); 63 | if (rightIndex == static_cast(-1)) 64 | return static_cast(-1); 65 | return leftSize + 1 + rightIndex; 66 | } 67 | } 68 | 69 | void inOrderTraversal(const Node* node, std::vector& result) const 70 | { 71 | if (!node) 72 | return; 73 | inOrderTraversal(node->left, result); 74 | result.push_back(node->data); 75 | inOrderTraversal(node->right, result); 76 | } 77 | 78 | public: 79 | BST() : root(nullptr) {} 80 | 81 | void insert(const T& value) 82 | { 83 | root = insertRec(root, value); 84 | } 85 | 86 | const T& operator[](size_t index) const 87 | { 88 | if (!root) 89 | throw std::out_of_range("BST is empty."); 90 | if (index >= root->subtreeSize) 91 | throw std::out_of_range("Index out of range."); 92 | return getNodeByIndexRec(*root, index).data; 93 | } 94 | 95 | size_t getIndexOf(const T& value) const 96 | { 97 | return getIndexOfRec(root, value); 98 | } 99 | 100 | std::vector treeSort() const 101 | { 102 | std::vector sortedResult; 103 | inOrderTraversal(root, sortedResult); 104 | return sortedResult; 105 | } 106 | }; 107 | 108 | int main() 109 | { 110 | BST tree; 111 | tree.insert(5); 112 | tree.insert(2); 113 | tree.insert(7); 114 | tree.insert(1); 115 | tree.insert(3); 116 | 117 | std::cout << "Element at index 0: " << tree[0] << "\n"; 118 | std::cout << "Element at index 1: " << tree[1] << "\n"; 119 | std::cout << "Element at index 2: " << tree[2] << "\n"; 120 | std::cout << "Element at index 3: " << tree[3] << "\n"; 121 | std::cout << "Element at index 4: " << tree[4] << "\n"; 122 | 123 | std::cout << "Index of value 5: " << tree.getIndexOf(5) << "\n"; 124 | std::cout << "Index of value 7: " << tree.getIndexOf(7) << "\n"; 125 | std::cout << "Index of value 6 (not in tree): " << tree.getIndexOf(6) << "\n"; 126 | 127 | std::vector sorted = tree.treeSort(); 128 | std::cout << "Tree sort result: "; 129 | for (int x : sorted) 130 | std::cout << x << " "; 131 | std::cout << "\n"; 132 | 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /BinarySearchTree/Map/Map.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | template > 7 | class Map 8 | { 9 | private: 10 | struct Node 11 | { 12 | std::pair data; 13 | Node* left; 14 | Node* right; 15 | 16 | Node(const std::pair& data, Node* left = nullptr, Node* right = nullptr); 17 | }; 18 | 19 | Node* root; 20 | size_t sz; 21 | Compare comp; 22 | 23 | Node** findMinNode(Node** current); 24 | void free(Node* current); 25 | Node* copy(Node* current); 26 | 27 | public: 28 | Map(); 29 | explicit Map(const Compare& comparator); 30 | Map(const Map& other); 31 | Map& operator=(const Map& other); 32 | ~Map(); 33 | 34 | bool insert(const std::pair& newData); 35 | bool insert(const Key& k, const Value& v); 36 | bool containsKey(const Key& k) const; 37 | bool remove(const Key& k); 38 | size_t size() const; 39 | bool empty() const; 40 | 41 | class ConstIterator 42 | { 43 | private: 44 | std::stack nodeStack; 45 | 46 | void pushLeft(Node* node); 47 | 48 | public: 49 | ConstIterator(Node* root = nullptr); 50 | const std::pair& operator*() const; 51 | ConstIterator& operator++(); 52 | ConstIterator operator++(int); 53 | bool operator==(const ConstIterator& other) const; 54 | bool operator!=(const ConstIterator& other) const; 55 | }; 56 | 57 | ConstIterator cbegin() const; 58 | ConstIterator cend() const; 59 | }; 60 | 61 | 62 | template 63 | Map::Node::Node(const std::pair& data, Node* left, Node* right) 64 | : data(data), left(left), right(right) {} 65 | 66 | template 67 | typename Map::Node** Map::findMinNode(Node** current) 68 | { 69 | while ((*current)->left) 70 | current = &(*current)->left; 71 | return current; 72 | } 73 | 74 | template 75 | void Map::free(Node* current) 76 | { 77 | if (!current) return; 78 | free(current->left); 79 | free(current->right); 80 | delete current; 81 | } 82 | 83 | template 84 | typename Map::Node* Map::copy(Node* current) 85 | { 86 | if (!current) 87 | return nullptr; 88 | Node* newNode = new Node(current->data); 89 | newNode->left = copy(current->left); 90 | newNode->right = copy(current->right); 91 | return newNode; 92 | } 93 | 94 | template 95 | Map::Map() : root(nullptr), sz(0), comp(Compare()) {} 96 | 97 | template 98 | Map::Map(const Compare& comparator) : root(nullptr), sz(0), comp(comparator) {} 99 | 100 | template 101 | Map::Map(const Map& other) : root(copy(other.root)), sz(other.sz), comp(other.comp) {} 102 | 103 | template 104 | Map& Map::operator=(const Map& other) 105 | { 106 | if (this != &other) 107 | { 108 | free(root); 109 | root = copy(other.root); 110 | sz = other.sz; 111 | comp = other.comp; 112 | } 113 | return *this; 114 | } 115 | 116 | template 117 | Map::~Map() 118 | { 119 | free(root); 120 | } 121 | 122 | template 123 | bool Map::insert(const std::pair& newData) 124 | { 125 | Node** current = &root; 126 | while (*current) 127 | { 128 | if (comp(newData.first, (*current)->data.first)) 129 | current = &(*current)->left; 130 | else if (comp((*current)->data.first, newData.first)) 131 | current = &(*current)->right; 132 | else 133 | return false; 134 | } 135 | *current = new Node(newData); 136 | ++sz; 137 | return true; 138 | } 139 | 140 | template 141 | bool Map::insert(const Key& k, const Value& v) 142 | { 143 | return insert(std::make_pair(k, v)); 144 | } 145 | 146 | template 147 | bool Map::containsKey(const Key& k) const 148 | { 149 | Node* current = root; 150 | while (current) 151 | { 152 | if (comp(k, current->data.first)) 153 | current = current->left; 154 | else if (comp(current->data.first, k)) 155 | current = current->right; 156 | else 157 | return true; 158 | } 159 | return false; 160 | } 161 | 162 | template 163 | bool Map::remove(const Key& k) 164 | { 165 | Node** current = &root; 166 | while (*current) 167 | { 168 | if (comp(k, (*current)->data.first)) 169 | current = &(*current)->left; 170 | else if (comp((*current)->data.first, k)) 171 | current = &(*current)->right; 172 | else 173 | break; 174 | } 175 | 176 | if (!(*current)) 177 | return false; 178 | 179 | Node* toDelete = *current; 180 | if (!toDelete->left && !toDelete->right) 181 | *current = nullptr; 182 | else if (!toDelete->right) 183 | *current = toDelete->left; 184 | else if (!toDelete->left) 185 | *current = toDelete->right; 186 | else 187 | { 188 | Node** rightMin = findMinNode(&toDelete->right); 189 | *current = *rightMin; 190 | *rightMin = (*rightMin)->right; 191 | (*current)->left = toDelete->left; 192 | (*current)->right = toDelete->right; 193 | } 194 | 195 | delete toDelete; 196 | --sz; 197 | return true; 198 | } 199 | 200 | template 201 | size_t Map::size() const 202 | { 203 | return sz; 204 | } 205 | 206 | template 207 | bool Map::empty() const 208 | { 209 | return sz == 0; 210 | } 211 | 212 | template 213 | void Map::ConstIterator::pushLeft(Node* node) 214 | { 215 | while (node) 216 | { 217 | nodeStack.push(node); 218 | node = node->left; 219 | } 220 | } 221 | 222 | template 223 | Map::ConstIterator::ConstIterator(Node* root) 224 | { 225 | pushLeft(root); 226 | } 227 | 228 | template 229 | const std::pair& Map::ConstIterator::operator*() const 230 | { 231 | return nodeStack.top()->data; 232 | } 233 | 234 | template 235 | typename Map::ConstIterator& Map::ConstIterator::operator++() 236 | { 237 | Node* node = nodeStack.top(); 238 | nodeStack.pop(); 239 | if (node->right) 240 | pushLeft(node->right); 241 | return *this; 242 | } 243 | 244 | template 245 | typename Map::ConstIterator Map::ConstIterator::operator++(int) 246 | { 247 | ConstIterator temp = *this; 248 | ++(*this); 249 | return temp; 250 | } 251 | 252 | template 253 | bool Map::ConstIterator::operator==(const ConstIterator& other) const 254 | { 255 | return nodeStack == other.nodeStack; 256 | } 257 | 258 | template 259 | bool Map::ConstIterator::operator!=(const ConstIterator& other) const 260 | { 261 | return !(*this == other); 262 | } 263 | 264 | template 265 | typename Map::ConstIterator Map::cbegin() const 266 | { 267 | return ConstIterator(root); 268 | } 269 | 270 | template 271 | typename Map::ConstIterator Map::cend() const 272 | { 273 | return ConstIterator(nullptr); 274 | } 275 | 276 | -------------------------------------------------------------------------------- /BinarySearchTree/Map/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Map.hpp" 3 | 4 | int main() { 5 | Map myMap; 6 | 7 | myMap.insert(10, "ten"); 8 | myMap.insert(20, "twenty"); 9 | myMap.insert(5, "five"); 10 | myMap.insert(15, "fifteen"); 11 | 12 | std::cout << "In-order traversal of the Map:\n"; 13 | for (auto it = myMap.cbegin(); it != myMap.cend(); ++it) 14 | std::cout << (*it).first << " -> " << (*it).second << "\n"; 15 | 16 | std::cout << "\nContainsKey tests:\n"; 17 | std::cout << "Does the Map contain 10? " << (myMap.containsKey(10) ? "Yes" : "No") << "\n"; 18 | std::cout << "Does the Map contain 25? " << (myMap.containsKey(25) ? "Yes" : "No") << "\n"; 19 | 20 | std::cout << "\nRemoving key 10...\n"; 21 | if (myMap.remove(10)) 22 | std::cout << "Key 10 removed.\n"; 23 | else 24 | std::cout << "Key 10 not found.\n"; 25 | 26 | 27 | std::cout << "After removal:\n"; 28 | for (auto it = myMap.cbegin(); it != myMap.cend(); ++it) { 29 | std::cout << (*it).first << " -> " << (*it).second << "\n"; 30 | } 31 | 32 | std::cout << "\nSize of the Map: " << myMap.size() << "\n"; 33 | std::cout << "Is the Map empty? " << (myMap.empty() ? "Yes" : "No") << "\n"; 34 | 35 | std::cout << "\nInserting duplicate key 5...\n"; 36 | if (!myMap.insert(5, "duplicate")) 37 | std::cout << "Duplicate key 5 was not inserted.\n"; 38 | 39 | 40 | std::cout << "\nFinal Map state:\n"; 41 | for (auto it = myMap.cbegin(); it != myMap.cend(); ++it) 42 | std::cout << (*it).first << " -> " << (*it).second << "\n"; 43 | 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /BinarySearchTree/Set/Set.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template > 8 | class Set 9 | { 10 | private: 11 | struct Node 12 | { 13 | T data; 14 | Node* left; 15 | Node* right; 16 | 17 | Node(const T& data, Node* left = nullptr, Node* right = nullptr) 18 | : data(data), left(left), right(right) {} 19 | }; 20 | 21 | Node* root = nullptr; 22 | size_t size = 0; 23 | Compare comp; 24 | 25 | Node** findMinNode(Node** root); 26 | void free(Node* current); 27 | Node* copy(Node* current); 28 | 29 | public: 30 | Set() = default; 31 | explicit Set(const Compare& comparator) : comp(comparator) {} 32 | Set(const Set& other); 33 | Set& operator=(const Set& other); 34 | ~Set(); 35 | 36 | bool insert(const T& data); 37 | bool contains(const T& data) const; 38 | bool remove(const T& data); 39 | 40 | size_t getSize() const; 41 | bool isEmpty() const; 42 | 43 | class ConstIterator 44 | { 45 | private: 46 | std::stack nodeStack; 47 | 48 | void pushLeft(Node* node) 49 | { 50 | while (node) 51 | { 52 | nodeStack.push(node); 53 | node = node->left; 54 | } 55 | } 56 | 57 | public: 58 | ConstIterator(Node* root = nullptr) 59 | { 60 | pushLeft(root); 61 | } 62 | 63 | const T& operator*() const 64 | { 65 | return nodeStack.top()->data; 66 | } 67 | 68 | ConstIterator& operator++() 69 | { 70 | Node* node = nodeStack.top(); 71 | nodeStack.pop(); 72 | if (node->right) { 73 | pushLeft(node->right); 74 | } 75 | return *this; 76 | } 77 | ConstIterator operator++(int) 78 | { 79 | ConstIterator old = *this; 80 | ++(*this); 81 | return old; 82 | } 83 | 84 | bool operator!=(const ConstIterator& other) const 85 | { 86 | return nodeStack != other.nodeStack; 87 | } 88 | 89 | bool operator==(const ConstIterator& other) const 90 | { 91 | return nodeStack == other.nodeStack; 92 | } 93 | }; 94 | 95 | ConstIterator cbegin() const 96 | { 97 | return ConstIterator(root); 98 | } 99 | 100 | ConstIterator cend() const 101 | { 102 | return ConstIterator(nullptr); 103 | } 104 | }; 105 | 106 | template 107 | bool Set::insert(const T& data) 108 | { 109 | Node** current = &root; 110 | 111 | while (*current) 112 | { 113 | if (comp(data, (*current)->data)) 114 | current = &(*current)->left; 115 | else if (comp((*current)->data, data)) 116 | current = &(*current)->right; 117 | else 118 | return false; 119 | } 120 | *current = new Node(data); 121 | size++; 122 | return true; 123 | } 124 | 125 | template 126 | bool Set::contains(const T& data) const 127 | { 128 | Node* current = root; 129 | 130 | while (current) 131 | { 132 | if (comp(data, current->data)) 133 | current = current->left; 134 | else if (comp(current->data, data)) 135 | current = current->right; 136 | else 137 | return true; 138 | } 139 | return false; 140 | } 141 | 142 | template 143 | typename Set::Node** Set::findMinNode(Node** root) 144 | { 145 | Node** current = root; 146 | 147 | while ((*current)->left) 148 | { 149 | current = &(*current)->left; 150 | } 151 | return current; 152 | } 153 | 154 | template 155 | bool Set::remove(const T& data) 156 | { 157 | Node** current = &root; 158 | 159 | while (*current) 160 | { 161 | if (comp(data, (*current)->data)) 162 | current = &(*current)->left; 163 | else if (comp((*current)->data, data)) 164 | current = &(*current)->right; 165 | else 166 | break; 167 | } 168 | 169 | if (!(*current)) 170 | return false; // Data not found 171 | 172 | Node* toDelete = *current; 173 | 174 | // No children 175 | if (!(*current)->left && !(*current)->right) 176 | *current = nullptr; 177 | // Only left child 178 | else if (!(*current)->right) 179 | *current = (*current)->left; 180 | // Only right child 181 | else if (!(*current)->left) 182 | *current = (*current)->right; 183 | // Two children 184 | else 185 | { 186 | Node** rightMin = findMinNode(&(*current)->right); 187 | *current = *rightMin; 188 | *rightMin = (*rightMin)->right; 189 | 190 | (*current)->left = toDelete->left; 191 | (*current)->right = toDelete->right; 192 | } 193 | delete toDelete; 194 | size--; 195 | return true; 196 | } 197 | 198 | template 199 | size_t Set::getSize() const 200 | { 201 | return size; 202 | } 203 | 204 | template 205 | bool Set::isEmpty() const 206 | { 207 | return getSize() == 0; 208 | } 209 | 210 | template 211 | typename Set::Node* Set::copy(Node* current) 212 | { 213 | if (!current) 214 | return nullptr; 215 | Node* res = new Node(current->data); 216 | res->left = copy(current->left); 217 | res->right = copy(current->right); 218 | return res; 219 | } 220 | 221 | template 222 | void Set::free(Node* current) 223 | { 224 | if (!current) 225 | return; 226 | free(current->left); 227 | free(current->right); 228 | delete current; 229 | } 230 | 231 | template 232 | Set::Set(const Set& other) : comp(other.comp) 233 | { 234 | root = copy(other.root); 235 | size = other.size; 236 | } 237 | 238 | template 239 | Set& Set::operator=(const Set& other) 240 | { 241 | if (this != &other) 242 | { 243 | free(root); 244 | root = copy(other.root); 245 | size = other.size; 246 | comp = other.comp; 247 | } 248 | return *this; 249 | } 250 | 251 | template 252 | Set::~Set() 253 | { 254 | free(root); 255 | } 256 | -------------------------------------------------------------------------------- /BinarySearchTree/Set/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Set.hpp" 3 | 4 | 5 | bool testInsert() 6 | { 7 | Set tree; 8 | 9 | if (!tree.insert(10)) return false; 10 | if (!tree.insert(5)) return false; 11 | if (!tree.insert(20)) return false; 12 | if (tree.insert(10)) return false; // Duplicate insert should return false 13 | 14 | if (tree.getSize() != 3) return false; // Only 3 unique elements inserted 15 | if (!tree.contains(10)) return false; 16 | if (!tree.contains(5)) return false; 17 | if (!tree.contains(20)) return false; 18 | if (tree.contains(15)) return false; 19 | 20 | return true; 21 | } 22 | 23 | bool testContains() 24 | { 25 | Set tree; 26 | tree.insert(10); 27 | tree.insert(5); 28 | tree.insert(20); 29 | 30 | if (!tree.contains(10)) return false; 31 | if (!tree.contains(5)) return false; 32 | if (!tree.contains(20)) return false; 33 | if (tree.contains(15)) return false; // 15 is not in the tree 34 | 35 | return true; 36 | } 37 | 38 | bool testRemove() 39 | { 40 | Set tree; 41 | tree.insert(10); 42 | tree.insert(5); 43 | tree.insert(20); 44 | 45 | if (!tree.remove(5)) return false; // 5 should be removed 46 | if (tree.contains(5)) return false; // 5 should no longer be in the tree 47 | if (tree.getSize() != 2) return false; 48 | 49 | if (!tree.remove(10)) return false; // 10 should be removed 50 | if (tree.contains(10)) return false; // 10 should no longer be in the tree 51 | if (tree.getSize() != 1) return false; 52 | 53 | if (!tree.remove(20)) return false; // 20 should be removed 54 | if (tree.contains(20)) return false; // 20 should no longer be in the tree 55 | if (!tree.isEmpty()) return false; // Tree should be empty now 56 | 57 | return true; 58 | } 59 | 60 | bool testCustomComparator() 61 | { 62 | auto comp = [](int a, int b) { return a > b; }; 63 | Set tree(comp); 64 | 65 | tree.insert(10); 66 | tree.insert(5); 67 | tree.insert(20); 68 | 69 | if (!tree.contains(10)) return false; 70 | if (!tree.contains(5)) return false; 71 | if (!tree.contains(20)) return false; 72 | 73 | // Testing the order through structure traversal (in this case, assumed order check) 74 | if (tree.getSize() != 3) return false; 75 | return true; 76 | } 77 | 78 | int main() 79 | { 80 | Set b; 81 | b.insert(3); 82 | b.insert(1); 83 | b.insert(2); 84 | b.insert(4); 85 | b.insert(0); 86 | 87 | std::cout << "Test Insert: " << (testInsert() ? "Passed" : "Failed") << std::endl; 88 | std::cout << "Test Contains: " << (testContains() ? "Passed" : "Failed") << std::endl; 89 | std::cout << "Test Remove: " << (testRemove() ? "Passed" : "Failed") << std::endl; 90 | std::cout << "Test Custom Comparator: " << (testCustomComparator() ? "Passed" : "Failed") << std::endl; 91 | 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /Deque/ArrayDeque/main.cpp: -------------------------------------------------------------------------------- 1 | #include "deque.hpp" 2 | #include 3 | 4 | bool testPushBack() 5 | { 6 | deque dq; 7 | dq.push_back(10); 8 | dq.push_back(20); 9 | dq.push_back(30); 10 | 11 | return dq.getSize() == 3 && dq[0] == 10 && dq[1] == 20 && dq[2] == 30; 12 | } 13 | 14 | bool testPushFront() 15 | { 16 | deque dq; 17 | dq.push_front(10); 18 | dq.push_front(20); 19 | dq.push_front(30); 20 | 21 | return dq.getSize() == 3 && dq[0] == 30 && dq[1] == 20 && dq[2] == 10; 22 | } 23 | 24 | bool testPopBack() 25 | { 26 | deque dq; 27 | dq.push_back(10); 28 | dq.push_back(20); 29 | dq.push_back(30); 30 | dq.pop_back(); 31 | 32 | return dq.getSize() == 2 && dq[0] == 10 && dq[1] == 20; 33 | } 34 | 35 | bool testPopFront() 36 | { 37 | deque dq; 38 | dq.push_back(10); 39 | dq.push_back(20); 40 | dq.push_back(30); 41 | dq.pop_front(); 42 | 43 | return dq.getSize() == 2 && dq[0] == 20 && dq[1] == 30; 44 | } 45 | 46 | bool testEmplaceBack() 47 | { 48 | deque dq; 49 | dq.emplaceBack(3, 'a'); 50 | 51 | return dq.getSize() == 1 && dq[0] == "aaa"; 52 | } 53 | 54 | bool testEmplaceFront() 55 | { 56 | deque dq; 57 | dq.emplaceFront(3, 'b'); 58 | 59 | return dq.getSize() == 1 && dq[0] == "bbb"; 60 | } 61 | 62 | bool testFrontBackAccess() 63 | { 64 | deque dq; 65 | dq.push_back(10); 66 | dq.push_back(20); 67 | dq.push_front(5); 68 | 69 | return dq.front() == 5 && dq.back() == 20; 70 | } 71 | 72 | bool testIsEmpty() 73 | { 74 | deque dq; 75 | return dq.empty(); 76 | } 77 | 78 | bool testResize() 79 | { 80 | deque dq; 81 | for (int i = 0; i < 20; ++i) 82 | { 83 | dq.push_back(i); 84 | } 85 | 86 | bool success = true; 87 | for (int i = 0; i < 20; ++i) 88 | { 89 | success = success && dq[i] == i; 90 | } 91 | 92 | return success && dq.getSize() == 20; 93 | } 94 | 95 | bool testIteratorIncrement() 96 | { 97 | deque dq; 98 | dq.push_back(1); 99 | dq.push_back(2); 100 | dq.push_back(3); 101 | 102 | auto it = dq.begin(); 103 | if (*it != 1) 104 | { 105 | return false; 106 | } 107 | 108 | it++; 109 | if (*it != 2) 110 | { 111 | return false; 112 | } 113 | 114 | ++it; 115 | if (*it != 3) 116 | { 117 | return false; 118 | } 119 | 120 | return it == dq.end() - 1; 121 | } 122 | 123 | bool testIteratorDecrement() 124 | { 125 | deque dq; 126 | dq.push_back(1); 127 | dq.push_back(2); 128 | dq.push_back(3); 129 | 130 | auto it = dq.end() - 1; 131 | if (*it != 3) 132 | { 133 | return false; 134 | } 135 | 136 | it--; 137 | if (*it != 2) 138 | { 139 | return false; 140 | } 141 | 142 | --it; 143 | if (*it != 1) 144 | { 145 | return false; 146 | } 147 | 148 | return it == dq.begin(); 149 | } 150 | 151 | bool testIteratorEquality() 152 | { 153 | deque dq; 154 | dq.push_back(10); 155 | dq.push_back(20); 156 | 157 | auto it1 = dq.begin(); 158 | auto it2 = dq.begin(); 159 | 160 | if (it1 != it2) 161 | { 162 | return false; 163 | } 164 | 165 | ++it2; 166 | 167 | if (it1 == it2) 168 | { 169 | return false; 170 | } 171 | 172 | return true; 173 | } 174 | 175 | bool testConstIterator() 176 | { 177 | deque dq; 178 | dq.push_back(5); 179 | dq.push_back(15); 180 | dq.push_back(25); 181 | 182 | const deque& constDq = dq; 183 | auto it = constDq.begin(); 184 | 185 | if (*it != 5) 186 | { 187 | return false; 188 | } 189 | 190 | ++it; 191 | 192 | if (*it != 15) 193 | { 194 | return false; 195 | } 196 | 197 | ++it; 198 | 199 | if (*it != 25) 200 | { 201 | return false; 202 | } 203 | 204 | return it == constDq.end() - 1; 205 | } 206 | 207 | bool testIteratorDereference() 208 | { 209 | deque dq; 210 | dq.push_back(100); 211 | dq.push_back(200); 212 | dq.push_back(300); 213 | 214 | auto it = dq.begin(); 215 | 216 | if (*it != 100) 217 | { 218 | return false; 219 | } 220 | 221 | ++it; 222 | 223 | if (*it != 200) 224 | { 225 | return false; 226 | } 227 | 228 | it++; 229 | 230 | if (*it != 300) 231 | { 232 | return false; 233 | } 234 | 235 | return true; 236 | } 237 | 238 | bool testCopyConstructor() 239 | { 240 | deque dq; 241 | dq.push_back(1); 242 | dq.push_back(2); 243 | dq.push_back(3); 244 | 245 | deque copy(dq); 246 | 247 | if (dq.getSize() != copy.getSize()) 248 | { 249 | return false; 250 | } 251 | 252 | while (copy.getSize()) 253 | { 254 | if (copy.front() != dq.front()) 255 | { 256 | return false; 257 | } 258 | 259 | copy.pop_front(); 260 | dq.pop_front(); 261 | } 262 | 263 | return dq.getSize() == copy.getSize(); 264 | } 265 | 266 | bool testMoveAndAssignment() 267 | { 268 | constexpr size_t SIZE = 4; 269 | 270 | deque d; 271 | 272 | for (size_t i = 0; i < SIZE; i++) 273 | { 274 | d.push_back(i); 275 | } 276 | 277 | deque d1; 278 | d1 = d; 279 | 280 | for (size_t i = 0; i < d1.getSize(); i++) 281 | { 282 | if (d1[i] != d[i]) 283 | { 284 | return false; 285 | } 286 | } 287 | 288 | deque moved(std::move(d1)); 289 | 290 | if (moved.getSize() != SIZE || d1.getSize() != 0) 291 | { 292 | return false; 293 | } 294 | 295 | d1 = std::move(moved); 296 | moved = std::move(d1); 297 | 298 | if (moved.getSize() != SIZE || d1.getSize() != 0) 299 | { 300 | return false; 301 | } 302 | 303 | while (moved.getSize()) 304 | { 305 | if (moved.front() != d.front() || moved.back() != d.back()) 306 | { 307 | return false; 308 | } 309 | 310 | moved.pop_back(); 311 | d.pop_back(); 312 | 313 | if (moved.empty() || d.empty()) 314 | { 315 | break; 316 | } 317 | 318 | moved.pop_front(); 319 | d.pop_front(); 320 | } 321 | 322 | return moved.empty() && d.empty(); 323 | } 324 | 325 | int main() 326 | { 327 | std::cout << "Test Push Back: " << (testPushBack() ? "PASSED" : "FAILED") << "\n"; 328 | std::cout << "Test Push Front: " << (testPushFront() ? "PASSED" : "FAILED") << "\n"; 329 | std::cout << "Test Pop Back: " << (testPopBack() ? "PASSED" : "FAILED") << "\n"; 330 | std::cout << "Test Pop Front: " << (testPopFront() ? "PASSED" : "FAILED") << "\n"; 331 | std::cout << "Test Emplace Back: " << (testEmplaceBack() ? "PASSED" : "FAILED") << "\n"; 332 | std::cout << "Test Emplace Front: " << (testEmplaceFront() ? "PASSED" : "FAILED") << "\n"; 333 | std::cout << "Test Front and Back Access: " << (testFrontBackAccess() ? "PASSED" : "FAILED") << "\n"; 334 | std::cout << "Test Is Empty: " << (testIsEmpty() ? "PASSED" : "FAILED") << "\n"; 335 | std::cout << "Test Resize: " << (testResize() ? "PASSED" : "FAILED") << "\n"; 336 | std::cout << "Test Iterator Increment: " << (testIteratorIncrement() ? "PASSED" : "FAILED") << "\n"; 337 | std::cout << "Test Iterator Decrement: " << (testIteratorDecrement() ? "PASSED" : "FAILED") << "\n"; 338 | std::cout << "Test Iterator Equality: " << (testIteratorEquality() ? "PASSED" : "FAILED") << "\n"; 339 | std::cout << "Test Const Iterator: " << (testConstIterator() ? "PASSED" : "FAILED") << "\n"; 340 | std::cout << "Test Iterator Dereference: " << (testIteratorDereference() ? "PASSED" : "FAILED") << "\n"; 341 | std::cout << "Test Copy Constructor: " << (testCopyConstructor() ? "PASSED" : "FAILED") << "\n"; 342 | std::cout << "Test Move Constructor And Assignment: " << (testMoveAndAssignment() ? "PASSED" : "FAILED") << "\n"; 343 | 344 | return 0; 345 | } 346 | -------------------------------------------------------------------------------- /Deque/LinkedDeque/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "LinkedDeque.hpp" // Include your LinkedDeque header here 3 | 4 | int main() 5 | { 6 | // 1) Create a LinkedDeque of int 7 | LinkedDeque dq; 8 | 9 | // 2) Push some elements (front and back) 10 | dq.push_front(10); 11 | dq.push_front(20); 12 | dq.push_back(30); 13 | dq.push_back(40); 14 | 15 | // 3) Print the contents 16 | std::cout << "Initial deque contents:\n"; 17 | dq.print(); // 20 <-> 10 <-> 30 <-> 40 18 | 19 | // 4) Use iterators to traverse (read/write) 20 | std::cout << "\nTraverse with iterator and modify the second element:\n"; 21 | { 22 | auto it = dq.begin(); 23 | // *it = 20 (the first element) 24 | ++it; 25 | // *it = 10 (the second element) 26 | *it = 99; // Modify the second element 27 | } 28 | dq.print(); // 20 <-> 99 <-> 30 <-> 40 29 | 30 | // 5) Insert an element using iterator 31 | std::cout << "\nInsert a value (555) before the 99:\n"; 32 | { 33 | auto it = dq.begin(); 34 | ++it; // 'it' now points to 99 35 | dq.insert(it, 555); 36 | } 37 | dq.print(); // 20 <-> 555 <-> 99 <-> 30 <-> 40 38 | 39 | // 6) Erase an element using iterator 40 | std::cout << "\nErase the element 555 using iterator:\n"; 41 | { 42 | auto it = dq.begin(); 43 | ++it; // 'it' now points to 555 44 | dq.erase(it); 45 | } 46 | dq.print(); // 20 <-> 99 <-> 30 <-> 40 47 | 48 | // 7) Pop from front and back 49 | std::cout << "\nPop front and back:\n"; 50 | dq.pop_front(); // removes 20 51 | dq.pop_back(); // removes 40 52 | dq.print(); // 99 <-> 30 53 | 54 | // 8) Demonstrate const_iterator usage 55 | std::cout << "\nTraverse with const_iterator:\n"; 56 | { 57 | const LinkedDeque& constRef = dq; 58 | for (auto cit = constRef.cbegin(); cit != constRef.cend(); ++cit) 59 | { 60 | std::cout << *cit << " "; 61 | } 62 | std::cout << std::endl; 63 | } 64 | 65 | // 9) Clear everything 66 | std::cout << "\nClear the deque:\n"; 67 | dq.clear(); 68 | dq.print(); // (should print nothing) 69 | 70 | std::cout << "\nDone!\n"; 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /DisjointSet/UnionByHeight/UnionFind.cpp: -------------------------------------------------------------------------------- 1 | #include "UnionFind.h" 2 | 3 | UnionFind::UnionFind(int n) : parent(n), height(n, 0) 4 | { 5 | for (int i = 0; i < n; i++) 6 | { 7 | parent[i] = i; 8 | } 9 | } 10 | 11 | int UnionFind::getRoot(int n) 12 | { 13 | if (parent[n] != n) 14 | { 15 | parent[n] = getRoot(parent[n]); 16 | } 17 | return parent[n]; 18 | } 19 | 20 | bool UnionFind::areInOneSet(int n, int k) 21 | { 22 | return getRoot(n) == getRoot(k); 23 | } 24 | 25 | bool UnionFind::Union(int n, int k) 26 | { 27 | int root1 = getRoot(n); 28 | int root2 = getRoot(k); 29 | 30 | if (root1 == root2) 31 | { 32 | return false; 33 | } 34 | 35 | if (height[root1] < height[root2]) 36 | { 37 | parent[root1] = root2; 38 | } 39 | else if (height[root1] > height[root2]) 40 | { 41 | parent[root2] = root1; 42 | } 43 | else 44 | { 45 | parent[root2] = root1; 46 | height[root1]++; 47 | } 48 | 49 | return true; 50 | } 51 | -------------------------------------------------------------------------------- /DisjointSet/UnionByHeight/UnionFind.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class UnionFind 6 | { 7 | private: 8 | std::vector parent; 9 | std::vector height; 10 | 11 | public: 12 | UnionFind(int n); 13 | int getRoot(int n); 14 | bool areInOneSet(int n, int k); 15 | bool Union(int n, int k); 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /DisjointSet/UnionByHeight/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "UnionFind.h" 3 | 4 | int main() 5 | { 6 | UnionFind uf(10); 7 | 8 | std::cout << "Union(1, 2): " << uf.Union(1, 2) << std::endl; 9 | std::cout << "Union(2, 3): " << uf.Union(2, 3) << std::endl; 10 | std::cout << "Union(4, 5): " << uf.Union(4, 5) << std::endl; 11 | std::cout << "Union(6, 7): " << uf.Union(6, 7) << std::endl; 12 | std::cout << "Union(5, 6): " << uf.Union(5, 6) << std::endl; 13 | std::cout << "Union(3, 7): " << uf.Union(3, 7) << std::endl; 14 | 15 | std::cout << "areInOneSet(1, 7): " << uf.areInOneSet(1, 7) << std::endl; 16 | std::cout << "areInOneSet(4, 6): " << uf.areInOneSet(4, 6) << std::endl; 17 | std::cout << "areInOneSet(1, 4): " << uf.areInOneSet(1, 4) << std::endl; 18 | std::cout << "areInOneSet(8, 9): " << uf.areInOneSet(8, 9) << std::endl; 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /DisjointSet/UnionBySize/UnionFind.cpp: -------------------------------------------------------------------------------- 1 | #include "UnionFind.h" 2 | #include 3 | 4 | UnionFind::UnionFind(int n) : parent(n), sizes(n, 1) 5 | { 6 | for (int i = 0; i < n; i++) 7 | { 8 | parent[i] = i; 9 | } 10 | } 11 | 12 | int UnionFind::getRoot(int n) 13 | { 14 | if (parent[n] != n) 15 | { 16 | parent[n] = getRoot(parent[n]); 17 | } 18 | return parent[n]; 19 | } 20 | 21 | bool UnionFind::areInOneSet(int n, int k) 22 | { 23 | return getRoot(n) == getRoot(k); 24 | } 25 | 26 | bool UnionFind::Union(int n, int k) 27 | { 28 | int root1 = getRoot(n); 29 | int root2 = getRoot(k); 30 | 31 | if (root1 == root2) 32 | { 33 | return false; 34 | } 35 | 36 | if (sizes[root1] < sizes[root2]) 37 | { 38 | parent[root1] = root2; 39 | sizes[root2] += sizes[root1]; 40 | } 41 | else 42 | { 43 | parent[root2] = root1; 44 | sizes[root1] += sizes[root2]; 45 | } 46 | 47 | return true; 48 | } 49 | -------------------------------------------------------------------------------- /DisjointSet/UnionBySize/UnionFind.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class UnionFind 6 | { 7 | private: 8 | std::vector parent; 9 | std::vector sizes; 10 | 11 | public: 12 | UnionFind(int n); 13 | int getRoot(int n); 14 | bool areInOneSet(int n, int k); 15 | bool Union(int n, int k); 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /DisjointSet/UnionBySize/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "UnionFind.h" 3 | 4 | int main() 5 | { 6 | UnionFind uf(10); 7 | 8 | std::cout << "Union(1, 2): " << uf.Union(1, 2) << std::endl; 9 | std::cout << "Union(2, 3): " << uf.Union(2, 3) << std::endl; 10 | std::cout << "Union(4, 5): " << uf.Union(4, 5) << std::endl; 11 | std::cout << "Union(6, 7): " << uf.Union(6, 7) << std::endl; 12 | std::cout << "Union(5, 6): " << uf.Union(5, 6) << std::endl; 13 | std::cout << "Union(3, 7): " << uf.Union(3, 7) << std::endl; 14 | 15 | std::cout << "areInOneSet(1, 7): " << uf.areInOneSet(1, 7) << std::endl; 16 | std::cout << "areInOneSet(4, 6): " << uf.areInOneSet(4, 6) << std::endl; 17 | std::cout << "areInOneSet(1, 4): " << uf.areInOneSet(1, 4) << std::endl; 18 | std::cout << "areInOneSet(8, 9): " << uf.areInOneSet(8, 9) << std::endl; 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /DoublyLinkedList/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "DoublyLinkedList.hpp" 3 | 4 | bool testInitialization() { 5 | DoublyLinkedList list; 6 | if (list.isEmpty() && list.getSize() == 0) { 7 | std::cout << "testInitialization passed\n"; 8 | return true; 9 | } else { 10 | std::cout << "testInitialization failed\n"; 11 | return false; 12 | } 13 | } 14 | 15 | bool testPushBackAndBack() { 16 | DoublyLinkedList list; 17 | list.pushBack(10); 18 | if (!list.isEmpty() && list.getSize() == 1 && list.back() == 10) { 19 | list.pushBack(20); 20 | if (list.getSize() == 2 && list.back() == 20) { 21 | std::cout << "testPushBackAndBack passed\n"; 22 | return true; 23 | } 24 | } 25 | std::cout << "testPushBackAndBack failed\n"; 26 | return false; 27 | } 28 | 29 | bool testPushFrontAndFront() { 30 | DoublyLinkedList list; 31 | list.pushFront(10); 32 | if (!list.isEmpty() && list.getSize() == 1 && list.front() == 10) { 33 | list.pushFront(20); 34 | if (list.getSize() == 2 && list.front() == 20) { 35 | std::cout << "testPushFrontAndFront passed\n"; 36 | return true; 37 | } 38 | } 39 | std::cout << "testPushFrontAndFront failed\n"; 40 | return false; 41 | } 42 | 43 | bool testPopBack() { 44 | DoublyLinkedList list; 45 | list.pushBack(10); 46 | list.pushBack(20); 47 | list.popBack(); 48 | if (list.getSize() == 1 && list.back() == 10) { 49 | list.popBack(); 50 | if (list.isEmpty()) { 51 | std::cout << "testPopBack passed\n"; 52 | return true; 53 | } 54 | } 55 | std::cout << "testPopBack failed\n"; 56 | return false; 57 | } 58 | 59 | bool testPopFront() { 60 | DoublyLinkedList list; 61 | list.pushFront(10); 62 | list.pushFront(20); 63 | list.popFront(); 64 | if (list.getSize() == 1 && list.front() == 10) { 65 | list.popFront(); 66 | if (list.isEmpty()) { 67 | std::cout << "testPopFront passed\n"; 68 | return true; 69 | } 70 | } 71 | std::cout << "testPopFront failed\n"; 72 | return false; 73 | } 74 | 75 | bool testInsertAndRemove() { 76 | DoublyLinkedList list; 77 | list.pushBack(10); 78 | list.pushBack(30); 79 | auto it = list.begin(); 80 | ++it; 81 | 82 | list.insert(20, it); 83 | 84 | std::cout << list.getSize() << " " << *list.begin() << " " << *++list.begin() << " " << *++(++list.begin()) < list; 98 | list.pushBack(10); 99 | list.pushBack(20); 100 | list.pushBack(30); 101 | auto it = list.begin(); 102 | if (*it == 10 && *(++it) == 20 && *(++it) == 30) { 103 | std::cout << "testIteratorTraversal passed\n"; 104 | return true; 105 | } 106 | std::cout << "testIteratorTraversal failed\n"; 107 | return false; 108 | } 109 | 110 | bool testFrontOnEmptyList() { 111 | DoublyLinkedList list; 112 | try { 113 | list.front(); 114 | std::cout << "testFrontOnEmptyList failed\n"; 115 | return false; 116 | } catch (...) { 117 | std::cout << "testFrontOnEmptyList passed\n"; 118 | return true; 119 | } 120 | } 121 | 122 | bool testBackOnEmptyList() { 123 | DoublyLinkedList list; 124 | try { 125 | list.back(); 126 | std::cout << "testBackOnEmptyList failed\n"; 127 | return false; 128 | } catch (...) { 129 | std::cout << "testBackOnEmptyList passed\n"; 130 | return true; 131 | } 132 | } 133 | 134 | bool testPushBackMultipleElements() { 135 | DoublyLinkedList list; 136 | for (int i = 1; i <= 10; ++i) { 137 | list.pushBack(i); 138 | } 139 | bool passed = list.getSize() == 10 && list.back() == 10; 140 | std::cout << (passed ? "testPushBackMultipleElements passed\n" : "testPushBackMultipleElements failed\n"); 141 | return passed; 142 | } 143 | 144 | bool testPushFrontMultipleElements() { 145 | DoublyLinkedList list; 146 | for (int i = 1; i <= 10; ++i) { 147 | list.pushFront(i); 148 | } 149 | bool passed = list.getSize() == 10 && list.front() == 10; 150 | std::cout << (passed ? "testPushFrontMultipleElements passed\n" : "testPushFrontMultipleElements failed\n"); 151 | return passed; 152 | } 153 | 154 | bool testClearList() { 155 | DoublyLinkedList list; 156 | for (int i = 0; i < 5; ++i) { 157 | list.pushBack(i); 158 | } 159 | list.clear(); // Explicitly call destructor to clear list 160 | bool passed = list.isEmpty() && list.getSize() == 0; 161 | std::cout << (passed ? "testClearList passed\n" : "testClearList failed\n"); 162 | return passed; 163 | } 164 | 165 | bool testCopyConstructor() { 166 | DoublyLinkedList list; 167 | list.pushBack(10); 168 | list.pushBack(20); 169 | DoublyLinkedList copyList(list); 170 | bool passed = (copyList.getSize() == 2) && (copyList.front() == 10) && (copyList.back() == 20); 171 | std::cout << (passed ? "testCopyConstructor passed\n" : "testCopyConstructor failed\n"); 172 | return passed; 173 | } 174 | 175 | bool testAssignmentOperator() { 176 | DoublyLinkedList list1; 177 | list1.pushBack(10); 178 | list1.pushBack(20); 179 | DoublyLinkedList list2; 180 | list2.pushBack(30); 181 | list2 = list1; // Test assignment operator 182 | 183 | bool passed = (list2.getSize() == 2) && (list2.front() == 10) && (list2.back() == 20); 184 | std::cout << (passed ? "testAssignmentOperator passed\n" : "testAssignmentOperator failed\n"); 185 | return passed; 186 | } 187 | 188 | bool testIteratorIncrement() { 189 | DoublyLinkedList list; 190 | list.pushBack(10); 191 | list.pushBack(20); 192 | list.pushBack(30); 193 | auto it = list.begin(); 194 | if (*it == 10 && *(++it) == 20 && *(++it) == 30) { 195 | std::cout << "testIteratorIncrement passed\n"; 196 | return true; 197 | } 198 | std::cout << "testIteratorIncrement failed\n"; 199 | return false; 200 | } 201 | 202 | bool testIteratorDecrement() { 203 | DoublyLinkedList list; 204 | list.pushBack(10); 205 | list.pushBack(20); 206 | list.pushBack(30); 207 | auto it = list.end(); 208 | --it; 209 | if (*it == 30 && *(--it) == 20 && *(--it) == 10) { 210 | std::cout << "testIteratorDecrement passed\n"; 211 | return true; 212 | } 213 | std::cout << "testIteratorDecrement failed\n"; 214 | return false; 215 | } 216 | 217 | int main() { 218 | int passedTests = 0; 219 | passedTests += testInitialization(); 220 | passedTests += testPushBackAndBack(); 221 | passedTests += testPushFrontAndFront(); 222 | passedTests += testPopBack(); 223 | passedTests += testPopFront(); 224 | passedTests += testInsertAndRemove(); 225 | passedTests += testIteratorTraversal(); 226 | passedTests += testFrontOnEmptyList(); 227 | passedTests += testBackOnEmptyList(); 228 | passedTests += testPushBackMultipleElements(); 229 | passedTests += testPushFrontMultipleElements(); 230 | passedTests += testClearList(); 231 | passedTests += testCopyConstructor(); 232 | passedTests += testAssignmentOperator(); 233 | passedTests += testIteratorIncrement(); 234 | passedTests += testIteratorDecrement(); 235 | 236 | std::cout << passedTests << " out of 16 tests passed\n"; 237 | return 0; 238 | } 239 | 240 | -------------------------------------------------------------------------------- /GraphMst/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | struct MST 10 | { 11 | std::vector> edges; 12 | size_t sumOfWeights; 13 | }; 14 | 15 | class UnionFind 16 | { 17 | std::vector parent; 18 | std::vector height; 19 | public: 20 | UnionFind(int n) 21 | { 22 | parent.resize(n); 23 | height.resize(n, 0); 24 | for(int i = 0; i < n; i++) 25 | { 26 | parent[i] = i; 27 | } 28 | } 29 | int getRoot(int n) 30 | { 31 | if(parent[n] != n) 32 | { 33 | parent[n] = getRoot(parent[n]); 34 | } 35 | return parent[n]; 36 | } 37 | bool areInOneSet(int n, int k) 38 | { 39 | return getRoot(n) == getRoot(k); 40 | } 41 | bool Union(int n, int k) 42 | { 43 | int root1 = getRoot(n); 44 | int root2 = getRoot(k); 45 | if(root1 == root2) 46 | { 47 | return false; 48 | } 49 | if(height[root1] < height[root2]) 50 | { 51 | parent[root1] = root2; 52 | } 53 | else if(height[root1] > height[root2]) 54 | { 55 | parent[root2] = root1; 56 | } 57 | else 58 | { 59 | parent[root2] = root1; 60 | height[root1]++; 61 | } 62 | return true; 63 | } 64 | }; 65 | 66 | using Edge = std::tuple; 67 | 68 | class Graph 69 | { 70 | bool isOriented; 71 | size_t V; 72 | std::vector>> adj; 73 | public: 74 | Graph(size_t V, bool isOriented) 75 | { 76 | this->V = V; 77 | this->isOriented = isOriented; 78 | adj.resize(V); 79 | } 80 | void addEdge(size_t start, size_t end, int weight) 81 | { 82 | adj[start].push_back(std::make_pair(end, weight)); 83 | if(!isOriented) 84 | { 85 | adj[end].push_back(std::make_pair(start, weight)); 86 | } 87 | } 88 | size_t dijkstra(size_t start, size_t end, std::vector& path) const 89 | { 90 | 91 | struct vertexDistance 92 | { 93 | size_t vertex; 94 | size_t distFromStart; 95 | bool operator>(const vertexDistance& other) const 96 | { 97 | return distFromStart > other.distFromStart; 98 | } 99 | }; 100 | 101 | std::vector distances(V, INT_MAX); 102 | std::vector prevs(V); 103 | std::priority_queue, std::greater> q; 104 | distances[start] = 0; 105 | q.push({start, 0}); 106 | while(!q.empty()) 107 | { 108 | auto current = q.top(); 109 | q.pop(); 110 | if(current.vertex == end) 111 | { 112 | size_t temp = end; 113 | while(temp != start) 114 | { 115 | path.push_back(temp); 116 | temp = prevs[temp]; 117 | } 118 | path.push_back(start); 119 | std::reverse(path.begin(), path.end()); 120 | return distances[end]; 121 | } 122 | for(int i = 0; i < adj[current.vertex].size(); i++) 123 | { 124 | size_t neighbor = adj[current.vertex][i].first; 125 | size_t newDist = current.distFromStart + adj[current.vertex][i].second; 126 | if(distances[neighbor] > newDist) 127 | { 128 | distances[neighbor] = newDist; 129 | prevs[neighbor] = current.vertex; 130 | q.push({neighbor, newDist}); 131 | } 132 | } 133 | } 134 | return INT_MAX; 135 | } 136 | MST Prim() const 137 | { 138 | 139 | 140 | struct primEdge 141 | { 142 | size_t start; 143 | size_t end; 144 | int weight; 145 | bool operator>(const primEdge& other) const 146 | { 147 | return weight > other.weight; 148 | } 149 | }; 150 | 151 | 152 | MST result; 153 | result.sumOfWeights = 0; 154 | std::priority_queue, std::greater> q; 155 | std::vector visited(V,false); 156 | q.push({0,0,0}); //just for the beginning 157 | size_t addedEdges = 0; 158 | bool isFirst = true; 159 | while(addedEdges < V - 1 && !q.empty()) 160 | { 161 | auto current = q.top(); 162 | q.pop(); 163 | if(visited[current.end]) 164 | { 165 | continue; 166 | } 167 | visited[current.end] = true; 168 | for(int i = 0; i < adj[current.end].size(); i++) 169 | { 170 | q.push({current.end, (size_t)adj[current.end][i].first, adj[current.end][i].second}); 171 | } 172 | if(isFirst) 173 | { 174 | isFirst = false; 175 | continue; 176 | } 177 | result.edges.push_back({current.start, current.end, current.weight}); 178 | result.sumOfWeights += current.weight; 179 | addedEdges++; 180 | } 181 | return result; 182 | } 183 | MST Kruskal() const 184 | { 185 | MST result; 186 | result.sumOfWeights = 0; 187 | std::vector edges; 188 | for(int i = 0; i < V; i++) 189 | { 190 | for(auto& p : adj[i]) 191 | { 192 | edges.push_back({i, (size_t)p.first, p.second}); 193 | } 194 | } 195 | std::sort(edges.begin(), edges.end(), [](const Edge& lhs, const Edge& rhs) 196 | { 197 | return std::get<2>(lhs) < std::get<2>(rhs); 198 | }); 199 | UnionFind uf(V); 200 | size_t edgesIncluded = 0; 201 | for(int i = 0; i < edges.size() && edgesIncluded < V - 1; i++) 202 | { 203 | auto& e = edges[i]; 204 | if(uf.Union(std::get<0>(e), std::get<1>(e))) 205 | { 206 | result.edges.push_back(e); 207 | result.sumOfWeights += std::get<2>(e); 208 | edgesIncluded++; 209 | } 210 | } 211 | return result; 212 | } 213 | }; 214 | 215 | void printEdge(const Edge& e) 216 | { 217 | std::cout << std::get<0>(e) << " " << std::get<1>(e) << " " << std::get<2>(e) << std::endl; 218 | } 219 | 220 | int main() 221 | { 222 | Graph g(9, false); 223 | g.addEdge(0, 1, 4); 224 | g.addEdge(0, 7, 8); 225 | g.addEdge(1, 7, 11); 226 | g.addEdge(1, 2, 8); 227 | g.addEdge(7, 8, 7); 228 | g.addEdge(7, 6, 1); 229 | g.addEdge(8, 6, 6); 230 | g.addEdge(8, 2, 2); 231 | g.addEdge(2, 5, 4); 232 | g.addEdge(6, 5, 2); 233 | g.addEdge(2, 3, 7); 234 | g.addEdge(3, 5, 14); 235 | g.addEdge(3, 4, 9); 236 | g.addEdge(5, 4, 10); 237 | 238 | { 239 | std::vector path; 240 | size_t dist = g.dijkstra(0, 4, path); 241 | std::cout << dist << std::endl; 242 | for(auto v : path) 243 | { 244 | std::cout << v << " "; 245 | } 246 | std::cout << std::endl; 247 | } 248 | 249 | { 250 | MST mstPrim = g.Prim(); 251 | std::cout << mstPrim.sumOfWeights << std::endl; 252 | for(auto& e : mstPrim.edges) 253 | { 254 | printEdge(e); 255 | } 256 | } 257 | 258 | { 259 | MST mstKruskal = g.Kruskal(); 260 | std::cout << mstKruskal.sumOfWeights << std::endl; 261 | for(auto& e : mstKruskal.edges) 262 | { 263 | printEdge(e); 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /GraphShortestPath/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // --4-->X 7 | 8 | class Graph 9 | { 10 | std::vector>> adj; 11 | bool oriented; 12 | 13 | public: 14 | Graph(size_t vertexCount, bool isOriented); 15 | void addEdge(size_t start, size_t end, int weight); 16 | 17 | size_t shortestPath(size_t start, size_t end, std::vector& path) const; 18 | }; 19 | 20 | Graph::Graph(size_t vertexCount, bool isOriented) : adj(vertexCount), oriented(isOriented) 21 | {} 22 | 23 | void Graph::addEdge(size_t start, size_t end, int weight) 24 | { 25 | adj[start].push_back({ end, weight }); 26 | if (!oriented) 27 | adj[end].push_back({ start, weight }); 28 | } 29 | 30 | size_t Graph::shortestPath(size_t start, size_t end, std::vector& path) const 31 | { 32 | struct VertexAndDist 33 | { 34 | size_t currVertex; 35 | size_t dist; 36 | 37 | bool operator<(const VertexAndDist& other) const 38 | { 39 | return dist > other.dist; 40 | } 41 | }; 42 | 43 | std::vector distances(adj.size(), INT_MAX); 44 | std::vector found(adj.size(), false); 45 | std::vector prev(adj.size(), INT_MAX); 46 | 47 | distances[start] = 0; 48 | std::priority_queue pq; //MAX HEAP 49 | 50 | pq.push({start, 0 }); 51 | 52 | while (!pq.empty()) 53 | { 54 | auto currentClosest = pq.top(); 55 | pq.pop(); 56 | 57 | if (found[currentClosest.currVertex]) 58 | continue; 59 | found[currentClosest.currVertex] = true; 60 | 61 | 62 | if (end == currentClosest.currVertex) 63 | { 64 | while (end != start) 65 | { 66 | path.push_back(end); 67 | end = prev[end]; 68 | } 69 | path.push_back(start); 70 | 71 | std::reverse(path.begin(), path.end()); 72 | 73 | return currentClosest.dist; 74 | } 75 | 76 | for (auto& edge : adj[currentClosest.currVertex]) 77 | { 78 | size_t n = edge.first; 79 | size_t edgeWeight = edge.second; 80 | 81 | if (distances[n] > distances[currentClosest.currVertex] + edgeWeight) 82 | { 83 | distances[n] = distances[currentClosest.currVertex] + edgeWeight; 84 | pq.push({ n, distances[currentClosest.currVertex] + edgeWeight }); 85 | prev[n] = currentClosest.currVertex; 86 | } 87 | } 88 | } 89 | 90 | 91 | return 0; 92 | } 93 | 94 | 95 | 96 | int main() 97 | { 98 | Graph g(3, true); 99 | g.addEdge(0,1, 3); 100 | g.addEdge(0, 2, 10); 101 | g.addEdge(1, 2, 4); 102 | 103 | std::vector path; 104 | std::cout << g.shortestPath(0, 2, path) << std::endl; 105 | 106 | for (int i = 0; i < path.size(); i++) 107 | std::cout << path[i] << " "; 108 | return 0; 109 | } -------------------------------------------------------------------------------- /GraphShortestPath/sp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class Graph 11 | { 12 | bool isOriented; 13 | size_t V; 14 | std::vector>> adj; 15 | 16 | public: 17 | Graph(size_t V, bool isOriented); 18 | void addEdge(size_t start, size_t end, int weight); 19 | 20 | size_t dijkstra(size_t start, size_t end, std::vector& path) const; 21 | 22 | }; 23 | 24 | Graph::Graph(size_t V, bool isOriented) : adj(V), V(V), isOriented(isOriented) 25 | {} 26 | void Graph::addEdge(size_t start, size_t end, int weight) 27 | { 28 | adj[start].push_back(std::make_pair(end, weight)); 29 | if (!isOriented) 30 | adj[end].push_back(std::make_pair(start, weight)); 31 | } 32 | 33 | size_t Graph::dijkstra(size_t start, size_t end, std::vector& path) const 34 | { 35 | std::vector distances(V, INT_MAX); 36 | std::vector prevs(V); 37 | 38 | 39 | struct vertexAndDistancePair 40 | { 41 | size_t vertex; 42 | size_t distFromStart; 43 | 44 | bool operator<(const vertexAndDistancePair& other) const 45 | { 46 | return distFromStart > other.distFromStart; 47 | } 48 | }; 49 | 50 | std::priority_queue q; 51 | 52 | distances[start] = 0; 53 | 54 | q.push({ start, 0 }); 55 | 56 | while (!q.empty()) 57 | { 58 | vertexAndDistancePair current = q.top(); 59 | q.pop(); 60 | 61 | if (current.vertex == end) 62 | { 63 | //get path 64 | while (end != start) 65 | { 66 | path.push_back(end); 67 | end = prevs[end]; 68 | } 69 | path.push_back(start); 70 | 71 | std::reverse(path.begin(), path.end()); 72 | // 73 | return distances[current.vertex]; 74 | } 75 | 76 | 77 | 78 | for (int i = 0; i < adj[current.vertex].size(); i++) 79 | { 80 | size_t currentNeighbor = adj[current.vertex][i].first; 81 | 82 | size_t newDist = current.distFromStart + adj[current.vertex][i].second; 83 | if (distances[currentNeighbor] > newDist) 84 | { 85 | distances[currentNeighbor] = newDist; 86 | q.push({ currentNeighbor, newDist }); 87 | prevs[currentNeighbor] = current.vertex; 88 | } 89 | } 90 | 91 | } 92 | return INT_MAX; 93 | 94 | } 95 | 96 | int main() 97 | { 98 | Graph g(9, false); 99 | g.addEdge(0, 1, 4); 100 | g.addEdge(0, 7, 8); 101 | g.addEdge(1, 7, 11); 102 | g.addEdge(1, 2, 8); 103 | g.addEdge(7, 8, 7); 104 | g.addEdge(7, 6, 1); 105 | g.addEdge(8, 6, 6); 106 | g.addEdge(8, 2, 2); 107 | g.addEdge(2, 5, 4); 108 | g.addEdge(6, 5, 2); 109 | g.addEdge(2, 3, 7); 110 | g.addEdge(3, 5, 14); 111 | g.addEdge(3, 4, 9); 112 | g.addEdge(5, 4, 10); 113 | 114 | { //Dijkstra example 115 | std::vector path; 116 | std::cout << "Shortest weight path from 0 to 4(with Dijkstra):" << g.dijkstra(0, 4, path) << std::endl; 117 | std::cout << "Path : "; 118 | for (int i = 0; i < path.size(); i++) 119 | std::cout << path[i] << " "; 120 | std::cout << std::endl << std::endl << std::endl; 121 | } 122 | 123 | 124 | } 125 | -------------------------------------------------------------------------------- /GraphTraversals/traversals.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | class Graph 8 | { 9 | std::vector> adj; 10 | bool oriented; 11 | 12 | void dfs_help_rec(size_t start, std::vector& visited, std::vector& result) const; 13 | bool contains_cycle_rec(size_t start, std::vector& visited, std::vector& stack) const; 14 | void topo_sort_rec(size_t start, std::vector& visited, std::vector& st) const; 15 | 16 | void connected_components_bfs(size_t start, std::vector& visited) const; 17 | public: 18 | Graph(size_t vertexCount, bool isOriented); 19 | void addEdge(size_t start, size_t end); 20 | 21 | void BFS(size_t start) const; 22 | void DFS_ITER(size_t start) const; 23 | void DFS_REC(size_t start) const; 24 | int BFS_shortest_path(size_t start, size_t end) const; 25 | int BFS_shortest_path_vector(size_t start, size_t end) const; 26 | 27 | bool containsCycle() const; 28 | std::vector topoSort() const; 29 | size_t getConnectedComponentsCount() const; 30 | 31 | }; 32 | 33 | Graph::Graph(size_t vertexCount, bool isOriented) : adj(vertexCount), oriented(isOriented) 34 | {} 35 | 36 | void Graph::addEdge(size_t start, size_t end) 37 | { 38 | adj[start].push_back((int)end); 39 | if (!oriented) 40 | adj[end].push_back((int)start); 41 | } 42 | 43 | void Graph::BFS(size_t start) const 44 | { 45 | std::vector visited(adj.size()); 46 | 47 | std::queue q; 48 | q.push(start); 49 | visited[start] = true; 50 | 51 | while (!q.empty()) 52 | { 53 | size_t currentVertex = q.front(); 54 | q.pop(); 55 | 56 | for (int i = 0; i < adj[currentVertex].size(); i++) 57 | { 58 | size_t neighbor = adj[currentVertex][i]; 59 | if (visited[neighbor]) 60 | continue; 61 | 62 | std::cout << neighbor << std::endl; 63 | visited[neighbor] = true; 64 | q.push(neighbor); 65 | } 66 | } 67 | } 68 | 69 | int Graph::BFS_shortest_path(size_t start, size_t end) const 70 | { 71 | if (start == end) return 0; 72 | 73 | std::vector visited(adj.size(), false); 74 | std::queue q; 75 | q.push(start); 76 | visited[start] = true; 77 | 78 | int dist = 0; 79 | 80 | while (!q.empty()) 81 | { 82 | size_t currentLevelSize = q.size(); 83 | for (size_t i = 0; i < currentLevelSize; i++) 84 | { 85 | size_t currentVertex = q.front(); 86 | q.pop(); 87 | 88 | for (auto neighbor : adj[currentVertex]) 89 | { 90 | if (visited[neighbor]) 91 | continue; 92 | if (neighbor == end) 93 | return dist + 1; 94 | 95 | q.push(neighbor); 96 | visited[neighbor] = true; 97 | } 98 | } 99 | dist++; 100 | } 101 | 102 | return -1; 103 | } 104 | 105 | int Graph::BFS_shortest_path_vector(size_t start, size_t end) const 106 | { 107 | std::vector currLevel = { start }; 108 | size_t dist = 0; 109 | std::vector visited(adj.size(), false); 110 | 111 | while (!currLevel.empty()) 112 | { 113 | std::vector nextLevel; 114 | 115 | for (size_t currNode : currLevel) 116 | { 117 | for (size_t currNodeChild : adj[currNode]) 118 | { 119 | if (visited[currNodeChild]) 120 | continue; 121 | visited[currNodeChild] = true; 122 | if (currNodeChild == end) 123 | return dist + 1; 124 | else 125 | nextLevel.push_back(currNodeChild); 126 | } 127 | } 128 | currLevel.swap(nextLevel); 129 | } 130 | return -1; 131 | } 132 | 133 | void Graph::DFS_ITER(size_t start) const 134 | { 135 | std::vector visited(adj.size(), false); 136 | 137 | std::stack s; 138 | s.push(start); 139 | 140 | while (!s.empty()) 141 | { 142 | size_t current = s.top(); 143 | s.pop(); 144 | 145 | if (visited[current]) 146 | continue; 147 | 148 | visited[current] = true; 149 | std::cout << current << " "; 150 | 151 | for (auto neighbor : adj[current]) 152 | { 153 | s.push(neighbor); 154 | } 155 | } 156 | } 157 | 158 | void Graph::dfs_help_rec(size_t curr, std::vector& visited, std::vector& result) const 159 | { 160 | visited[curr] = true; 161 | std::cout << curr << " "; 162 | for (auto neighbor : adj[curr]) 163 | { 164 | if (!visited[neighbor]) 165 | dfs_help_rec(neighbor, visited, result); 166 | } 167 | } 168 | 169 | void Graph::DFS_REC(size_t start) const 170 | { 171 | std::vector visited(adj.size(), false); 172 | std::vector result; 173 | 174 | dfs_help_rec(start, visited, result); 175 | } 176 | 177 | bool Graph::contains_cycle_rec(size_t start, std::vector& visited, std::vector& stack) const 178 | { 179 | if (!visited[start]) 180 | { 181 | visited[start] = true; 182 | stack[start] = true; 183 | 184 | for (auto neighbor : adj[start]) 185 | { 186 | if (!visited[neighbor] && contains_cycle_rec(neighbor, visited, stack)) 187 | return true; 188 | else if (stack[neighbor]) 189 | return true; 190 | } 191 | } 192 | stack[start] = false; 193 | return false; 194 | } 195 | 196 | bool Graph::containsCycle() const 197 | { 198 | std::vector visited(adj.size(), false); 199 | std::vector inStack(adj.size(), false); 200 | 201 | for (size_t i = 0; i < adj.size(); i++) 202 | { 203 | if (contains_cycle_rec(i, visited, inStack)) 204 | return true; 205 | } 206 | return false; 207 | } 208 | 209 | void Graph::topo_sort_rec(size_t start, std::vector& visited, std::vector& st) const 210 | { 211 | visited[start] = true; 212 | for (int i = 0; i < adj[start].size(); i++) 213 | { 214 | size_t neihbor = adj[start][i]; 215 | if (!visited[neihbor]) 216 | topo_sort_rec(neihbor, visited, st); 217 | } 218 | st.push_back(start); 219 | } 220 | 221 | std::vector Graph::topoSort() const 222 | { 223 | std::vector visited(adj.size()); 224 | std::vector result; 225 | 226 | for (int i = 0; i < adj.size(); i++) 227 | { 228 | if (!visited[i]) 229 | topo_sort_rec(i, visited, result); 230 | } 231 | 232 | std::reverse(result.begin(), result.end()); 233 | 234 | return std::move(result); 235 | } 236 | 237 | void Graph::connected_components_bfs(size_t start, std::vector& visited) const 238 | { 239 | std::queue q; 240 | q.push(start); 241 | visited[start] = true; 242 | 243 | while (!q.empty()) 244 | { 245 | size_t currentVertex = q.front(); 246 | q.pop(); 247 | 248 | for (int i = 0; i < adj[currentVertex].size(); i++) 249 | { 250 | size_t neighbor = adj[currentVertex][i]; 251 | if (visited[neighbor]) 252 | continue; 253 | 254 | visited[neighbor] = true; 255 | q.push(neighbor); 256 | } 257 | } 258 | } 259 | 260 | size_t Graph::getConnectedComponentsCount() const 261 | { 262 | size_t connectedComponentsCount = 0; 263 | std::vector visited(adj.size(), false); 264 | 265 | for(int i = 0; i < adj.size(); i++) 266 | { 267 | if(!visited[i]) 268 | { 269 | connectedComponentsCount++; 270 | connected_components_bfs(i, visited); 271 | } 272 | 273 | } 274 | return connectedComponentsCount; 275 | } 276 | 277 | 278 | 279 | int main() 280 | { 281 | Graph g(9, false); 282 | 283 | g.addEdge(0, 1); 284 | g.addEdge(0, 3); 285 | g.addEdge(1, 3); 286 | g.addEdge(3, 2); 287 | 288 | g.addEdge(2, 1); 289 | g.addEdge(4, 2); 290 | g.addEdge(5, 2); 291 | g.addEdge(6, 1); 292 | 293 | g.addEdge(4, 6); 294 | 295 | g.BFS(0); 296 | 297 | return 0; 298 | } 299 | -------------------------------------------------------------------------------- /LinearProbingHash/Map/HashMap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | template > 12 | class HashMap 13 | { 14 | private: 15 | struct Bucket 16 | { 17 | std::optional> entry; 18 | bool tombstone = false; 19 | }; 20 | 21 | public: 22 | using element = std::pair; 23 | 24 | class ConstIterator 25 | { 26 | public: 27 | const element& operator*() const 28 | { 29 | return *(context.buckets[index].entry); 30 | } 31 | 32 | ConstIterator operator++(int) 33 | { 34 | ConstIterator old(*this); 35 | advance(); 36 | return old; 37 | } 38 | 39 | ConstIterator& operator++() 40 | { 41 | advance(); 42 | return *this; 43 | } 44 | 45 | bool operator==(const ConstIterator& other) const 46 | { 47 | return (&context == &other.context) && (index == other.index); 48 | } 49 | 50 | bool operator!=(const ConstIterator& other) const 51 | { 52 | return !(*this == other); 53 | } 54 | 55 | private: 56 | friend class HashMap; 57 | 58 | ConstIterator(int idx, const HashMap& ctx) 59 | : index(idx), context(ctx) 60 | { 61 | } 62 | 63 | void advance() 64 | { 65 | do 66 | { 67 | ++index; 68 | } while (index >= 0 && index < (int)context.buckets.size() 69 | && !context.isActive(context.buckets[index])); 70 | 71 | if (index < 0 || index >= (int)context.buckets.size()) 72 | { 73 | index = -1; 74 | } 75 | } 76 | 77 | int index; 78 | const HashMap& context; 79 | }; 80 | 81 | HashMap(size_t table_size = 10, size_t probe_step = 3) 82 | : size(0), k(probe_step), buckets(table_size) 83 | { 84 | } 85 | 86 | void add(const KeyType& key, const ValueType& value) 87 | { 88 | double loadFactor = static_cast(size) / buckets.size(); 89 | if (loadFactor > maxLoadFactor) 90 | { 91 | resize(buckets.size() * 2); 92 | } 93 | 94 | size_t idx = hasher(key) % buckets.size(); 95 | while (isActive(buckets[idx])) 96 | { 97 | if (buckets[idx].entry->first == key) 98 | { 99 | throw std::logic_error("Already exists!"); 100 | } 101 | idx = (idx + k) % buckets.size(); 102 | } 103 | 104 | buckets[idx].entry = std::make_pair(key, value); 105 | buckets[idx].tombstone = false; 106 | ++size; 107 | } 108 | 109 | void remove(const KeyType& key) 110 | { 111 | size_t idx = hasher(key) % buckets.size(); 112 | size_t start = idx; 113 | while (true) 114 | { 115 | if (!buckets[idx].entry.has_value() && !buckets[idx].tombstone) 116 | { 117 | break; 118 | } 119 | if (isActive(buckets[idx]) && buckets[idx].entry->first == key) 120 | { 121 | buckets[idx].tombstone = true; 122 | buckets[idx].entry.reset(); 123 | --size; 124 | break; 125 | } 126 | 127 | idx = (idx + k) % buckets.size(); 128 | if (idx == start) 129 | break; 130 | } 131 | } 132 | 133 | ConstIterator get(const KeyType& key) const 134 | { 135 | size_t idx = hasher(key) % buckets.size(); 136 | size_t start = idx; 137 | while (true) 138 | { 139 | if (!buckets[idx].entry.has_value() && !buckets[idx].tombstone) 140 | { 141 | return cend(); 142 | } 143 | if (isActive(buckets[idx]) && buckets[idx].entry->first == key) 144 | { 145 | return ConstIterator((int)idx, *this); 146 | } 147 | 148 | idx = (idx + k) % buckets.size(); 149 | if (idx == start) 150 | { 151 | return cend(); 152 | } 153 | } 154 | } 155 | 156 | ConstIterator cbegin() const 157 | { 158 | if (size == 0) 159 | { 160 | return cend(); 161 | } 162 | for (int i = 0; i < (int)buckets.size(); i++) 163 | { 164 | if (isActive(buckets[i])) 165 | { 166 | return ConstIterator(i, *this); 167 | } 168 | } 169 | return cend(); 170 | } 171 | 172 | ConstIterator cend() const 173 | { 174 | return ConstIterator(-1, *this); 175 | } 176 | 177 | size_t getSize() const 178 | { 179 | return size; 180 | } 181 | 182 | private: 183 | bool isActive(const Bucket& b) const 184 | { 185 | return b.entry.has_value() && !b.tombstone; 186 | } 187 | 188 | void resize(size_t newSize) 189 | { 190 | std::vector oldBuckets = std::move(buckets); 191 | buckets.resize(newSize); 192 | for (auto& b : buckets) 193 | { 194 | b.entry.reset(); 195 | b.tombstone = false; 196 | } 197 | size = 0; 198 | 199 | for (auto& b : oldBuckets) 200 | { 201 | if (isActive(b)) 202 | { 203 | add(b.entry->first, b.entry->second); 204 | } 205 | } 206 | } 207 | 208 | private: 209 | size_t size; 210 | size_t k; 211 | std::vector buckets; 212 | Hasher hasher{}; 213 | const double maxLoadFactor = 0.8; 214 | }; 215 | -------------------------------------------------------------------------------- /LinearProbingHash/Map/main.cpp: -------------------------------------------------------------------------------- 1 | #include "HashMap.hpp" 2 | int main() 3 | { 4 | HashMap hashTable; 5 | 6 | hashTable.add("apple", 10); 7 | hashTable.add("banana", 20); 8 | hashTable.add("cherry", 30); 9 | 10 | for (auto it = hashTable.cbegin(); it != hashTable.cend(); it++) 11 | { 12 | std::cout << (*it).first << " " << (*it).second << std::endl; 13 | } 14 | 15 | auto it = hashTable.get("banana"); 16 | if (it != hashTable.cend()) 17 | { 18 | std::cout << "Found: " << (*it).first << " -> " << (*it).second << std::endl; 19 | 20 | } 21 | 22 | 23 | hashTable.remove("apple"); 24 | 25 | std::cout << "Size of table: " << hashTable.getSize() << std::endl; 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /LinearProbingHash/Set/HashSet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | template > 11 | class HashSet 12 | { 13 | public: 14 | class ConstIterator 15 | { 16 | public: 17 | const KeyType& operator*() const; 18 | ConstIterator operator++(int); 19 | ConstIterator& operator++(); 20 | bool operator==(const ConstIterator& other) const; 21 | bool operator!=(const ConstIterator& other) const; 22 | private: 23 | ConstIterator(int index, const HashSet& context); 24 | int index; 25 | const HashSet& context; 26 | friend class HashSet; 27 | }; 28 | 29 | HashSet(size_t table_size = 10, size_t probe_step = 3); 30 | void add(const KeyType& key); 31 | void remove(const KeyType& key); 32 | ConstIterator get(const KeyType& key) const; 33 | ConstIterator cbegin() const; 34 | ConstIterator cend() const; 35 | size_t getSize() const; 36 | private: 37 | struct Data 38 | { 39 | std::optional data; 40 | bool tombstone; 41 | }; 42 | std::vector data; 43 | size_t size; 44 | size_t k; 45 | double maxLoadFactor = 0.8; 46 | Hasher hasher; 47 | bool containsElementAtIndex(size_t index) const 48 | { 49 | return data[index].data.has_value() && !data[index].tombstone; 50 | } 51 | void resize(size_t newSize); 52 | }; 53 | 54 | template 55 | HashSet::HashSet(size_t table_size, size_t probe_step) 56 | : size(0), k(probe_step) 57 | { 58 | data.resize(table_size); 59 | for (auto& d : data) 60 | { 61 | d.data.reset(); 62 | d.tombstone = false; 63 | } 64 | } 65 | 66 | template 67 | void HashSet::add(const KeyType& key) 68 | { 69 | double loadFactor = (double)size / data.size(); 70 | if (loadFactor > maxLoadFactor) 71 | { 72 | resize(data.size() * 2); 73 | } 74 | int indexToPut = hasher(key) % data.size(); 75 | while (containsElementAtIndex(indexToPut)) 76 | { 77 | if (*data[indexToPut].data == key) 78 | { 79 | throw std::logic_error("Already exists!"); 80 | } 81 | (indexToPut += k) %= data.size(); 82 | } 83 | data[indexToPut].data = key; 84 | data[indexToPut].tombstone = false; 85 | size++; 86 | } 87 | 88 | template 89 | void HashSet::remove(const KeyType& key) 90 | { 91 | int index = hasher(key) % data.size(); 92 | while (data[index].data.has_value()) 93 | { 94 | if (!data[index].tombstone && *data[index].data == key) 95 | { 96 | data[index].tombstone = true; 97 | size--; 98 | break; 99 | } 100 | (index += k) %= data.size(); 101 | } 102 | } 103 | 104 | template 105 | typename HashSet::ConstIterator HashSet::get(const KeyType& key) const 106 | { 107 | int index = hasher(key) % data.size(); 108 | while (data[index].data.has_value()) 109 | { 110 | if (!data[index].tombstone && *data[index].data == key) 111 | { 112 | return ConstIterator(index, *this); 113 | } 114 | (index += k) %= data.size(); 115 | } 116 | return cend(); 117 | } 118 | 119 | template 120 | typename HashSet::ConstIterator HashSet::cbegin() const 121 | { 122 | if (size == 0) 123 | { 124 | return cend(); 125 | } 126 | for (int i = 0; i < (int)data.size(); i++) 127 | { 128 | if (containsElementAtIndex(i)) 129 | { 130 | return ConstIterator(i, *this); 131 | } 132 | } 133 | return cend(); 134 | } 135 | 136 | template 137 | typename HashSet::ConstIterator HashSet::cend() const 138 | { 139 | return ConstIterator(-1, *this); 140 | } 141 | 142 | template 143 | size_t HashSet::getSize() const 144 | { 145 | return size; 146 | } 147 | 148 | template 149 | void HashSet::resize(size_t newSize) 150 | { 151 | std::vector oldData = data; 152 | data.clear(); 153 | data.resize(newSize); 154 | for (auto& d : data) 155 | { 156 | d.data.reset(); 157 | d.tombstone = false; 158 | } 159 | size = 0; 160 | for (auto& d : oldData) 161 | { 162 | if (d.data.has_value() && !d.tombstone) 163 | { 164 | add(*d.data); 165 | } 166 | } 167 | } 168 | 169 | template 170 | HashSet::ConstIterator::ConstIterator(int index, const HashSet& context) 171 | : index(index), context(context) 172 | { 173 | } 174 | 175 | template 176 | const KeyType& HashSet::ConstIterator::operator*() const 177 | { 178 | return *context.data[index].data; 179 | } 180 | 181 | template 182 | typename HashSet::ConstIterator HashSet::ConstIterator::operator++(int) 183 | { 184 | int oldIndex = index; 185 | do 186 | { 187 | index++; 188 | } 189 | while (index < (int)context.data.size() && !context.containsElementAtIndex(index)); 190 | if (index >= (int)context.data.size()) 191 | { 192 | index = -1; 193 | } 194 | return Iterator(oldIndex, context); 195 | } 196 | 197 | template 198 | typename HashSet::ConstIterator& HashSet::ConstIterator::operator++() 199 | { 200 | do 201 | { 202 | index++; 203 | } 204 | while (index < (int)context.data.size() && !context.containsElementAtIndex(index)); 205 | if (index >= (int)context.data.size()) 206 | { 207 | index = -1; 208 | } 209 | return *this; 210 | } 211 | 212 | template 213 | bool HashSet::ConstIterator::operator==(const ConstIterator& other) const 214 | { 215 | return index == other.index; 216 | } 217 | 218 | template 219 | bool HashSet::ConstIterator::operator!=(const ConstIterator& other) const 220 | { 221 | return index != other.index; 222 | } 223 | -------------------------------------------------------------------------------- /LinearProbingHash/Set/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "HashSet.hpp" 3 | 4 | int main() 5 | { 6 | HashSet set; 7 | 8 | // Add elements 9 | set.add(10); 10 | set.add(20); 11 | set.add(30); 12 | 13 | std::cout << "Added elements: 10, 20, 30\n"; 14 | 15 | // Check size 16 | std::cout << "Set size: " << set.getSize() << "\n"; 17 | 18 | // Test contains (using get) 19 | if (set.get(20) != set.cend()) 20 | { 21 | std::cout << "Set contains 20\n"; 22 | } 23 | else 24 | { 25 | std::cout << "Set does not contain 20\n"; 26 | } 27 | 28 | if (set.get(40) == set.cend()) 29 | { 30 | std::cout << "Set does not contain 40\n"; 31 | } 32 | 33 | // Remove an element 34 | set.remove(20); 35 | std::cout << "Removed element 20\n"; 36 | 37 | if (set.get(20) == set.cend()) 38 | { 39 | std::cout << "Set does not contain 20 after removal\n"; 40 | } 41 | 42 | // Iterate over the set 43 | std::cout << "Remaining elements in the set: "; 44 | for (auto it = set.cbegin(); it != set.cend(); ++it) 45 | { 46 | std::cout << *it << " "; 47 | } 48 | std::cout << "\n"; 49 | 50 | // Test adding a duplicate element 51 | try 52 | { 53 | set.add(10); 54 | std::cout << "Added duplicate element 10\n"; 55 | } 56 | catch (const std::logic_error& e) 57 | { 58 | std::cout << "Caught exception: " << e.what() << "\n"; 59 | } 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /Miscellaneous/LeastRecentlyUsedCache: -------------------------------------------------------------------------------- 1 | // Task: 2 | // Design and build a "least recently used" cache, which evicts the least 3 | // recently used item. The cache should map from keys to values (allowing you 4 | // to insert and retrieve a value associated with a particular key) and be 5 | // initialized with a max size. When it is full, it should evict the least 6 | // recently used item. 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include //we need c++ 17 15 | 16 | template 17 | class LeastRecentlyUsedCache 18 | { 19 | using CacheList = std::list>; 20 | using CacheListIterator = typename CacheList::iterator; 21 | using CacheMap = std::unordered_map; 22 | 23 | CacheList _cache; 24 | CacheMap _keyToCacheMap; 25 | size_t _capacity; 26 | 27 | void markAsMostRecentlyUsed(typename CacheMap::iterator mapIt) 28 | { 29 | CacheListIterator cacheIt = mapIt->second; 30 | _cache.splice(_cache.end(), _cache, cacheIt); 31 | } 32 | 33 | void handleCacheSize() 34 | { 35 | if(_cache.size() > _capacity) 36 | { 37 | KeyType key = _cache.front().first; 38 | _keyToCacheMap.erase(key); 39 | _cache.pop_front(); 40 | } 41 | } 42 | 43 | public: 44 | LeastRecentlyUsedCache(size_t capacity) : _capacity(capacity) {} 45 | 46 | // Return an optional value. If key is not found, returns std::nullopt 47 | std::optional findInCache(const KeyType& key) 48 | { 49 | auto it = _keyToCacheMap.find(key); 50 | if (it == _keyToCacheMap.end()) 51 | { 52 | return std::nullopt; 53 | } 54 | markAsMostRecentlyUsed(it); 55 | return it->second->second; 56 | } 57 | 58 | // If key is new, add it. If key is already present, update its value 59 | bool addInCache(const KeyType& key, const ValueType& value) 60 | { 61 | auto [mapIt, inserted] = _keyToCacheMap.insert({key, _cache.end()}); 62 | 63 | if (!inserted) 64 | { 65 | // mapIt points to the existing element 66 | mapIt->second->second = value; // update value 67 | markAsMostRecentlyUsed(mapIt); 68 | return true; 69 | } 70 | 71 | _cache.push_back({key, value}); 72 | auto endIter = _cache.end(); 73 | --endIter; 74 | mapIt->second = endIter; 75 | 76 | handleCacheSize(); 77 | return true; 78 | } 79 | }; 80 | 81 | 82 | ////Mocking 83 | 84 | // Simulates heavy work 85 | template 86 | Value workHard(const Key &request) { 87 | std::this_thread::sleep_for(std::chrono::seconds(3)); 88 | return Value(request); 89 | } 90 | 91 | // Specialization for std::string 92 | template<> 93 | std::string workHard(const std::string &request) { 94 | static const std::string request_suffix("request"); 95 | static const std::string response_suffix("response"); 96 | std::this_thread::sleep_for(std::chrono::seconds(3)); 97 | size_t request_body_length = request.size() - request_suffix.size(); 98 | return request.substr(0, request_body_length) + response_suffix; 99 | } 100 | 101 | // Specialization for int 102 | template<> 103 | std::string workHard(const int& request) { 104 | static const std::string response_pref("response "); 105 | std::this_thread::sleep_for(std::chrono::seconds(3)); 106 | return response_pref + std::to_string(request); 107 | } 108 | 109 | // Retrieves from cache if possible. Otherwise computes using workHard and caches it 110 | template 111 | Value handle(const Key &request, LeastRecentlyUsedCache& cache) { 112 | auto res = cache.findInCache(request); 113 | if (res.has_value()) { 114 | return *res; 115 | } 116 | Value response = workHard(request); 117 | cache.addInCache(request, response); 118 | return response; 119 | } 120 | 121 | int main(int argc, char *argv[]) { 122 | 123 | const size_t CACHE_CAPACITY = 2; 124 | LeastRecentlyUsedCache cache(CACHE_CAPACITY); 125 | 126 | std::string response = handle(1, cache); 127 | std::cout << response << "(s)" << std::endl; 128 | 129 | response = handle(1, cache); 130 | std::cout << response << "(f)" << std::endl; 131 | 132 | response = handle(2, cache); 133 | std::cout << response << "(s)" << std::endl; 134 | 135 | response = handle(2, cache); 136 | std::cout << response << "(f)" << std::endl; 137 | 138 | response = handle(1, cache); 139 | std::cout << response << "(f)" << std::endl; 140 | 141 | response = handle(3, cache); 142 | std::cout << response << "(s)" << std::endl; 143 | 144 | response = handle(3, cache); 145 | std::cout << response << "(f)" << std::endl; 146 | 147 | response = handle(1, cache); 148 | std::cout << response << "(f)" << std::endl; 149 | 150 | response = handle(2, cache); 151 | std::cout << response << "(s)" << std::endl; 152 | 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /Miscellaneous/Lists_tasks/README.md: -------------------------------------------------------------------------------- 1 | 2 | **Задача 1:** Даден е едносвързан **цикличен** списък, чиито елементи са стрингове. 3 | Да се реализира функция *unite(Node\* list)*, която получава като параметър указател към елемент на цикличния списък от стрингове и ***обединява всички двойки последователни елементи на списъка, за които последния символ на единия елемент съвпада с първия символ на непосредствено следващия му елемент***, в общ елемент, чийто низ е съставен от слепването на стринговете на двата елемента, разделени с тире. 4 | Функцията да изкарва списъка на стандартния изход, започвайки от лексикографски най-малкия низ. 5 | *Вход:* 6 | ```c++ 7 | street -> taxi -> ink -> dog -> smile -> eat -> tall -> pass 8 | ``` 9 | *Изход:* 10 | ```c++ 11 | dog 12 | 13 | smile-eat-tall 14 | 15 | pass-street-taxi-ink 16 | ``` 17 | 18 | ***Задача 2:*** Даден е двусвързан списък с четен брой елементи. Всеки елемент представлява едносвързан списък от числа в интервала [0,9]. 19 | Всеки едносвързан списък сам по себе си интерпретира число, чиито цифри са елементите на списъка в същия ред. ( 3->4->5 е числото 345). 20 | Напишете функция, която получава като параметър двусвързан списък от този вид и проверява **дали първите n/2 (където n е дължината на списъка) 21 | числа образуват растяща редица и вторите n/2 числа - намаляваща.** 22 | 23 | ***Задача 3:*** Даден е едносвъран списък, чийто елементи са числа. Напишете функция **rearange**, която преподрежда елементите, така че първо да бъдат четните числа, после нечетните. 24 | Относителната наредба между числата трябва да се запази. Решението ви трябва да работи за O(n) по време. 25 | 26 | **Пример:** Списъкът да е: 3->5->2->9->4 27 | 28 | **Изход:** 2->4->3->5->9 29 | 30 | **Задача 4:** Даден е списък **l** с елементи опашки от естествени числа. 31 | Да се дефинира функция, която връща *дали последователната конкатенация на всички опашки образува сортирана редица.* 32 | **Да се реши с константна памет и да не се променят входните данни!** 33 | 34 | *Вход:*                                              *Изход:* 35 | ```c++ 36 | 1 -> 2 -> 3 yes 37 | | 1 -> 2 -> 3 -> 6 -> 9 -> 10 -> 38 | v 11 -> 22 -> 33 39 | 6 -> 9 -> 10 40 | | 41 | v 42 | 11 -> 22 -> 33 43 | | 44 | v 45 | empty 46 | ``` 47 | *Вход:*                                              *Изход:* 48 | ```c++ 49 | 1 no 50 | | 51 | v 52 | 6 -> 9 -> 10 53 | | 54 | v 55 | 9 -> 22 56 | ``` 57 | *Вход:*                                              *Изход:* 58 | ```c++ 59 | 1 -> 2 -> 3 no 60 | | 61 | v 62 | 4 -> 5 -> 4 63 | ``` 64 | 65 | **Задача 5:** Даден е списък **l** с елементи опашки от естествени числа. 66 | - Ако **n** последователни опашки са с равна големина, то те са "подобни" и *трябва да се слеят*. 67 | - Ако **две** последователни опашки не са с равен брой елементи, *то той трябва да се изравни с разлика до единица*. 68 | 69 | *Вход:*                                              *Изход:* 70 | ```c++ 71 | 2 -> 4 -> 6 2 -> 4 -> 6 -> 8 -> 0 -> 7 72 | | | 73 | v v 74 | 8 -> 0 -> 7 7 -> 9 -> 23 -> 22 75 | | | 76 | v v 77 | 5 -> 7 -> 9 -> 23 -> 22 9 -> 1 -> 5 78 | | | 79 | v v 80 | 9 -> 1 2 -> 1 -> 33 -> 44 81 | | 82 | V 83 | 2 84 | | 85 | v 86 | 1 87 | | 88 | v 89 | 33 -> 44 90 | ``` 91 | 92 | **Задача 6 (Flatten):** Даден е указател към началото на двойно свързан списък с *четен брой елементи*, които имат и още един указател - **child**. Този указател сочи към друг отделен двойно свързан списък. 93 | В първата половина на списъка, child указателите на елементите са празни. Но във втората се е получила аномалия на списъка, и някои елементи имат child указатели, които не са празни. 94 | По този начин втората половина на списъка се е превърнала в списък на няколко нива. 95 | *Нашата задача е да превърнем списъка в списък на едно ниво*. 96 | 97 | ![alt_text](https://i.ibb.co/7rbwp4r/Multilevel-list.png) 98 | 99 | ![alt_text](https://i.ibb.co/F3994Hh/One-level-list.png) 100 | -------------------------------------------------------------------------------- /Miscellaneous/Lists_tasks/Task1.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct Node 7 | { 8 | Node(const string& text) : text(text), next(nullptr){} 9 | string text; 10 | Node* next; 11 | }; 12 | void Print(Node* list) 13 | { 14 | Node* iter = list; 15 | do 16 | { 17 | cout << iter->text << endl; 18 | iter = iter->next; 19 | } while (iter != list); 20 | } 21 | bool shouldUnite(const string& lhs, const string& rhs) 22 | { 23 | if (lhs == "" || rhs == "") 24 | return false; 25 | return lhs[lhs.size() - 1] == rhs[0]; 26 | } 27 | void absorb(Node* first, Node* second) 28 | { 29 | first->text += "-" + second->text; 30 | first->next = second->next; 31 | delete second; 32 | } 33 | void Free(Node* list) 34 | { 35 | Node* iter = list; 36 | do 37 | { 38 | Node* toDelete = iter; 39 | iter = iter->next; 40 | delete toDelete; 41 | } while (iter != list); 42 | } 43 | void unite(Node* list) 44 | { 45 | Node* iter = list; 46 | 47 | Node* lexMin = list; 48 | 49 | bool shouldFinish = false; 50 | while (!shouldFinish) 51 | { 52 | if (strcmp(iter->text.c_str(), lexMin->text.c_str()) < 0) 53 | lexMin = iter; 54 | 55 | Node* next = iter->next; 56 | if (next == list) 57 | shouldFinish = true; 58 | if (iter != next && shouldUnite(iter->text, next->text)) 59 | absorb(iter, next); 60 | else 61 | iter = iter->next; 62 | 63 | } 64 | Print(lexMin); 65 | Free(lexMin); 66 | } 67 | 68 | 69 | // pass-street-taxi-inc -> dog -> smile-eat-tall -> 70 | int main() 71 | { 72 | 73 | //Node* f1 = new Node("street"); 74 | //Node* f2 = new Node("taxi"); 75 | //Node* f3 = new Node("inc"); 76 | //Node* f4 = new Node("dog"); 77 | //Node* f5 = new Node("smile"); 78 | //Node* f6 = new Node("eat"); 79 | //Node* f7 = new Node("tall"); 80 | //Node* f8 = new Node("pass"); 81 | 82 | //f1->next = f2; 83 | //f2->next = f3; 84 | //f3->next = f4; 85 | //f4->next = f5; 86 | //f5->next = f6; 87 | //f6->next = f7; 88 | //f7->next = f8; 89 | //f8->next = f1; 90 | 91 | Node* f1 = new Node("abc"); 92 | Node* f2 = new Node("cbd"); 93 | Node* f3 = new Node("dba"); 94 | f1->next = f2; 95 | f2->next = f3; 96 | f3->next = f1; 97 | 98 | unite(f1); 99 | } -------------------------------------------------------------------------------- /Miscellaneous/Lists_tasks/Task2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct SNode 7 | { 8 | SNode(int digit, SNode* next) : next(next), digit(digit){} 9 | 10 | SNode* next = nullptr; 11 | int digit; 12 | }; 13 | struct DNode 14 | { 15 | DNode(SNode* number) : number(number) {} 16 | 17 | SNode* number; 18 | 19 | DNode* next; 20 | DNode* prev; 21 | }; 22 | 23 | int eval(SNode* first) 24 | { 25 | SNode* iter = first; 26 | int result = 0; 27 | 28 | while (iter != nullptr) 29 | { 30 | (result *= 10) += iter->digit; 31 | iter = iter->next; 32 | } 33 | return result; 34 | } 35 | DNode* findMid(DNode* list) 36 | { 37 | DNode* slow = list; 38 | DNode* fast = list; 39 | 40 | while (fast != nullptr) 41 | { 42 | slow = slow->next; 43 | fast = fast->next->next; 44 | } 45 | return slow; 46 | } 47 | bool isIncreasingOrDecreasing(DNode* first, DNode* last, bool Increasing) 48 | { 49 | DNode* iter = first; 50 | 51 | while (iter != last && iter->next != nullptr) 52 | { 53 | DNode* next = iter->next; 54 | if (Increasing && eval(iter->number) >= eval(next->number)) 55 | return false; 56 | if (!Increasing && eval(iter->number) <= eval(next->number)) 57 | return false; 58 | iter = iter->next; 59 | 60 | } 61 | return true; 62 | } 63 | bool task(DNode* list) 64 | { 65 | DNode* mid = findMid(list); 66 | 67 | return isIncreasingOrDecreasing(list, mid->prev, true) 68 | && isIncreasingOrDecreasing(mid, nullptr, false); 69 | 70 | } 71 | void Free(SNode* list) 72 | { 73 | SNode* iter = list; 74 | while (iter != nullptr) 75 | { 76 | SNode* toDelete = iter; 77 | iter = iter->next; 78 | delete toDelete; 79 | } 80 | } 81 | void Free(DNode* list) 82 | { 83 | DNode* iter = list; 84 | while (iter != nullptr) 85 | { 86 | Free(iter->number); 87 | DNode* toDelete = iter; 88 | iter = iter->next; 89 | delete toDelete; 90 | } 91 | } 92 | // pass-street-taxi-inc -> dog -> smile-eat-tall -> 93 | int main() 94 | { 95 | SNode* l1 = new SNode(3, new SNode(4, new SNode(1, nullptr))); 96 | 97 | 98 | SNode* l2 = new SNode(5, new SNode(5, new SNode(1, new SNode(4,nullptr)))); 99 | SNode* l3 = new SNode(9, new SNode(9, new SNode(9, new SNode(9, nullptr)))); 100 | 101 | SNode* l4 = new SNode(9, new SNode(5, new SNode(2, new SNode(9, nullptr)))); 102 | SNode* l5 = new SNode(9, new SNode(9, new SNode(4, new SNode(4, nullptr)))); 103 | SNode* l6 = new SNode(3, new SNode(4,nullptr)); 104 | 105 | DNode* d1 = new DNode(l1); 106 | DNode* d2 = new DNode(l2); 107 | DNode* d3 = new DNode(l3);//s 108 | DNode* d4 = new DNode(l4); 109 | DNode* d5 = new DNode(l5);//f 110 | DNode* d6 = new DNode(l6); 111 | d1->prev = nullptr; 112 | d1->next = d2; 113 | d2->prev = d1; 114 | d2->next = d3; 115 | d3->prev = d2; 116 | d3->next = d4; 117 | d4->next = d5; 118 | d4->prev = d3; 119 | d5->next = d6; 120 | d5->prev = d4; 121 | d6->prev = d5; 122 | d6->next = nullptr; 123 | 124 | cout << task(d1); 125 | 126 | Free(d1); 127 | } -------------------------------------------------------------------------------- /Miscellaneous/Lists_tasks/Task3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct Node 6 | { 7 | Node(int value, Node* next) : value(value), next(next){} 8 | int value; 9 | Node* next; 10 | }; 11 | 12 | void print(Node* list) 13 | { 14 | Node* iter = list; 15 | while (iter != nullptr) 16 | { 17 | cout << iter->value <<" "; 18 | iter = iter->next; 19 | } 20 | } 21 | 22 | void freeList(Node* list) 23 | { 24 | Node* iter = list; 25 | while(iter) 26 | { 27 | Node* next = iter->next; 28 | delete iter; 29 | iter = next; 30 | } 31 | } 32 | 33 | Node* rearrange(Node* list) 34 | { 35 | Node* firstEven; 36 | Node* lastEven; 37 | 38 | Node* firstOdd; 39 | Node* lastOdd; 40 | 41 | firstEven = lastEven = firstOdd = lastOdd = nullptr; 42 | 43 | Node* iter = list; 44 | 45 | while (iter != nullptr) 46 | { 47 | if (iter->value % 2 == 0) 48 | { 49 | if (firstEven == nullptr) 50 | firstEven = lastEven = iter; 51 | else 52 | { 53 | lastEven->next = iter; 54 | lastEven = iter; 55 | } 56 | } 57 | else 58 | { 59 | if (firstOdd == nullptr) 60 | firstOdd = lastOdd = iter; 61 | else 62 | { 63 | lastOdd->next = iter; 64 | lastOdd = iter; 65 | } 66 | 67 | } 68 | iter = iter->next; 69 | } 70 | if (lastEven) 71 | lastEven->next = firstOdd; 72 | 73 | if (lastOdd) 74 | lastOdd->next = nullptr; 75 | 76 | return lastEven != nullptr ? firstEven : firstOdd; 77 | } 78 | 79 | int main() 80 | { 81 | Node* list = new Node(1, new Node(8, nullptr)); 82 | print(rearrange(list)); 83 | freeList(list); 84 | 85 | } 86 | -------------------------------------------------------------------------------- /Miscellaneous/Lists_tasks/Task4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | bool isQueueSorted(queue& q, int& lastEl) 8 | { 9 | if (q.empty()) 10 | return true; 11 | 12 | for (size_t i = 0; i < q.size(); i++) 13 | { 14 | int current = q.front(); 15 | q.pop(); 16 | 17 | if (i == q.size()) 18 | lastEl = current; 19 | 20 | if ((i != q.size()) && current > q.front()) 21 | return false; 22 | 23 | q.push(current); 24 | } 25 | 26 | return true; 27 | } 28 | bool isSortedSequence(list>& l) 29 | { 30 | int lastEl = INT_MIN; 31 | for (list>::iterator it = l.begin(); it != l.end(); ++it) 32 | { 33 | if (it != l.begin()) 34 | { 35 | if (!(*it).empty() && lastEl > (*it).front()) 36 | return false; 37 | } 38 | 39 | if (!isQueueSorted(*it, lastEl)) 40 | return false; 41 | } 42 | 43 | return true; 44 | } 45 | 46 | int main() 47 | { 48 | list> l; 49 | 50 | queue q1; 51 | q1.push(1); 52 | q1.push(2); 53 | q1.push(3); 54 | queue q2; 55 | q2.push(6); 56 | q2.push(9); 57 | q2.push(10); 58 | queue q3; 59 | q3.push(10); 60 | q3.push(22); 61 | q3.push(23); 62 | queue q4; 63 | 64 | l.push_back(q1); 65 | l.push_back(q2); 66 | l.push_back(q3); 67 | l.push_back(q4); 68 | 69 | cout << isSortedSequence(l); 70 | } 71 | -------------------------------------------------------------------------------- /Miscellaneous/Lists_tasks/Task5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | bool areQueuesOfSameSize(const queue& lhs, const queue& rhs) 8 | { 9 | return lhs.size() == rhs.size(); 10 | } 11 | void mergeQueues(queue& lhs, queue& rhs) 12 | { 13 | while (!rhs.empty()) 14 | { 15 | lhs.push(rhs.front()); 16 | rhs.pop(); 17 | } 18 | } 19 | void equalize(queue& lhs, queue& rhs) 20 | { 21 | bool isLhsBigger = lhs.size() > rhs.size() ? true : false; 22 | 23 | if (isLhsBigger) 24 | { 25 | while (lhs.size() > rhs.size() + 1) 26 | { 27 | rhs.push(lhs.front()); 28 | lhs.pop(); 29 | } 30 | } 31 | else 32 | { 33 | while (rhs.size() > lhs.size() + 1) 34 | { 35 | lhs.push(rhs.front()); 36 | rhs.pop(); 37 | } 38 | } 39 | } 40 | 41 | void modifyList(list>& l) 42 | { 43 | if (l.empty()) 44 | return; 45 | 46 | list>::iterator it = l.begin(); 47 | 48 | while (it != l.end()) 49 | { 50 | list>::iterator next = it; 51 | ++next; 52 | 53 | if (next == l.end()) 54 | break; 55 | 56 | if (areQueuesOfSameSize(*it, *next)) 57 | { 58 | mergeQueues(*it, *next); 59 | l.erase(next); 60 | continue; 61 | } 62 | else 63 | { 64 | ++it; 65 | 66 | if (++next == l.end()) 67 | break; 68 | 69 | if (!areQueuesOfSameSize(*it, *next)) 70 | { 71 | equalize(*it, *next); 72 | ++it; 73 | } 74 | } 75 | } 76 | } 77 | 78 | int main() 79 | { 80 | list> l; 81 | 82 | queue q1; 83 | q1.push(2); 84 | q1.push(4); 85 | q1.push(6); 86 | queue q2; 87 | q2.push(8); 88 | q2.push(0); 89 | q2.push(7); 90 | queue q3; 91 | q3.push(5); 92 | q3.push(7); 93 | q3.push(9); 94 | q3.push(23); 95 | q3.push(22); 96 | queue q4; 97 | q4.push(9); 98 | q4.push(1); 99 | queue q5; 100 | q5.push(2); 101 | queue q6; 102 | q6.push(1); 103 | queue q7; 104 | q7.push(33); 105 | q7.push(44); 106 | 107 | l.push_back(q1); 108 | l.push_back(q2); 109 | l.push_back(q3); 110 | l.push_back(q4); 111 | l.push_back(q5); 112 | l.push_back(q6); 113 | l.push_back(q7); 114 | 115 | modifyList(l); 116 | } 117 | -------------------------------------------------------------------------------- /Miscellaneous/Lists_tasks/Task6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | struct Node 7 | { 8 | string data; 9 | Node* next; 10 | 11 | Node(const string& data, Node* next = nullptr) : data(data), next(next) 12 | {} 13 | }; 14 | 15 | void free(Node* iter) 16 | { 17 | if (!iter) 18 | return; 19 | 20 | Node* first = iter; 21 | do 22 | { 23 | Node* toDelete = iter; 24 | iter = iter->next; 25 | delete toDelete; 26 | } while (iter != first); 27 | } 28 | void print(Node* iter) 29 | { 30 | if (!iter) 31 | return; 32 | 33 | Node* first = iter; 34 | do 35 | { 36 | cout << iter->data << endl; 37 | iter = iter->next; 38 | } while (iter != first); 39 | } 40 | 41 | bool shouldUnite(const string& lhs, const string& rhs) 42 | { 43 | if (lhs == "" || rhs == "") 44 | return false; 45 | 46 | return lhs[lhs.size() - 1] == rhs[0]; 47 | } 48 | void absorb(Node* lhs, Node* rhs) 49 | { 50 | lhs->data.append(" -> "); 51 | lhs->data.append(rhs->data); 52 | 53 | lhs->next = rhs->next; 54 | delete rhs; 55 | } 56 | 57 | void unite(Node* list) 58 | { 59 | Node* first = list; 60 | Node* lexMin = first; 61 | 62 | bool shouldFinish = false; 63 | 64 | do 65 | { 66 | if (list->next == first) 67 | shouldFinish = true; 68 | 69 | if (shouldUnite(list->data, list->next->data)) 70 | absorb(list, list->next); 71 | else 72 | { 73 | list = list->next; 74 | 75 | if (list->data < lexMin->data) 76 | lexMin = list; 77 | } 78 | } while (!shouldFinish); 79 | 80 | print(lexMin); 81 | free(lexMin); 82 | } 83 | 84 | int main() 85 | { 86 | Node* f1 = new Node("street"); 87 | Node* f2 = new Node("taxi"); 88 | Node* f3 = new Node("ink"); 89 | Node* f4 = new Node("dog"); 90 | Node* f5 = new Node("smile"); 91 | Node* f6 = new Node("eat"); 92 | Node* f7 = new Node("tall"); 93 | Node* f8 = new Node("pass"); 94 | 95 | f1->next = f2; 96 | f2->next = f3; 97 | f3->next = f4; 98 | f4->next = f5; 99 | f5->next = f6; 100 | f6->next = f7; 101 | f7->next = f8; 102 | f8->next = f1; 103 | 104 | unite(f6); 105 | } 106 | -------------------------------------------------------------------------------- /Miscellaneous/Lists_tasks/Task7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | template 5 | struct Node 6 | { 7 | T data; 8 | 9 | Node* prev; 10 | Node* next; 11 | Node* child; 12 | 13 | Node(const T& data) : data(data), prev(nullptr), next(nullptr), child(nullptr) 14 | {} 15 | }; 16 | 17 | template 18 | void free(Node* iter) 19 | { 20 | while (iter) 21 | { 22 | Node* toDelete = iter; 23 | iter = iter->next; 24 | delete toDelete; 25 | } 26 | } 27 | template 28 | void print(Node* iter) 29 | { 30 | while (iter) 31 | { 32 | cout << iter->data; 33 | if (iter->next) 34 | cout << "->"; 35 | iter = iter->next; 36 | } 37 | } 38 | 39 | template 40 | Node* getMiddle(Node* list) 41 | { 42 | Node* slowIter = list; 43 | Node* fastIter = list; 44 | 45 | while (fastIter) 46 | { 47 | slowIter = slowIter->next; 48 | fastIter = fastIter->next->next; 49 | } 50 | 51 | return slowIter; 52 | } 53 | 54 | template 55 | void flatten(Node* list) 56 | { 57 | Node* iter = getMiddle(list); 58 | 59 | while (iter) 60 | { 61 | if (iter->child) 62 | { 63 | Node* tempNext = iter->next; 64 | Node* tempChildIter = iter->child; 65 | 66 | iter->next = tempChildIter; 67 | tempChildIter->prev = iter; 68 | iter->child = nullptr; 69 | 70 | while (tempChildIter->next) 71 | tempChildIter = tempChildIter->next; 72 | 73 | if (tempNext) 74 | { 75 | tempChildIter->next = tempNext; 76 | tempNext->prev = tempChildIter; 77 | } 78 | } 79 | 80 | iter = iter->next; 81 | } 82 | 83 | print(list); 84 | free(list); 85 | } 86 | 87 | int main() 88 | { 89 | Node* n1 = new Node(1); 90 | Node* n2 = new Node(2); 91 | Node* n3 = new Node(3); 92 | Node* n4 = new Node(4); 93 | Node* n7 = new Node(7); 94 | Node* n8 = new Node(8); 95 | Node* n9 = new Node(9); 96 | Node* n10 = new Node(10); 97 | Node* n11 = new Node(11); 98 | Node* n12 = new Node(12); 99 | 100 | n1->next = n2; 101 | n2->prev = n1; 102 | n2->next = n3; 103 | n3->prev = n2; 104 | n3->next = n4; 105 | n4->prev = n3; 106 | 107 | n3->child = n7; 108 | n7->next = n8; 109 | n8->prev = n7; 110 | n8->next = n9; 111 | n9->prev = n8; 112 | n9->next = n10; 113 | n10->prev = n9; 114 | 115 | n8->child = n11; 116 | n11->next = n12; 117 | n12->prev = n11; 118 | 119 | flatten(n1); 120 | } 121 | -------------------------------------------------------------------------------- /Miscellaneous/README.md: -------------------------------------------------------------------------------- 1 | В тази папка са примерите направени в час. 2 | В подпапките са задачи за самоподготовка. 3 | -------------------------------------------------------------------------------- /Miscellaneous/Tree_tasks/Binary_tree/Binary_tree_tasks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | 8 | struct NodeFull 9 | { 10 | int value; 11 | vector children; 12 | }; 13 | 14 | struct Node 15 | { 16 | Node(int value) :value(value), left(nullptr), right(nullptr) 17 | {} 18 | int value; 19 | Node* left; 20 | Node* right; 21 | }; 22 | bool contains(Node* root, int elem) 23 | { 24 | if (root == nullptr) 25 | return false; 26 | return root->value == elem || contains(root->left, elem) || contains(root->right, elem); 27 | } 28 | int sum(Node* root) 29 | { 30 | if (root == nullptr) 31 | return 0; 32 | return root->value + sum(root->left) + sum(root->right); 33 | } 34 | int max(int a, int b) 35 | { 36 | return a > b ? a : b; 37 | } 38 | int max(int a, int b, int c) 39 | { 40 | return max(max(a, b), c); 41 | } 42 | int maxElementInTree(Node* root) 43 | { 44 | if (root->left == nullptr && root->right == nullptr) 45 | return root->value; 46 | else if (root->left == nullptr && root->right != nullptr) 47 | return max(root->value, maxElementInTree(root->right)); 48 | else if (root->left != nullptr && root->right == nullptr) 49 | return max(root->value, maxElementInTree(root->left)); 50 | 51 | return max(root->value, maxElementInTree(root->left), maxElementInTree(root->right)); 52 | } 53 | int heght(Node* root) 54 | { 55 | if (root == nullptr) 56 | return -1; 57 | return 1 + max(heght(root->left), heght(root->right)); 58 | } 59 | 60 | int countElements(Node* root) 61 | { 62 | if (root == nullptr) 63 | return 0; 64 | return 1 + countElements(root->left) + countElements(root->right); 65 | } 66 | bool markOccurrencesHelper(Node* root, vector& temp) 67 | { 68 | if (root == nullptr) 69 | return true; 70 | if (root->value < 1 || root->value > temp.size()) 71 | return false; 72 | if (temp[root->value - 1]) // ïðîâåðÿâàìå çà ïîâòîðåíèå 73 | return false; 74 | temp[root->value - 1] = true; 75 | return markOccurrencesHelper(root->left, temp) && markOccurrencesHelper(root->right, temp); 76 | } 77 | 78 | 79 | void fillWords(Node* root, vector& words, string currentWord) 80 | { 81 | if (root == nullptr) 82 | return; 83 | if (root->left == nullptr && root->right == nullptr) 84 | words.push_back(currentWord + (char)root->value); 85 | fillWords(root->left, words, currentWord + (char)root->value); 86 | fillWords(root->right, words, currentWord + (char)root->value); 87 | } 88 | vector getWords(Node* root) 89 | { 90 | vector result; 91 | fillWords(root, result, ""); 92 | return result; 93 | } 94 | 95 | bool isPermutation(Node* root ) 96 | { 97 | vector temp(countElements(root)); // F F F F F F F F... F 98 | 99 | return markOccurrencesHelper(root,temp); 100 | } 101 | 102 | string getStringOnLevel(Node* root, int level) 103 | { 104 | if (root == nullptr) 105 | return ""; 106 | if (level == 0) 107 | { 108 | string res; 109 | res += (char)root->value; 110 | return res; 111 | } 112 | return getStringOnLevel(root->left, level - 1) + getStringOnLevel(root->right, level - 1); 113 | } 114 | void Free(Node* root) 115 | { 116 | if(root == nullptr) 117 | return; 118 | Free(root->left); 119 | Free(root->right); 120 | delete root; 121 | } 122 | int main() 123 | { 124 | // Àêî íÿêúäå èìàìå ÷èñëî, êîåòî íå å [1..n] 125 | Node* root = new Node('A'); 126 | Node* n1 = new Node('B'); 127 | Node* n2 = new Node('C'); 128 | Node* n3 = new Node('D'); 129 | Node* n4 = new Node('E'); 130 | Node* n5 = new Node('F'); 131 | root->left = n1; 132 | root->right = n2; 133 | n1->left = n3; 134 | n2->left = n4; 135 | n2->right = n5; 136 | 137 | //cout << isPermutation(root); 138 | cout << getStringOnLevel(root, 1); 139 | Free(root); 140 | return 0; 141 | } 142 | 143 | -------------------------------------------------------------------------------- /Miscellaneous/Tree_tasks/General_tree/general_tree_tasks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | template 9 | struct NodeFull 10 | { 11 | T data; 12 | vector*> children; 13 | 14 | NodeFull(T data) : data(data) {} 15 | }; 16 | template 17 | void print(NodeFull* root) 18 | { 19 | cout << root->data << " "; 20 | 21 | for (int i = 0; i < root->children.size(); i++) 22 | print(root->children[i]); 23 | } 24 | template 25 | void free(NodeFull* root) 26 | { 27 | for (int i = 0; i < root->children.size(); i++) 28 | free(root->children[i]); 29 | 30 | delete root; 31 | } 32 | 33 | 34 | // Задача 1: Да се напише функция, която приема произволно дърво и връща дали дадено число се съдържа в него. 35 | template 36 | bool contains(NodeFull* root, T element) 37 | { 38 | int size = root->children.size(); 39 | 40 | if (root->data == element) 41 | return true; 42 | 43 | for (int i = 0; i < size; i++) 44 | { 45 | if (contains(root->children[i], element)) 46 | return true; 47 | } 48 | return false; 49 | } 50 | 51 | // Задача 2: Да се напише функция, която приема произволно дърво и връща сумата на елементите в него. 52 | template 53 | int sum(NodeFull* root) 54 | { 55 | int sum = root->data; 56 | 57 | for (int i = 0; i < root->children.size(); i++) 58 | sum += sum(root->children[i]); 59 | return sum; 60 | } 61 | 62 | // Задача 3: Да се напише функция, която приема произволно дърво и връща най-големият елемент в него. 63 | template 64 | T maxT(NodeFull* root) 65 | { 66 | T maxEl = root->data; 67 | 68 | for (int i = 0; i < root->children.size(); i++) 69 | maxEl = max(maxEl, maxT(root->children[i])); 70 | return maxEl; 71 | } 72 | 73 | // Задача 4: Да се напише функция, която приема произволно дърво и връща височината му. 74 | template 75 | int height(NodeFull* root) 76 | { 77 | int maxHeight = -1; 78 | 79 | for (int i = 0; i < root->children.size(); i++) 80 | { 81 | int currHeight = height(root->children[i]); 82 | if (currHeight > maxHeight) 83 | maxHeight = currHeight; 84 | } 85 | return maxHeight + 1; 86 | } 87 | 88 | // Задача 5: Да се напише функция, която приема произволно дърво и връща броя на елементите му. 89 | template 90 | int getNumOfElements(NodeFull* root) 91 | { 92 | int numOfElements = 1; 93 | 94 | for (int i = 0; i < root->children.size(); i++) 95 | numOfElements += getNumOfElements(root->children[i]); 96 | return numOfElements; 97 | } 98 | 99 | // Задача 6: Да се напише функция, която приема произволно дърво с n върха и проверява дали 100 | // числата от 1 до n се срещат точно веднъж в дървото. 101 | bool markOccurances(NodeFull* root, vector& nums, int n) 102 | { 103 | if (root->data < 1 || root->data > n) 104 | return false; 105 | if (nums[root->data - 1]) 106 | return false; 107 | 108 | nums[root->data - 1] = true; 109 | for (int i = 0; i < root->children.size(); i++) 110 | { 111 | if (!markOccurances(root->children[i], nums, n)) 112 | return false; 113 | } 114 | return true; 115 | } 116 | bool isPermutation(NodeFull* root) 117 | { 118 | int size = getNumOfElements(root); 119 | vector nums(size); 120 | 121 | return markOccurances(root, nums, size); 122 | } 123 | 124 | // Задача 7: Да се напише функция, която приема произволно дърво, чиито елементи са символи и цяло число к 125 | // и отпечатва думата на к - тото ниво на дървото. 126 | string word(NodeFull* root, int k) 127 | { 128 | string wordOnLevel; 129 | 130 | if (root == nullptr) 131 | return ""; 132 | if (k == 1) 133 | return wordOnLevel + (char)root->data; 134 | 135 | for (int i = 0; i < root->children.size(); i++) 136 | wordOnLevel += word(root->children[i], k - 1); 137 | return wordOnLevel; 138 | } 139 | 140 | // Задача 8: Да се напише функция, която приема произволно дърво и връща всички думи, които са получени от корена до някое листо. 141 | void fillWords(NodeFull* root, vector& v, string currentWord) 142 | { 143 | currentWord += root->data; 144 | if (root->children.size() == 0) 145 | { 146 | v.push_back(currentWord); 147 | return; 148 | } 149 | 150 | for (int i = 0; i < root->children.size(); i++) 151 | fillWords(root->children[i], v, currentWord); 152 | } 153 | 154 | // Задача 9: Да се напише функция, която приема произволно дърво и връща сумата на листата. 155 | template 156 | T sumOfLeaves(NodeFull* root) 157 | { 158 | int sum = 0; 159 | if (root->children.size() == 0) 160 | return root->data; 161 | 162 | for (int i = 0; i < root->children.size(); i++) 163 | sum += sumOfLeaves(root->children[i]); 164 | return sum; 165 | } 166 | 167 | // Задача 10: Напишете фунцкия, която намира максималната разклоненост(брой деца) на дърво. 168 | template 169 | int getNumOfLeaves(NodeFull* root) 170 | { 171 | int numOfLeaves = 0; 172 | if (root->children.empty()) 173 | numOfLeaves++; 174 | 175 | for (int i = 0; i < root->children.size(); i++) 176 | numOfLeaves += getNumOfLeaves(root->children[i]); 177 | 178 | return numOfLeaves; 179 | } 180 | template 181 | int maxBranching(NodeFull* root) 182 | { 183 | int maxBranching = 1; 184 | int tempBranching = 0; 185 | 186 | for (int i = 0; i < root->children.size(); i++) 187 | tempBranching = getNumOfLeaves(root->children[i]); 188 | 189 | if (tempBranching > maxBranching) 190 | maxBranching = tempBranching; 191 | 192 | return maxBranching; 193 | } 194 | 195 | 196 | int main() 197 | { 198 | NodeFull* root = new NodeFull(1); 199 | 200 | (root->children).push_back(new NodeFull(2)); 201 | (root->children).push_back(new NodeFull(3)); 202 | (root->children).push_back(new NodeFull(4)); 203 | (root->children[0]->children).push_back(new NodeFull(5)); 204 | (root->children[1]->children).push_back(new NodeFull(6)); 205 | (root->children[1]->children[0]->children).push_back(new NodeFull(7)); 206 | (root->children[2]->children).push_back(new NodeFull(8)); 207 | (root->children[2]->children).push_back(new NodeFull(10)); 208 | } 209 | -------------------------------------------------------------------------------- /Miscellaneous/Tree_tasks/README.md: -------------------------------------------------------------------------------- 1 | ***Задача 1:*** Да се напише функция, която приема двоично/произволно дърво и връща дали дадено число се съдържа в него. 2 | 3 | ***Задача 2:*** Да се напише функция, която приема двоично/произволно дърво и връща сумата на елементите в него. 4 | 5 | ***Задача 3:*** Да се напише функция, която приема двоично/произволно дърво и връща най-големият елемент в него. 6 | 7 | ***Задача 4:*** Да се напише функция, която приема двоично/произволно дърво и връща височината му. 8 | 9 | ***Задача 5:*** Да се напише функция, която приема двоично/произволно дърво и връща броя на елементите му. 10 | 11 | ***Задача 6:*** Да се напише функция, която приема двоично/произволно дърво с n върха и проверява дали числата от 1 до n се срещат точно веднъж в дървото. 12 | 13 | ***Задача 7:*** Да се напише функция, която приема двоично/произволно дърво и връща всички думи, които са получени от корена до някое листо. 14 | 15 | ***Задача 8:*** Да се напише функция, която приема двоично/произволно дърво, чиито елементи са символи и цяло число к и отпечатва думата на к-тото ниво на дървото. 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Miscellaneous/checkValidBracketsString.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool isOpeningBracket(char ch) 6 | { 7 | return ch == '(' || ch == '[' || ch == '{'; 8 | } 9 | 10 | bool isMatchingBracket(char ch1, char ch2) 11 | { 12 | switch (ch1) 13 | { 14 | case '(': 15 | return ch2 == ')'; 16 | case '[': 17 | return ch2 == ']'; 18 | case '{': 19 | return ch2 == '}'; 20 | } 21 | 22 | return false; 23 | } 24 | 25 | bool isCorrect(const std::string& str) 26 | { 27 | std::stack brackets; 28 | 29 | for (char ch : str) 30 | { 31 | if (isOpeningBracket(ch)) 32 | { 33 | brackets.push(ch); 34 | } 35 | else 36 | { 37 | if (brackets.empty() || !isMatchingBracket(brackets.top(), ch)) 38 | { 39 | return false; 40 | } 41 | else 42 | { 43 | brackets.pop(); 44 | } 45 | } 46 | } 47 | return brackets.empty(); 48 | } 49 | 50 | int main() 51 | { 52 | std::cout << isCorrect("()"); 53 | } -------------------------------------------------------------------------------- /Miscellaneous/generateBoolVectors - amorthized analysis.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void print(const std::vector& v) 5 | { 6 | std::cout << "["; 7 | for (auto it = v.begin(); it != v.end(); it++) 8 | { 9 | std::cout << (*it) << " "; 10 | } 11 | std::cout << "]" << std::endl; 12 | } 13 | 14 | void next(std::vector& v) 15 | { 16 | int ind = v.size() - 1; 17 | while (ind >= 0 && v[ind] == 1) 18 | v[ind--] = 0; 19 | if (ind >= 0) 20 | v[ind] = 1; 21 | } 22 | 23 | void nextWithIterators(std::vector& v) //just for exercise 24 | { 25 | auto it = v.rbegin(); //reverse iterator 26 | 27 | while (it != v.rend() && *it == 1) 28 | *it++ = 0; 29 | 30 | if (it != v.rend()) 31 | *it = 1; 32 | } 33 | 34 | void generateBoolVectors(int n) 35 | { 36 | std::vector v(n, 0); 37 | unsigned count = 1 << n; 38 | 39 | for (unsigned i = 0; i < count; i++) 40 | { 41 | print(v); 42 | nextWithIterators(v); 43 | } 44 | } 45 | 46 | int main() 47 | { 48 | generateBoolVectors(3); 49 | } 50 | -------------------------------------------------------------------------------- /Miscellaneous/parentArrayTreeHeight.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | 6 | std::vector getNextLevel(const std::vector& currLevel, const std::vector& parentArray) 7 | { 8 | std::vector nextLevel; 9 | 10 | for (int i = 0; i < parentArray.size(); i++) 11 | { 12 | int currVertexParent = parentArray[i]; 13 | auto it = std::find(currLevel.begin(), currLevel.end(), currVertexParent); 14 | if (it != currLevel.end()) 15 | nextLevel.push_back(i); 16 | } 17 | return nextLevel; 18 | } 19 | 20 | int getHeight(const std::vector& parentArray) 21 | { 22 | std::vector currentLevel = { -1 }; 23 | int level = -1; 24 | while (!currentLevel.empty()) 25 | { 26 | level++; 27 | currentLevel = getNextLevel(currentLevel, parentArray); 28 | } 29 | return level; 30 | } 31 | 32 | int main() 33 | { 34 | std::vector v= { -1,0, 1, 2 }; 35 | cout << getHeight(v); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Miscellaneous/removeNodesSinglyLinkedList.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node 5 | { 6 | Node* next; 7 | int data; 8 | }; 9 | 10 | template 11 | Node* removeNodes(Node* head, Predicate predicate) 12 | { 13 | Node** current = &head; 14 | while (*current != nullptr) 15 | { 16 | if (predicate((*current)->data)) 17 | { 18 | Node* temp = *current; 19 | *current = (*current)->next; 20 | delete temp; 21 | } 22 | else 23 | { 24 | current = &(*current)->next; 25 | } 26 | } 27 | return head; 28 | } 29 | 30 | void printList(Node* head) 31 | { 32 | Node* current = head; 33 | while (current != nullptr) 34 | { 35 | std::cout << current->data << " "; 36 | current = current->next; 37 | } 38 | std::cout << std::endl; 39 | } 40 | 41 | void freeList(Node* list) 42 | { 43 | Node* curr = list; 44 | 45 | while(curr) 46 | { 47 | Node* toDelete = curr; 48 | curr = curr->next; 49 | delete toDelete; 50 | } 51 | } 52 | 53 | int main() 54 | { 55 | // Create a sample list: 1 -> 2 -> 3 -> 4 -> 5 56 | Node* head = new Node{nullptr, 1}; 57 | head->next = new Node{nullptr, 2}; 58 | head->next->next = new Node{nullptr, 3}; 59 | head->next->next->next = new Node{nullptr, 4}; 60 | head->next->next->next->next = new Node{nullptr, 5}; 61 | 62 | std::cout << "Original list: "; 63 | printList(head); 64 | 65 | head = removeNodes(head, [](int data) { return data % 2 == 0; }); 66 | 67 | std::cout << "List after removing even values: "; 68 | printList(head); 69 | 70 | head = removeNodes(head, [](int) { return true; }); 71 | 72 | freeList(head); 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /Miscellaneous/singlyLinkedList-partition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Node 4 | { 5 | int data; 6 | Node* next = nullptr; 7 | Node(int value, Node* ptr = nullptr) : data(value), next(ptr) {} 8 | }; 9 | 10 | 11 | void push_back(Node*& begin, Node*& end, Node* toAdd) 12 | { 13 | if (begin == nullptr) 14 | { 15 | begin = end = toAdd; 16 | } 17 | else 18 | { 19 | end->next = toAdd; 20 | end = toAdd; 21 | ///toAdd->next = nullptr !!! NO! You need this pointer in the next iteration of the partition func 22 | } 23 | } 24 | 25 | template 26 | Node* partition(Node* list, const PredicateType& pred) 27 | { 28 | Node* trueListBegin = nullptr; 29 | Node* trueListEnd = nullptr; 30 | 31 | Node* falseListBegin = nullptr; 32 | Node* falseListEnd = nullptr; 33 | 34 | while (list != nullptr) 35 | { 36 | if (pred(list->data)) 37 | push_back(trueListBegin, trueListEnd, list); 38 | else 39 | push_back(falseListBegin, falseListEnd, list); 40 | list = list->next; 41 | } 42 | if (trueListEnd) 43 | { 44 | trueListEnd->next = falseListBegin; 45 | } 46 | if(falseListEnd) 47 | falseListEnd->next = nullptr; 48 | 49 | 50 | return trueListBegin != nullptr ? trueListBegin : falseListBegin; 51 | } 52 | 53 | void printList(Node* iter) 54 | { 55 | while (iter != nullptr) 56 | { 57 | 58 | std::cout << iter->data; 59 | if(iter->next) 60 | std::cout << " -> "; 61 | iter = iter->next; 62 | } 63 | } 64 | void freeList(Node* iter) 65 | { 66 | while (iter != nullptr) 67 | { 68 | Node* toDelete = iter; 69 | iter = iter->next; 70 | delete toDelete; 71 | } 72 | } 73 | 74 | int main() 75 | { 76 | Node* list = new Node{ 3, new Node{4, new Node{5, new Node{6}}} }; 77 | Node* newBegin = partition(list, [](int x) {return x % 2 == 0; }); 78 | printList(newBegin); 79 | freeList(newBegin); 80 | } 81 | 82 | -------------------------------------------------------------------------------- /Miscellaneous/singlyLinkedList_mergeSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct Node 5 | { 6 | int data = 0; 7 | Node* next = nullptr; 8 | 9 | Node(int data, Node* next = nullptr) : data(data), next(next){} 10 | }; 11 | 12 | void print(const Node* root) 13 | { 14 | while(root) 15 | { 16 | std::cout << root->data << " "; 17 | root = root->next; 18 | } 19 | std::cout << std::endl; 20 | } 21 | 22 | void freeList(Node* root) 23 | { 24 | Node* current = root; 25 | while(current) 26 | { 27 | Node* next = current->next; 28 | delete current; 29 | current = next; 30 | } 31 | } 32 | 33 | void pushBack(Node*& resultBegin, Node*& resultEnd, Node* toAdd) 34 | { 35 | if (!resultBegin) 36 | { 37 | resultBegin = resultEnd = toAdd; 38 | } 39 | else 40 | { 41 | resultEnd->next = toAdd; 42 | resultEnd = toAdd; 43 | } 44 | } 45 | 46 | Node* mergeLists(Node* first, Node* second) 47 | { 48 | Node* resultBegin = nullptr, *resultEnd = nullptr; 49 | 50 | while (first && second) 51 | { 52 | if (first->data < second->data) 53 | { 54 | pushBack(resultBegin, resultEnd, first); 55 | first = first->next; 56 | } 57 | else 58 | { 59 | pushBack(resultBegin, resultEnd, second); 60 | second = second->next; 61 | } 62 | } 63 | if (!first) 64 | { 65 | pushBack(resultBegin, resultEnd, second); 66 | } 67 | else 68 | { 69 | pushBack(resultBegin, resultEnd, first); 70 | } 71 | return resultBegin; 72 | } 73 | 74 | 75 | Node* getMid(Node* list) 76 | { 77 | Node* slow = list; 78 | Node* fast = list ->next; 79 | 80 | while(fast && fast->next) 81 | { 82 | slow = slow->next; 83 | fast = fast->next->next; 84 | } 85 | return slow; 86 | } 87 | 88 | Node* mergeSort(Node* list) 89 | { 90 | 91 | if(!list || !list->next) 92 | return list; 93 | 94 | Node* mid = getMid(list); 95 | 96 | 97 | Node* left = list; 98 | Node* right = mid->next; 99 | mid->next = nullptr; 100 | 101 | left = mergeSort(left); 102 | right = mergeSort(right); 103 | 104 | return mergeLists(left, right); 105 | } 106 | 107 | 108 | int main() 109 | { 110 | Node* list = new Node(20, new Node(14, new Node(7))); 111 | list = mergeSort(list); 112 | print(list); 113 | freeList(list); 114 | list = nullptr; 115 | } 116 | -------------------------------------------------------------------------------- /Miscellaneous/singlyLinkedList_quickSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Node 4 | { 5 | int data; 6 | Node* next = nullptr; 7 | Node(int value, Node* ptr = nullptr) : data(value), next(ptr) {} 8 | }; 9 | 10 | void push_back(Node*& begin, Node*& end, Node* toAdd) 11 | { 12 | if (begin == nullptr) 13 | { 14 | begin = end = toAdd; 15 | } 16 | else 17 | { 18 | end->next = toAdd; 19 | end = toAdd; 20 | ///toAdd->next = nullptr !!! NO! You need this pointer in the next iteration of the partition func 21 | } 22 | } 23 | 24 | template 25 | std::pair partition(Node* list, const PredicateType& pred) 26 | { 27 | Node* trueListBegin = nullptr; 28 | Node* trueListEnd = nullptr; 29 | 30 | Node* falseListBegin = nullptr; 31 | Node* falseListEnd = nullptr; 32 | 33 | while (list != nullptr) 34 | { 35 | if (pred(list->data)) 36 | push_back(trueListBegin, trueListEnd, list); 37 | else 38 | push_back(falseListBegin, falseListEnd, list); 39 | list = list->next; 40 | } 41 | if (trueListEnd) 42 | { 43 | trueListEnd->next = nullptr; 44 | } 45 | if (falseListEnd) 46 | { 47 | falseListEnd->next = nullptr; 48 | } 49 | 50 | return std::make_pair(trueListBegin, falseListBegin); 51 | } 52 | 53 | // 54 | std::pair concatLists(Node* leftBegin, Node* leftEnd, Node* rightBegin, Node* rightEnd) 55 | { 56 | if (leftBegin == nullptr) return std::make_pair(rightBegin, rightEnd); 57 | if (rightBegin == nullptr) return std::make_pair(leftBegin, leftEnd); 58 | 59 | leftEnd->next = rightBegin; 60 | return std::make_pair(leftBegin, rightEnd); 61 | } 62 | 63 | 64 | std::pair quickSort(Node* list) 65 | { 66 | if (!list || !list->next) 67 | return std::make_pair(list, list); 68 | 69 | int pivot = list->data; 70 | auto partitionResults = partition(list, [pivot](int el) {return el < pivot; }); 71 | 72 | Node* pivotPtr = partitionResults.second; 73 | 74 | auto leftToConcat = quickSort(partitionResults.first); 75 | auto rightToConcat = quickSort(partitionResults.second->next); //skip the pivot 76 | 77 | pivotPtr->next = rightToConcat.first; //attach the pivot to the begin of right 78 | rightToConcat.first = pivotPtr; 79 | if (!rightToConcat.second) //the right was empty list, we should concat only the pivot 80 | rightToConcat.second = pivotPtr; 81 | 82 | return concatLists(leftToConcat.first, 83 | leftToConcat.second, 84 | rightToConcat.first, 85 | rightToConcat.second); 86 | } 87 | 88 | void printList(Node* iter) 89 | { 90 | while (iter != nullptr) 91 | { 92 | std::cout << iter->data; 93 | if (iter->next) 94 | std::cout << " -> "; 95 | iter = iter->next; 96 | } 97 | } 98 | void freeList(Node* iter) 99 | { 100 | while (iter != nullptr) 101 | { 102 | Node* toDelete = iter; 103 | iter = iter->next; 104 | delete toDelete; 105 | } 106 | } 107 | 108 | int main() 109 | { 110 | Node* list = new Node{ 31, new Node{4, new Node{53, new Node{2}}} }; 111 | 112 | auto res = quickSort(list); 113 | list = res.first; 114 | printList(list); 115 | freeList(list); 116 | } 117 | -------------------------------------------------------------------------------- /Miscellaneous/tree_print_by_levels_BFS.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node 5 | { 6 | char data; 7 | std::vector children; 8 | }; 9 | 10 | void printByLevels(const Node* root) //BFS! 11 | { 12 | std::vector currLevel = { root }; 13 | 14 | while (!currLevel.empty()) 15 | { 16 | std::vector nextLevel; 17 | for (const Node* curr : currLevel) 18 | { 19 | std::cout << curr->data << " "; 20 | for (const Node* child : curr->children) 21 | nextLevel.push_back(child); 22 | } 23 | std::cout << std::endl; 24 | currLevel.swap(nextLevel); 25 | } 26 | } 27 | void free(Node* root) 28 | { 29 | for (Node* child : root->children) 30 | free(child); 31 | delete root; 32 | } 33 | 34 | int main() 35 | { 36 | Node* root = new Node{ 'a' }; 37 | 38 | root->children.push_back(new Node{'b'}); 39 | root->children.push_back(new Node{ 'c' }); 40 | root->children.push_back(new Node{ 'd' }); 41 | root->children.at(0)->children.push_back(new Node{ 'x' }); 42 | root->children.at(0)->children.push_back(new Node{ 'y' }); 43 | 44 | printByLevels(root); 45 | free(root); 46 | } 47 | 48 | -------------------------------------------------------------------------------- /Miscellaneous/tree_print_root_to_leaf_DFS.CPP: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node 5 | { 6 | char data; 7 | std::vector children; 8 | }; 9 | 10 | void printRootToLeafPaths(const Node* root, std::string& str) //DFS / str could be hidden in wrapper func 11 | { 12 | str.push_back(root->data); 13 | if (root->children.empty()) 14 | std::cout << str << std::endl; 15 | else 16 | { 17 | for (const Node* ch : root->children) 18 | printRootToLeafPaths(ch, str); 19 | } 20 | str.pop_back(); 21 | } 22 | void free(Node* root) 23 | { 24 | for (Node* child : root->children) 25 | free(child); 26 | delete root; 27 | } 28 | 29 | int main() 30 | { 31 | Node* root = new Node{ 'a' }; 32 | 33 | root->children.push_back(new Node{'b'}); 34 | root->children.push_back(new Node{ 'c' }); 35 | root->children.push_back(new Node{ 'd' }); 36 | root->children.at(0)->children.push_back(new Node{ 'x' }); 37 | root->children.at(0)->children.push_back(new Node{ 'y' }); 38 | 39 | std::string str; 40 | printRootToLeafPaths(root, str); 41 | free(root); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /PriorityQueue/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "priorityQueue.hpp" 3 | 4 | int main() 5 | { 6 | PriorityQueue pq; 7 | 8 | pq.insert(3); 9 | pq.insert(10); 10 | pq.insert(0); 11 | 12 | std::cout << pq.peek(); 13 | } 14 | -------------------------------------------------------------------------------- /PriorityQueue/priorityQueue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | template 6 | class PriorityQueue 7 | { 8 | static size_t leftChild(size_t i); 9 | static size_t rightChild(size_t i); 10 | static int parent(int i); 11 | 12 | void heapify(size_t ind); 13 | std::vector data; 14 | 15 | public: 16 | PriorityQueue() = default; 17 | PriorityQueue(const std::vector& v); 18 | 19 | bool isEmpty() const; 20 | const T& peek() const; 21 | void pop(); // Премахва най-големия елемент (може и да го върнем). 22 | void insert(const T& el); 23 | size_t size() const; 24 | }; 25 | 26 | template 27 | size_t PriorityQueue::leftChild(size_t i) 28 | { 29 | return 2 * i + 1; 30 | } 31 | 32 | template 33 | size_t PriorityQueue::rightChild(size_t i) 34 | { 35 | return 2 * i + 2; 36 | } 37 | 38 | template 39 | int PriorityQueue::parent(int i) 40 | { 41 | return (i - 1) / 2; 42 | } 43 | 44 | template 45 | bool PriorityQueue::isEmpty() const 46 | { 47 | return data.empty(); 48 | } 49 | 50 | template 51 | void PriorityQueue::pop() 52 | { 53 | if (isEmpty()) 54 | throw std::runtime_error("Empty queue!"); 55 | 56 | data[0] = data[data.size() - 1]; // Новият корен става последен елемент. 57 | data.pop_back(); 58 | 59 | if (data.size() != 0) 60 | heapify(0); // Коренът започва да се "спуска" надолу, за да се запази пирамидалното свойство. 61 | } 62 | 63 | template 64 | const T& PriorityQueue::peek() const 65 | { 66 | if (isEmpty()) 67 | throw std::runtime_error("Empty queue!"); 68 | return data[0]; 69 | } 70 | 71 | // Функция, която "спуска елемент". Елементът ако има ляво поддърво, което е пирамида и дясно поддърво, което е пирамида, образува нова пирамида, обединявайки двете + корена. 72 | template 73 | void PriorityQueue::heapify(size_t ind) 74 | { 75 | int currentElementIndex = ind; 76 | while (true) 77 | { 78 | int leftChildIndex = leftChild(currentElementIndex); 79 | int rightChildIndex = rightChild(currentElementIndex); 80 | 81 | // Проверяваме дали има ляв/десен наследник и дали той е по-голям от текущия елемент. 82 | bool shouldGoLeft = leftChildIndex < data.size() && data[leftChildIndex] > data[currentElementIndex]; 83 | bool shouldGoRight = rightChildIndex < data.size() && data[rightChildIndex] > data[currentElementIndex]; 84 | 85 | if (shouldGoLeft && shouldGoRight) 86 | { 87 | // Ако и двата наследника са по-големи, се "спускаме" към по големия. 88 | if (data[leftChildIndex] > data[rightChildIndex]) 89 | { 90 | std::swap(data[currentElementIndex], data[leftChildIndex]); 91 | currentElementIndex = leftChildIndex; 92 | } 93 | else 94 | { 95 | std::swap(data[currentElementIndex], data[rightChildIndex]); 96 | currentElementIndex = rightChildIndex; 97 | } 98 | } 99 | else if (shouldGoLeft) 100 | { 101 | std::swap(data[currentElementIndex], data[leftChildIndex]); 102 | currentElementIndex = leftChildIndex; 103 | } 104 | else if (shouldGoRight) 105 | { 106 | std::swap(data[currentElementIndex], data[rightChildIndex]); 107 | currentElementIndex = rightChildIndex; 108 | } 109 | else 110 | break; 111 | } 112 | } 113 | 114 | template 115 | void PriorityQueue::insert(const T& el) 116 | { 117 | data.push_back(el); 118 | int ind = data.size() - 1; 119 | int parentIndex = parent(ind); 120 | 121 | // Елементът е поставен на дъното на пирамидата и той се опитва да "изплува" нагоре, докато родителят е по-малък от него. 122 | while (ind > 0 && data[ind] > data[parentIndex]) 123 | { 124 | std::swap(data[ind], data[parentIndex]); 125 | ind = parentIndex; 126 | parentIndex = parent(ind); 127 | } 128 | } 129 | 130 | template 131 | PriorityQueue::PriorityQueue(const std::vector& v) // O(n) 132 | { 133 | data = v; 134 | 135 | for (int i = v.size() / 2 - 1; i >= 0; i--) 136 | heapify(i); 137 | } 138 | 139 | template 140 | size_t PriorityQueue::size() const 141 | { 142 | return data.size(); 143 | } 144 | 145 | -------------------------------------------------------------------------------- /PriorityQueue/readme.md: -------------------------------------------------------------------------------- 1 | d 2 | **Приоритетна опашка**, трябва най-малко да поддържа следните операции: 3 | 4 | - добавяне с приоритет – добавя елемент на опашката със съответен приоритет. 5 | - изваждане на елемента с най-висок приоритет. 6 | 7 | Ако в приоритетната опашка имаме елементи с еднакъв приоритет, то те трябва да се подчиняват на **FIFO** (first in, first out). 8 | 9 | Реализация с **двоична пирамида** **(Binary heap)**. 10 | 11 | ![enter image description here](https://i.ibb.co/yf7TVSY/1200px-Max-Heap-svg.png) 12 | 13 | 14 | По дефинирация двоичната пирамида **не прави разлика между елементи с еднакъв приоритет**. За това в пирамидата **ще пазим наредени двойки < елемент, момент на добавяне >**, за да може да поддържаме FIFO за повтарящите се елементи. 15 | 16 | Забележка: В примерите е реализирана макс. двоична пирамида - max binary heap. (Съществува и min binary heap) 17 | 18 | 19 | 20 | **Задача 1:** Да се реализира строене на двоична пирамида от произволен масив със сложност **О(n)**. 21 | Използвайте функцията **heapify**. 22 | 23 | ![enter image description here](https://i.ibb.co/K9DsZTg/Untitled-Diagram.png) 24 | 25 | **Задача 2:** Да се реализира сортиращия алгоритъм **HeapSort**. 26 | 27 | ## Задача за упражнение. 28 | 29 | **Задача 1:** 30 | Реализирайте приоритетна опашка с троична-минимална пирамида **(Ternary heap)**. 31 | В нашата опашка искаме да изваждаме първо елементите с най-нисък приоритет (най-малките числа). 32 | Троична-минимална пирамида е **пълно троично дърво.** 33 | 34 | - Всеки връх има най-много 3 наследника. 35 | - Всеки връх е по-малък или равен от наследниците си. 36 | - Всяко ниво е пълно, с изключение на последното, което е запълнено от ляво надясно. 37 | 38 | Реализирайте сортиращ алгоритъм **ternaryHeapSort**, който сортира произволен масив, използвайки вече реализираната приоритетна опашка. 39 | 40 | ![enter image description here](https://i.ibb.co/VCCHF5S/Untitled-Diagram-1.png) 41 | 42 | **Задача 2:** 43 | Реализирайте **K-ary Heap**. - опашка, която има най-много k наследника. 44 | Сравнете производителността при различни стойности на k. За кое k е най-оптимално ? 45 | -------------------------------------------------------------------------------- /Queue/CircularQueue/CircularQueue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QUEUE_HDR 2 | #define QUEUE_HDR 3 | 4 | #include 5 | using namespace std; 6 | 7 | template 8 | class Queue 9 | { 10 | private: 11 | 12 | T* data; 13 | size_t capacity; 14 | size_t count; 15 | 16 | size_t putIter; 17 | size_t getIter; 18 | 19 | void resize(); 20 | void copyFrom(const Queue& other); 21 | void free(); 22 | 23 | public: 24 | Queue(); 25 | Queue(const Queue& other); 26 | Queue& operator=(const Queue& other); 27 | ~Queue(); 28 | 29 | bool isEmpty() const; 30 | void enqueue(const T& el); 31 | void dequeue(); 32 | const T& peek() const; 33 | }; 34 | 35 | template 36 | void Queue::resize() 37 | { 38 | size_t newCapacity = capacity * 2; 39 | size_t currentCapacity = capacity; 40 | 41 | T* temp = new T[newCapacity]; 42 | 43 | for (int i = 0; i < currentCapacity; ++i) 44 | { 45 | temp[i] = peek(); 46 | dequeue(); 47 | } 48 | 49 | getIter = 0; 50 | putIter = capacity; 51 | 52 | count = capacity; 53 | capacity *= 2; 54 | 55 | delete[] data; 56 | data = temp; 57 | } 58 | 59 | template 60 | void Queue::copyFrom(const Queue& other) 61 | { 62 | data = new T[other.capacity]; 63 | for (int i = other.getIter; i != other.putIter; (i+=1)%=other.capacity) 64 | data[i] = other.data[i]; 65 | 66 | count = other.count; 67 | capacity = other.capacity; 68 | 69 | putIter = other.putIter; 70 | getIter = other.getIter; 71 | } 72 | 73 | template 74 | void Queue::free() 75 | { 76 | delete[] data; 77 | count = capacity = 0; 78 | } 79 | 80 | template 81 | Queue::Queue() 82 | { 83 | const size_t DEFAULT_CAPACITY = 4; 84 | 85 | data = new T[DEFAULT_CAPACITY]; 86 | capacity = DEFAULT_CAPACITY; 87 | count = 0; 88 | putIter = 0; 89 | getIter = 0; 90 | } 91 | 92 | template 93 | Queue::Queue(const Queue& other) 94 | { 95 | copyFrom(other); 96 | } 97 | 98 | template 99 | Queue& Queue::operator=(const Queue& other) 100 | { 101 | if (this != &other) 102 | { 103 | free(); 104 | copyFrom(other); 105 | } 106 | return *this; 107 | } 108 | 109 | template 110 | Queue::~Queue() 111 | { 112 | free(); 113 | } 114 | 115 | template 116 | bool Queue::isEmpty() const 117 | { 118 | return count == 0; 119 | } 120 | 121 | template 122 | void Queue::enqueue(const T& el) 123 | { 124 | if (count == capacity) 125 | resize(); 126 | 127 | data[putIter] = el; 128 | 129 | (++putIter) %= capacity; 130 | count++; 131 | } 132 | 133 | template 134 | void Queue::dequeue() 135 | { 136 | if (count == 0) 137 | throw std::runtime_error("Queue is empty!"); 138 | count--; 139 | (++getIter) %= capacity; 140 | } 141 | 142 | template 143 | const T& Queue::peek() const 144 | { 145 | if (isEmpty()) 146 | throw std::runtime_error("Queue is empty!"); 147 | return data[getIter]; 148 | } 149 | 150 | #endif // !QUEUE_HDR 151 | -------------------------------------------------------------------------------- /Queue/CircularQueue/source.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CircularQueue.hpp" 3 | 4 | int main() 5 | { 6 | Queue q; 7 | 8 | q.enqueue(1); 9 | q.enqueue(2); 10 | q.enqueue(3); 11 | q.enqueue(4); 12 | q.enqueue(5); 13 | 14 | std::cout << q.peek() << std::endl; 15 | q.dequeue(); 16 | std::cout << q.peek() << std::endl; 17 | q.dequeue(); 18 | std::cout << q.peek() << std::endl; 19 | q.dequeue(); 20 | std::cout << q.peek() << std::endl; 21 | q.dequeue(); 22 | std::cout << q.peek() << std::endl; 23 | q.dequeue(); 24 | 25 | std::cout << q.isEmpty() << std::endl; 26 | 27 | q.enqueue(1); 28 | q.enqueue(2); 29 | q.enqueue(3); 30 | q.enqueue(4); 31 | q.enqueue(5); 32 | 33 | Queue q2(q); 34 | std::cout << q.peek() << std::endl; 35 | q.dequeue(); 36 | std::cout << q.peek() << std::endl; 37 | q.dequeue(); 38 | std::cout << q.peek() << std::endl; 39 | q.dequeue(); 40 | std::cout << q.peek() << std::endl; 41 | q.dequeue(); 42 | std::cout << q.peek() << std::endl; 43 | q.dequeue(); 44 | } -------------------------------------------------------------------------------- /Queue/LinkedQueue/LinkedQueue.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class LinkedQueue 5 | { 6 | struct Node 7 | { 8 | Node(T data) 9 | { 10 | this->data = data; 11 | next = nullptr; 12 | } 13 | T data; 14 | Node* next; 15 | }; 16 | 17 | Node* head; 18 | Node* tail; 19 | 20 | void free(); 21 | void copyFrom(const LinkedQueue& other); 22 | 23 | public: 24 | LinkedQueue(); 25 | LinkedQueue(const LinkedQueue& other); 26 | LinkedQueue operator=(const LinkedQueue& other); 27 | ~LinkedQueue(); 28 | 29 | void enqueue(const T&); // O(1) 30 | void dequeue(); //O(1) 31 | const T& peek() const; //O(1) 32 | 33 | bool isEmpty() const; 34 | 35 | }; 36 | 37 | template 38 | void LinkedQueue::free() 39 | { 40 | Node* iter = head; 41 | while (iter != nullptr) 42 | { 43 | Node* prev = iter; 44 | iter = iter->next; 45 | delete prev; 46 | } 47 | 48 | head = tail = nullptr; 49 | } 50 | 51 | template 52 | void LinkedQueue::copyFrom(const LinkedQueue& other) 53 | { 54 | Node* iter = other.head; 55 | while (iter != nullptr) 56 | { 57 | enqueue(iter->data); 58 | iter = iter->next; 59 | } 60 | 61 | } 62 | 63 | template 64 | LinkedQueue::LinkedQueue() 65 | { 66 | head = nullptr; 67 | tail = nullptr; 68 | } 69 | 70 | template 71 | LinkedQueue::LinkedQueue(const LinkedQueue& other) 72 | { 73 | copyFrom(other); 74 | } 75 | 76 | template 77 | LinkedQueue LinkedQueue::operator=(const LinkedQueue& other) 78 | { 79 | if (this != &other) 80 | { 81 | free(); 82 | copyFrom(other); 83 | } 84 | return *this; 85 | } 86 | 87 | template 88 | void LinkedQueue::enqueue(const T& el) 89 | { 90 | Node* newNode = new Node(el); 91 | if (isEmpty()) 92 | { 93 | head = newNode; 94 | tail = newNode; 95 | } 96 | else 97 | { 98 | tail->next = newNode; 99 | tail = newNode; 100 | } 101 | } 102 | 103 | 104 | 105 | template 106 | void LinkedQueue::dequeue() 107 | { 108 | if (isEmpty()) 109 | throw std::runtime_error("The list is empty!"); 110 | else if (head == tail) 111 | { 112 | T el = head->data; 113 | delete head; 114 | 115 | head = nullptr; 116 | tail = nullptr; 117 | } 118 | else 119 | { 120 | Node* temp = head->next; 121 | 122 | delete head; 123 | head = temp; 124 | } 125 | 126 | } 127 | template 128 | const T& LinkedQueue::peek() const 129 | { 130 | if(isEmpty()) 131 | throw std::runtime_error("The list is empty!"); 132 | 133 | return head->data; 134 | } 135 | 136 | template 137 | bool LinkedQueue::isEmpty() const 138 | { 139 | return head == nullptr && tail == nullptr; 140 | } 141 | 142 | template 143 | LinkedQueue::~LinkedQueue() 144 | { 145 | free(); 146 | } 147 | -------------------------------------------------------------------------------- /Queue/LinkedQueue/source.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "LinkedQueue.hpp" 3 | 4 | int main() 5 | { 6 | LinkedQueue q; 7 | 8 | q.enqueue(1); 9 | q.enqueue(2); 10 | q.enqueue(3); 11 | q.enqueue(4); 12 | q.enqueue(5); 13 | 14 | std::cout << q.peek() << std::endl; 15 | q.dequeue(); 16 | std::cout << q.peek() << std::endl; 17 | q.dequeue(); 18 | std::cout << q.peek() << std::endl; 19 | q.dequeue(); 20 | std::cout << q.peek() << std::endl; 21 | q.dequeue(); 22 | std::cout << q.peek() << std::endl; 23 | q.dequeue(); 24 | 25 | std::cout << q.isEmpty() << std::endl; 26 | 27 | q.enqueue(1); 28 | q.enqueue(2); 29 | q.enqueue(3); 30 | q.enqueue(4); 31 | q.enqueue(5); 32 | 33 | LinkedQueue q2(q); 34 | std::cout << q.peek() << std::endl; 35 | q.dequeue(); 36 | std::cout << q.peek() << std::endl; 37 | q.dequeue(); 38 | std::cout << q.peek() << std::endl; 39 | q.dequeue(); 40 | std::cout << q.peek() << std::endl; 41 | q.dequeue(); 42 | std::cout << q.peek() << std::endl; 43 | q.dequeue(); 44 | } -------------------------------------------------------------------------------- /Queue/QueueWithTemplateContainer/Queue.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template > 5 | class Queue 6 | { 7 | private: 8 | Container container; 9 | 10 | public: 11 | void push(const T& value) 12 | { 13 | container.push_back(value); 14 | } 15 | 16 | void push(T&& value) 17 | { 18 | container.push_back(std::move(value)); 19 | } 20 | 21 | void pop() 22 | { 23 | container.pop_front(); 24 | } 25 | 26 | T& front() 27 | { 28 | return container.front(); 29 | } 30 | 31 | const T& front() const 32 | { 33 | return container.front(); 34 | } 35 | 36 | T& back() 37 | { 38 | return container.back(); 39 | } 40 | 41 | const T& back() const 42 | { 43 | return container.back(); 44 | } 45 | 46 | bool empty() const 47 | { 48 | return container.empty(); 49 | } 50 | 51 | size_t size() const 52 | { 53 | return container.size(); 54 | } 55 | }; -------------------------------------------------------------------------------- /Queue/QueueWithTemplateContainer/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Queue.hpp" 2 | int main() 3 | { 4 | Queue q; 5 | q.push(1); 6 | q.push(2); 7 | q.push(3); 8 | int x = 4; 9 | q.push(std::move(x)); 10 | std::cout << q.front() << " " << q.back() << std::endl; 11 | q.pop(); 12 | std::cout << q.front() << " " << q.size() << std::endl; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### **Код от семинарите по СД/СДА/СДП - ФМИ, спец. Информационни системи / Софтуерно инженерство** 2 | ----- 3 | 4 | - **Тема 1 :** Анализ на сложността на итеративни алгоритми. Анализ на сложността на алгортими за търсене и алгоритми за сортиране. Анализ на среден случай. 5 | - **Тема 2 :** Анализ на сложността на рекурсивни алгоритми. Рекурентни уравнения. Quick sort. Merge sort. 6 | - **Тема 3 :** Долна граница за сложност при сортиращи алгоритми, базирани на директни сравнения. Counting sort. Структура от данни вектор/динамичен масив. Амортизирана сложност. 7 | - **Тема 4 :** Свързан списък - едносвързан и двусвързан. 8 | - **Тема 5 :** Сортиране на свързани списъци. Алокатори. Абстрактна структура от данни Deque, имплементация. 9 | - **Тема 6 :** Стек и опашка. Дървета. Представяния на дървета в паметта. 10 | - **Тема 7 :** Двоично наредено дърво за търсене (Binary search tree). 11 | - **Тема 8 :** Самобалансиращи се дървета. AVL дърво 12 | - **Тема 9 :** Приоритетна опашка. Имплементация с двоична пирамира (binary heap) 13 | - **Тема 10 :** Set и Map. Хеш таблици. Справяне с колизии. 14 | - **Тема 11 :** Хеш таблици. (част 2) 15 | - **Тема 12 :** Графи. Обхождания на графи (BFS и DFS). Търсене на цикъл. Топологична сортировка. Търсене на свързани компоненти в граф. 16 | - **Тема 13 :** Тегловни графи. Най-къс път в граф. 17 | - **Тема 14 :** Тегловни графи. Минимално покриващо дърво 18 | 19 | 20 | 21 | ### Практикум на Група 2, ИС 22 | ----- 23 | - [Линк към repository-то](https://github.com/KristinaKalemdzhieva/Data_structures_and_algorithms_pract_FMI) 24 | 25 | 26 | # Overview 27 | 28 | ## Vector / Dynamic Array 29 | - with allocator 30 | - **Iterators:** 31 | - Iterator 32 | - Const Iterator 33 | - Reverse Iterator 34 | 35 | ## Singly Linked List 36 | - **Structure:** 37 | - Linked Nodes (with next pointer) 38 | - **Iterators:** 39 | - Iterator 40 | - Const Iterator 41 | 42 | ## Doubly Linked List 43 | - **Structure:** 44 | - Linked Nodes (with both previous and next pointers) 45 | - **Iterators:** 46 | - Iterator 47 | - Const Iterator 48 | 49 | ## Stack 50 | - **Structure:** 51 | - Linked Implementation 52 | - Array Implementation 53 | - Template Container Implementation 54 | 55 | ## Queue 56 | - **Structure:** 57 | - Linked Implementation 58 | - Array Implementation 59 | - Template Container Implementation 60 | 61 | ## Deque 62 | - **Structure:** 63 | - Linked Implementation 64 | - Array Implementation 65 | - **Iterators:** 66 | - Iterator 67 | 68 | ## Set/Map 69 | - **Structure:** 70 | - Binary Search Tree 71 | - **Iterators:** 72 | - Const Iterator 73 | - **Additional Features:** 74 | - Custom Comparator 75 | 76 | ## Priority Queue 77 | - **Structure:** 78 | - Binary Heap 79 | 80 | ## Unordered Map/Set 81 | - **Structure:** 82 | - Separate Chaining 83 | - **Iterators:** 84 | - Const Iterator 85 | - **Additional Features:** 86 | - Template Hasher 87 | 88 | ## Unordered Map/Set (Preserves Insertion Order) 89 | - **Structure:** 90 | - Separate Chaining 91 | - **Iterators:** 92 | - Const Iterator 93 | - **Additional Features:** 94 | - Template Hasher 95 | 96 | ## Unordered Map/Set (Linear Probing) 97 | - **Structure:** 98 | - Linear Probing 99 | - **Iterators:** 100 | - Const Iterator 101 | - **Additional Features:** 102 | - Template Hasher 103 | 104 | ## Disjoint Set 105 | - **Structure:** 106 | - Union by Height 107 | - Union by Size 108 | -------------------------------------------------------------------------------- /Searching/binary_search_iter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | template 5 | int binarySearch(const T* arr, int len, const T& searched) 6 | { 7 | int leftIndex = 0; 8 | int rightIndex = len - 1; 9 | while (leftIndex <= rightIndex) 10 | { 11 | int midIndex = (leftIndex + (rightIndex - leftIndex) / 2); 12 | 13 | if (arr[midIndex] == searched) 14 | return midIndex; 15 | 16 | if (arr[midIndex] > searched) 17 | rightIndex = midIndex - 1; 18 | else 19 | leftIndex = midIndex + 1; 20 | } 21 | return -1; 22 | 23 | } 24 | 25 | template 26 | Iterator binarySearch(Iterator begin, Iterator end, const T& value) 27 | { 28 | Iterator left = begin; 29 | Iterator right = end; 30 | 31 | while (left < right) 32 | { 33 | Iterator middle = left + std::distance(left, right) / 2; 34 | 35 | if (*middle == value) 36 | return middle; 37 | else if (*middle < value) 38 | left = middle + 1; 39 | else 40 | right = middle - 1; 41 | } 42 | return end; 43 | } 44 | 45 | int main() 46 | { 47 | int arr[] = { 1, 2, 3, 4, 5, 6, 7 }; 48 | 49 | cout << binarySearch(arr, 7, 10); 50 | } 51 | -------------------------------------------------------------------------------- /Searching/binary_search_rec.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | template 5 | int binarySearch(const int* arr, int len, const T& searched) 6 | { 7 | if (len == 0) 8 | return -1; 9 | 10 | int midIndex = len / 2; 11 | 12 | if (arr[midIndex] == searched) 13 | return midIndex; 14 | 15 | if (arr[midIndex] < searched) 16 | { 17 | int result = binarySearch(arr + midIndex + 1, len - midIndex - 1, searched); 18 | return (result == -1) ? -1 : result + midIndex + 1; 19 | } 20 | else 21 | return binarySearch(arr, midIndex, searched); 22 | } 23 | 24 | template 25 | Iterator binarySearchIterators(Iterator left, Iterator right, const T& value) 26 | { 27 | if (left >= right) 28 | return right; 29 | 30 | Iterator middle = left + std::distance(left, right) / 2; 31 | 32 | if (*middle == value) 33 | return middle; 34 | else if (*middle < value) 35 | return binarySearchIterators(middle + 1, right, value); 36 | else 37 | return binarySearchIterators(left, middle, value); 38 | } 39 | 40 | int main() 41 | { 42 | int arr[] = { 1, 2, 2, 6, 19, 55 }; 43 | cout << binarySearch(arr, 6, 19); 44 | } 45 | -------------------------------------------------------------------------------- /Searching/linear_search_iter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | int linearSearch(const T* arr, unsigned len, const T& searched) 5 | { 6 | for (int i = 0; i < len; i++) 7 | { 8 | if (arr[i] == searched) 9 | return i; 10 | } 11 | return -1; 12 | } 13 | 14 | //with iterators 15 | template 16 | Iterator linearSearch(Iterator begin, Iterator end, const T& value) { 17 | for (Iterator it = begin; it != end; ++it) 18 | { 19 | if (*it == value) 20 | { 21 | return it; 22 | } 23 | } 24 | return end; 25 | } 26 | 27 | int main() 28 | { 29 | int arr[] = { 1, 2, 3, 4, 5, 6, 7 }; 30 | 31 | std::cout << linearSearch(arr, 7, 10); 32 | } 33 | -------------------------------------------------------------------------------- /Searching/linear_search_rec.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | template 5 | bool linearSearch(const T* arr, unsigned len, const T& searched) 6 | { 7 | if (len == 0) 8 | return false; 9 | 10 | return *arr == searched || linearSearch(++arr, --len, searched); 11 | } 12 | 13 | template 14 | Iterator linearSearch(Iterator begin, Iterator end, const T& value) 15 | { 16 | if (begin == end) 17 | return end; 18 | 19 | if (*begin == value) 20 | return begin; 21 | 22 | return linearSearch(++begin, end, value); 23 | } 24 | 25 | int main() 26 | { 27 | int arr[5] = { 1, 2, 3, 4, 5 }; 28 | cout << linearSearch(arr, 5, 9); 29 | } 30 | -------------------------------------------------------------------------------- /SeparateChainingHash/Map/UnorderedMap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template > 9 | class UnorderedMap 10 | { 11 | private: 12 | std::list> data; 13 | std::vector>::iterator, size_t>> hashTable; 14 | size_t elementCount = 0; 15 | double loadFactorThreshold = 0.75; 16 | Hasher hasher; 17 | 18 | typename std::list>::iterator getElementByChain(size_t chainIndex, const Key& key); 19 | typename std::list>::const_iterator getElementByChain(size_t chainIndex, const Key& key) const; 20 | void rehash(size_t newSize); 21 | 22 | public: 23 | class ConstUnorderedMapIterator 24 | { 25 | friend class UnorderedMap; 26 | 27 | private: 28 | typename std::list>::const_iterator currElement; 29 | 30 | ConstUnorderedMapIterator(typename std::list>::const_iterator it) 31 | : currElement(it) 32 | { 33 | } 34 | 35 | public: 36 | ConstUnorderedMapIterator() {} 37 | 38 | ConstUnorderedMapIterator& operator++() 39 | { 40 | ++currElement; 41 | return *this; 42 | } 43 | 44 | ConstUnorderedMapIterator operator++(int) 45 | { 46 | ConstUnorderedMapIterator temp = *this; 47 | ++(*this); 48 | return temp; 49 | } 50 | 51 | const std::pair& operator*() const 52 | { 53 | return *currElement; 54 | } 55 | 56 | const std::pair* operator->() const 57 | { 58 | return &(*currElement); 59 | } 60 | 61 | bool operator==(const ConstUnorderedMapIterator& other) const 62 | { 63 | return currElement == other.currElement; 64 | } 65 | 66 | bool operator!=(const ConstUnorderedMapIterator& other) const 67 | { 68 | return currElement != other.currElement; 69 | } 70 | }; 71 | 72 | explicit UnorderedMap(size_t initHashSize = 16); 73 | 74 | std::pair insert(const Key& key, const T& value); 75 | ConstUnorderedMapIterator find(const Key& key) const; 76 | bool remove(const Key& key); 77 | bool remove(const ConstUnorderedMapIterator& iter); 78 | void clear(); 79 | bool empty() const; 80 | size_t size() const 81 | { 82 | return elementCount; 83 | } 84 | 85 | ConstUnorderedMapIterator cbegin() const 86 | { 87 | return ConstUnorderedMapIterator(data.cbegin()); 88 | } 89 | 90 | ConstUnorderedMapIterator cend() const 91 | { 92 | return ConstUnorderedMapIterator(data.cend()); 93 | } 94 | }; 95 | 96 | template 97 | UnorderedMap::UnorderedMap(size_t initHashSize) 98 | : hashTable(initHashSize, std::make_pair(data.end(), 0)) 99 | { 100 | } 101 | 102 | template 103 | typename std::list>::iterator UnorderedMap::getElementByChain(size_t chainIndex, const Key& key) 104 | { 105 | size_t chainSize = hashTable[chainIndex].second; 106 | if (chainSize == 0) return data.end(); 107 | 108 | auto currIt = hashTable[chainIndex].first; 109 | for (size_t i = 0; i < chainSize; i++) 110 | { 111 | if (currIt->first == key) return currIt; 112 | ++currIt; 113 | } 114 | return data.end(); 115 | } 116 | 117 | template 118 | typename std::list>::const_iterator UnorderedMap::getElementByChain(size_t chainIndex, const Key& key) const 119 | { 120 | size_t chainSize = hashTable[chainIndex].second; 121 | if (chainSize == 0) return data.cend(); 122 | 123 | auto currIt = hashTable[chainIndex].first; 124 | for (size_t i = 0; i < chainSize; i++) 125 | { 126 | if (currIt->first == key) return currIt; 127 | ++currIt; 128 | } 129 | return data.cend(); 130 | } 131 | 132 | template 133 | std::pair::ConstUnorderedMapIterator> UnorderedMap::insert(const Key& key, const T& value) 134 | { 135 | if (hashTable.empty()) hashTable.resize(16, std::make_pair(data.end(), 0)); 136 | 137 | size_t bucketIndex = hasher(key) % hashTable.size(); 138 | auto foundIt = getElementByChain(bucketIndex, key); 139 | if (foundIt != data.end()) return std::make_pair(false, ConstUnorderedMapIterator(foundIt)); 140 | 141 | auto& chainInfo = hashTable[bucketIndex]; 142 | if (chainInfo.second == 0) 143 | { 144 | data.push_front(std::make_pair(key, value)); 145 | chainInfo.first = data.begin(); 146 | } 147 | else 148 | { 149 | auto newIt = data.insert(chainInfo.first, std::make_pair(key, value)); 150 | chainInfo.first = newIt; 151 | } 152 | chainInfo.second++; 153 | elementCount++; 154 | 155 | double currentLoadFactor = static_cast(elementCount) / hashTable.size(); 156 | if (currentLoadFactor > loadFactorThreshold) 157 | { 158 | rehash(hashTable.size() * 2); 159 | size_t newBucketIndex = hasher(key) % hashTable.size(); 160 | auto newPos = getElementByChain(newBucketIndex, key); 161 | return std::make_pair(true, ConstUnorderedMapIterator(newPos)); 162 | } 163 | return std::make_pair(true, ConstUnorderedMapIterator(chainInfo.first)); 164 | } 165 | 166 | template 167 | typename UnorderedMap::ConstUnorderedMapIterator UnorderedMap::find(const Key& key) const 168 | { 169 | if (hashTable.empty()) return cend(); 170 | 171 | size_t bucketIndex = hasher(key) % hashTable.size(); 172 | auto foundIt = getElementByChain(bucketIndex, key); 173 | if (foundIt == data.end()) return cend(); 174 | 175 | return ConstUnorderedMapIterator(foundIt); 176 | } 177 | 178 | template 179 | bool UnorderedMap::remove(const Key& key) 180 | { 181 | if (hashTable.empty()) return false; 182 | 183 | size_t bucketIndex = hasher(key) % hashTable.size(); 184 | auto foundIt = getElementByChain(bucketIndex, key); 185 | if (foundIt == data.end()) return false; 186 | 187 | auto& chainInfo = hashTable[bucketIndex]; 188 | if (foundIt == chainInfo.first) 189 | { 190 | auto nextIt = foundIt; 191 | ++nextIt; 192 | chainInfo.first = nextIt; 193 | } 194 | 195 | data.erase(foundIt); 196 | chainInfo.second--; 197 | elementCount--; 198 | return true; 199 | } 200 | 201 | template 202 | bool UnorderedMap::remove(const ConstUnorderedMapIterator& iter) 203 | { 204 | if (iter == cend() || hashTable.empty()) return false; 205 | 206 | const Key& key = iter.currElement->first; 207 | return remove(key); 208 | } 209 | 210 | template 211 | void UnorderedMap::clear() 212 | { 213 | data.clear(); 214 | hashTable.clear(); 215 | elementCount = 0; 216 | } 217 | 218 | template 219 | bool UnorderedMap::empty() const 220 | { 221 | return elementCount == 0; 222 | } 223 | 224 | template 225 | void UnorderedMap::rehash(size_t newSize) 226 | { 227 | std::vector> oldElements; 228 | oldElements.reserve(elementCount); 229 | 230 | for (auto it = data.begin(); it != data.end(); ++it) 231 | { 232 | oldElements.push_back(*it); 233 | } 234 | 235 | data.clear(); 236 | hashTable.clear(); 237 | hashTable.resize(newSize, std::make_pair(data.end(), 0)); 238 | elementCount = 0; 239 | 240 | for (auto& elem : oldElements) 241 | { 242 | insert(elem.first, elem.second); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /SeparateChainingHash/Map/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "UnorderedMap.hpp" 4 | 5 | int main() 6 | { 7 | UnorderedMap myMap(4); 8 | myMap.insert("apple", 100); 9 | myMap.insert("banana", 200); 10 | myMap.insert("orange", 300); 11 | myMap.insert("pear", 400); 12 | std::cout << "Size: " << myMap.size() << std::endl; 13 | auto it = myMap.find("banana"); 14 | if (it != myMap.cend()) 15 | std::cout << "Found banana with value " << it->second << std::endl; 16 | 17 | myMap.remove("orange"); 18 | std::cout << "Size after removing orange: " << myMap.size() << std::endl; 19 | for (auto iter = myMap.cbegin(); iter != myMap.cend(); ++iter) 20 | std::cout << iter->first << " -> " << iter->second << std::endl; 21 | myMap.clear(); 22 | std::cout << "Size after clear: " << myMap.size() << std::endl; 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /SeparateChainingHash/Set/UnorderedSet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template > 8 | class UnorderedSet 9 | { 10 | private: 11 | std::list data; 12 | std::vector::iterator, size_t>> hashTable; 13 | 14 | size_t elementCount = 0; 15 | double loadFactorThreshold = 0.75; 16 | Hasher hasher; 17 | 18 | typename std::list::iterator getElementByChain(size_t chainIndex, const Key& element); 19 | typename std::list::const_iterator getElementByChain(size_t chainIndex, const Key& element) const; 20 | void rehash(size_t newSize); 21 | 22 | public: 23 | class ConstUnorderedSetIterator 24 | { 25 | friend class UnorderedSet; 26 | 27 | private: 28 | typename std::list::const_iterator currElement; 29 | 30 | ConstUnorderedSetIterator(typename std::list::const_iterator it) 31 | : currElement(it) { 32 | } 33 | 34 | public: 35 | ConstUnorderedSetIterator() {} 36 | 37 | ConstUnorderedSetIterator& operator++() 38 | { 39 | ++currElement; 40 | return *this; 41 | } 42 | 43 | ConstUnorderedSetIterator operator++(int) 44 | { 45 | ConstUnorderedSetIterator temp = *this; 46 | ++(*this); 47 | return temp; 48 | } 49 | 50 | const Key& operator*() const 51 | { 52 | return *currElement; 53 | } 54 | 55 | const Key* operator->() const 56 | { 57 | return &(*currElement); 58 | } 59 | 60 | bool operator==(const ConstUnorderedSetIterator& other) const 61 | { 62 | return currElement == other.currElement; 63 | } 64 | 65 | bool operator!=(const ConstUnorderedSetIterator& other) const 66 | { 67 | return currElement != other.currElement; 68 | } 69 | }; 70 | 71 | explicit UnorderedSet(size_t initHashSize = 16); 72 | 73 | std::pair insert(const Key& element); 74 | ConstUnorderedSetIterator find(const Key& element) const; 75 | bool remove(const Key& element); 76 | bool remove(const ConstUnorderedSetIterator& iter); 77 | void clear(); 78 | bool empty() const; 79 | size_t size() const 80 | { 81 | return elementCount; 82 | } 83 | ConstUnorderedSetIterator cbegin() const 84 | { 85 | return ConstUnorderedSetIterator(data.cbegin()); 86 | } 87 | ConstUnorderedSetIterator cend() const 88 | { 89 | return ConstUnorderedSetIterator(data.cend()); 90 | } 91 | }; 92 | 93 | template 94 | UnorderedSet::UnorderedSet(size_t initHashSize) 95 | : hashTable(initHashSize, std::make_pair(data.end(), 0)) 96 | { 97 | } 98 | 99 | //code duplicate!! (should be fixed) 100 | template 101 | typename std::list::iterator UnorderedSet::getElementByChain(size_t chainIndex, const Key& element) 102 | { 103 | size_t chainSize = hashTable[chainIndex].second; 104 | if (chainSize == 0) 105 | { 106 | return data.end(); 107 | } 108 | typename std::list::iterator currIt = hashTable[chainIndex].first; 109 | for (size_t i = 0; i < chainSize; i++) 110 | { 111 | if (*currIt == element) 112 | { 113 | return currIt; 114 | } 115 | ++currIt; 116 | } 117 | return data.end(); 118 | } 119 | 120 | template 121 | typename std::list::const_iterator UnorderedSet::getElementByChain(size_t chainIndex, const Key& element) const 122 | { 123 | size_t chainSize = hashTable[chainIndex].second; 124 | if (chainSize == 0) 125 | { 126 | return data.cend(); 127 | } 128 | typename std::list::const_iterator currIt = hashTable[chainIndex].first; 129 | for (size_t i = 0; i < chainSize; i++) 130 | { 131 | if (*currIt == element) 132 | { 133 | return currIt; 134 | } 135 | ++currIt; 136 | } 137 | return data.cend(); 138 | } 139 | 140 | template 141 | std::pair::ConstUnorderedSetIterator> UnorderedSet::insert(const Key& element) 142 | { 143 | if (hashTable.empty()) 144 | { 145 | hashTable.resize(16, std::make_pair(data.end(), 0)); 146 | } 147 | 148 | size_t bucketIndex = hasher(element) % hashTable.size(); 149 | typename std::list::iterator foundIt = getElementByChain(bucketIndex, element); 150 | if (foundIt != data.end()) 151 | { 152 | return std::make_pair(false, ConstUnorderedSetIterator(foundIt)); 153 | } 154 | std::pair::iterator, size_t>& chainInfo = hashTable[bucketIndex]; 155 | if (chainInfo.second == 0) 156 | { 157 | data.push_front(element); 158 | chainInfo.first = data.begin(); 159 | } 160 | else 161 | { 162 | typename std::list::iterator newIt = data.insert(chainInfo.first, element); 163 | chainInfo.first = newIt; 164 | } 165 | chainInfo.second++; 166 | elementCount++; 167 | 168 | 169 | double currentLoadFactor = static_cast(elementCount) / hashTable.size(); 170 | if (currentLoadFactor > loadFactorThreshold) 171 | { 172 | rehash(hashTable.size() * 2); 173 | size_t newBucketIndex = hasher(element) % hashTable.size(); 174 | typename std::list::iterator newPos = getElementByChain(newBucketIndex, element); 175 | return std::make_pair(true, ConstUnorderedSetIterator(newPos)); 176 | } 177 | 178 | return std::make_pair(true, ConstUnorderedSetIterator(chainInfo.first)); 179 | } 180 | 181 | template 182 | typename UnorderedSet::ConstUnorderedSetIterator UnorderedSet::find(const Key& element) const 183 | { 184 | if (hashTable.empty()) 185 | { 186 | return cend(); 187 | } 188 | size_t bucketIndex = hasher(element) % hashTable.size(); 189 | typename std::list::const_iterator foundIt = getElementByChain(bucketIndex, element); 190 | if (foundIt == data.end()) 191 | { 192 | return cend(); 193 | } 194 | return ConstUnorderedSetIterator(foundIt); 195 | } 196 | 197 | template 198 | bool UnorderedSet::remove(const Key& element) 199 | { 200 | if (hashTable.empty()) 201 | { 202 | return false; 203 | } 204 | size_t bucketIndex = hasher(element) % hashTable.size(); 205 | typename std::list::iterator foundIt = getElementByChain(bucketIndex, element); 206 | if (foundIt == data.end()) 207 | { 208 | return false; 209 | } 210 | 211 | std::pair::iterator, size_t>& chainInfo = hashTable[bucketIndex]; 212 | if (foundIt == chainInfo.first) 213 | { 214 | typename std::list::iterator nextIt = foundIt; 215 | ++nextIt; 216 | chainInfo.first = nextIt; 217 | } 218 | 219 | data.erase(foundIt); 220 | chainInfo.second--; 221 | elementCount--; 222 | return true; 223 | } 224 | 225 | template 226 | bool UnorderedSet::remove(const ConstUnorderedSetIterator& iter) 227 | { 228 | if (iter == cend() || hashTable.empty()) 229 | { 230 | return false; 231 | } 232 | const Key& element = *iter; 233 | return remove(element); 234 | } 235 | 236 | template 237 | void UnorderedSet::clear() 238 | { 239 | data.clear(); 240 | hashTable.clear(); 241 | elementCount = 0; 242 | } 243 | 244 | template 245 | bool UnorderedSet::empty() const 246 | { 247 | return (elementCount == 0); 248 | } 249 | 250 | template 251 | void UnorderedSet::rehash(size_t newSize) 252 | { 253 | std::vector oldElements; 254 | oldElements.reserve(elementCount); 255 | typename std::list::iterator it = data.begin(); 256 | while (it != data.end()) 257 | { 258 | oldElements.push_back(*it); 259 | ++it; 260 | } 261 | data.clear(); 262 | hashTable.clear(); 263 | hashTable.resize(newSize, std::make_pair(data.end(), 0)); 264 | elementCount = 0; 265 | typename std::vector::iterator vecIt = oldElements.begin(); 266 | while (vecIt != oldElements.end()) 267 | { 268 | insert(*vecIt); 269 | ++vecIt; 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /SeparateChainingHash/Set/main.cpp: -------------------------------------------------------------------------------- 1 | #include "UnorderedSet.hpp" 2 | 3 | 4 | int main() 5 | { 6 | UnorderedSet intSet(4); 7 | std::pair::ConstUnorderedSetIterator> result1 = intSet.insert(10); 8 | bool inserted1 = result1.first; 9 | UnorderedSet::ConstUnorderedSetIterator it1 = result1.second; 10 | std::cout << inserted1 << "\n"; 11 | 12 | std::pair::ConstUnorderedSetIterator> result2 = intSet.insert(10); 13 | bool inserted2 = result2.first; 14 | UnorderedSet::ConstUnorderedSetIterator it2 = result2.second; 15 | std::cout << inserted2 << "\n"; 16 | 17 | intSet.insert(1); 18 | intSet.insert(2); 19 | intSet.insert(3); 20 | intSet.insert(4); 21 | intSet.insert(5); 22 | 23 | UnorderedSet::ConstUnorderedSetIterator foundIt = intSet.find(30); 24 | if (foundIt != intSet.cend()) 25 | { 26 | std::cout << "Found\n"; 27 | } 28 | else 29 | { 30 | std::cout << "Not found.\n"; 31 | } 32 | 33 | bool removed3 = intSet.remove(3); 34 | std::cout << removed3 << "\n"; 35 | 36 | 37 | std::cout << "All elements: "; 38 | for (UnorderedSet::ConstUnorderedSetIterator it = intSet.cbegin(); it != intSet.cend(); ++it) 39 | { 40 | std::cout << *it << " "; 41 | } 42 | std::cout << "\n"; 43 | 44 | intSet.clear(); 45 | std::cout << intSet.empty() << "\n"; 46 | 47 | UnorderedSet stringSet; 48 | stringSet.insert("Hello"); 49 | stringSet.insert("World"); 50 | 51 | for (UnorderedSet::ConstUnorderedSetIterator it = stringSet.cbegin(); it != stringSet.cend(); ++it) 52 | { 53 | std::cout << *it << " "; 54 | } 55 | std::cout << "\n"; 56 | 57 | return 0; 58 | } -------------------------------------------------------------------------------- /SeparateChainingHash_InsertionOrderPerserve/Map/InsertionOrderHashMap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | template > 13 | class InsertionOrderHashMap 14 | { 15 | public: 16 | using Element = std::pair; 17 | 18 | class ConstIterator 19 | { 20 | public: 21 | const Element& operator*() const; 22 | ConstIterator& operator++(); 23 | ConstIterator operator++(int); 24 | const Element* operator->() const; 25 | bool operator==(const ConstIterator& other) const; 26 | bool operator!=(const ConstIterator& other) const; 27 | 28 | private: 29 | typename std::list::const_iterator currElement; 30 | ConstIterator(typename std::list::const_iterator curr); 31 | friend class InsertionOrderHashMap; 32 | }; 33 | 34 | InsertionOrderHashMap(); 35 | bool add(const Key& key, const Value& value); //TODO: to return iterators 36 | bool remove(const Key& key); 37 | ConstIterator find(const Key& key) const; 38 | ConstIterator cbegin() const; 39 | ConstIterator cend() const; 40 | double loadFactor() const; 41 | 42 | private: 43 | std::list data; 44 | std::vector::iterator>> hashTable; 45 | double maxLoadFactor = 0.75; 46 | Hash getHash; 47 | 48 | void resize(); 49 | size_t getHashCode(const Key& key) const; 50 | }; 51 | 52 | 53 | // Constructor 54 | template 55 | InsertionOrderHashMap::InsertionOrderHashMap() 56 | { 57 | hashTable.resize(8); 58 | } 59 | 60 | // ConstIterator Implementation 61 | template 62 | InsertionOrderHashMap::ConstIterator::ConstIterator(typename std::list::const_iterator curr) 63 | : currElement(curr) {} 64 | 65 | template 66 | const typename InsertionOrderHashMap::Element& 67 | InsertionOrderHashMap::ConstIterator::operator*() const 68 | { 69 | return *currElement; 70 | } 71 | 72 | template 73 | typename InsertionOrderHashMap::ConstIterator& 74 | InsertionOrderHashMap::ConstIterator::operator++() 75 | { 76 | ++currElement; 77 | return *this; 78 | } 79 | 80 | template 81 | typename InsertionOrderHashMap::ConstIterator 82 | InsertionOrderHashMap::ConstIterator::operator++(int) 83 | { 84 | ConstIterator temp = *this; 85 | ++(*this); 86 | return temp; 87 | } 88 | 89 | template 90 | const typename InsertionOrderHashMap::Element* 91 | InsertionOrderHashMap::ConstIterator::operator->() const { 92 | return &(*currElement); 93 | } 94 | 95 | template 96 | bool InsertionOrderHashMap::ConstIterator::operator==(const ConstIterator& other) const 97 | { 98 | return currElement == other.currElement; 99 | } 100 | 101 | template 102 | bool InsertionOrderHashMap::ConstIterator::operator!=(const ConstIterator& other) const 103 | { 104 | return currElement != other.currElement; 105 | } 106 | 107 | // Public methods 108 | template 109 | bool InsertionOrderHashMap::add(const Key& key, const Value& value) 110 | { 111 | if (loadFactor() >= maxLoadFactor) { 112 | resize(); 113 | } 114 | 115 | size_t hashCode = getHashCode(key); 116 | auto& bucket = hashTable[hashCode]; 117 | auto iter = std::find_if(bucket.begin(), bucket.end(), [&key](const auto& it) { 118 | return it->first == key; 119 | }); 120 | 121 | if (iter != bucket.end()) return false; 122 | 123 | data.emplace_back(key, value); 124 | bucket.push_front(--data.end()); 125 | return true; 126 | } 127 | 128 | template 129 | bool InsertionOrderHashMap::remove(const Key& key) 130 | { 131 | size_t hashCode = getHashCode(key); 132 | auto& bucket = hashTable[hashCode]; 133 | size_t removedCount = bucket.remove_if([this, &key](const auto& it) { 134 | if (it->first == key) { 135 | data.erase(it); 136 | return true; 137 | } 138 | return false; 139 | }); 140 | return removedCount; 141 | } 142 | 143 | template 144 | typename InsertionOrderHashMap::ConstIterator 145 | InsertionOrderHashMap::find(const Key& key) const 146 | { 147 | size_t hashCode = getHashCode(key); 148 | const auto& bucket = hashTable[hashCode]; 149 | auto iter = std::find_if(bucket.begin(), bucket.end(), [&key](const auto& it) { 150 | return it->first == key; 151 | }); 152 | 153 | if (iter == bucket.end()) return cend(); 154 | return ConstIterator(*iter); 155 | } 156 | 157 | template 158 | typename InsertionOrderHashMap::ConstIterator 159 | InsertionOrderHashMap::cbegin() const 160 | { 161 | return ConstIterator(data.cbegin()); 162 | } 163 | 164 | template 165 | typename InsertionOrderHashMap::ConstIterator 166 | InsertionOrderHashMap::cend() const 167 | { 168 | return ConstIterator(data.cend()); 169 | } 170 | 171 | template 172 | double InsertionOrderHashMap::loadFactor() const 173 | { 174 | return static_cast(data.size()) / hashTable.size(); 175 | } 176 | 177 | 178 | template 179 | void InsertionOrderHashMap::resize() 180 | { 181 | size_t newSize = hashTable.size() * 2; 182 | std::vector::iterator>> newHashTable(newSize); 183 | 184 | for (auto it = data.begin(); it != data.end(); ++it) { 185 | size_t newHashCode = getHashCode(it->first) % newSize; 186 | newHashTable[newHashCode].push_front(it); 187 | } 188 | 189 | hashTable = std::move(newHashTable); 190 | } 191 | 192 | 193 | template 194 | size_t InsertionOrderHashMap::getHashCode(const Key& key) const 195 | { 196 | return getHash(key) % hashTable.size(); 197 | } 198 | -------------------------------------------------------------------------------- /SeparateChainingHash_InsertionOrderPerserve/Map/main.cpp: -------------------------------------------------------------------------------- 1 | #include "InsertionOrderHashMap.hpp" 2 | 3 | int main() 4 | { 5 | InsertionOrderHashMap map; 6 | 7 | map.add("apple", 10); 8 | map.add("banana", 20); 9 | map.add("cherry", 30); 10 | 11 | std::cout << "Contents of the map:\n"; 12 | for (auto it = map.cbegin(); it != map.cend(); ++it) 13 | std::cout << (*it).first << ": " << (*it).second << "\n"; 14 | 15 | 16 | std::cout << "\nFinding 'banana':\n"; 17 | auto found = map.find("banana"); 18 | if (found != map.cend()) 19 | std::cout << (*found).first << ": " << (*found).second << "\n"; 20 | else 21 | std::cout << "Key not found.\n"; 22 | 23 | 24 | std::cout << "\nRemoving 'apple'...\n"; 25 | map.remove("apple"); 26 | 27 | std::cout << "Contents of the map after removal:\n"; 28 | for (auto it = map.cbegin(); it != map.cend(); ++it) 29 | std::cout << (*it).first << ": " << (*it).second << "\n"; 30 | 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /SeparateChainingHash_InsertionOrderPerserve/Set/InsertionOrderHashSet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | template > 13 | class InsertionOrderHashSet 14 | { 15 | public: 16 | class ConstIterator 17 | { 18 | public: 19 | const Key& operator*() const; 20 | ConstIterator& operator++(); 21 | ConstIterator operator++(int); 22 | const Key* operator->() const; 23 | bool operator==(const ConstIterator& other) const; 24 | bool operator!=(const ConstIterator& other) const; 25 | 26 | private: 27 | typename std::list::const_iterator currElement; 28 | ConstIterator(typename std::list::const_iterator curr); 29 | friend class InsertionOrderHashSet; 30 | }; 31 | 32 | InsertionOrderHashSet(); 33 | 34 | bool add(const Key& key); //would be better if add and remove return iterators! 35 | bool remove(const Key& key); 36 | ConstIterator find(const Key& key) const; 37 | ConstIterator cbegin() const; 38 | ConstIterator cend() const; 39 | 40 | private: 41 | std::list data; 42 | std::vector::iterator>> hashTable; 43 | double maxLoadFactor = 0.75; 44 | Hash getHash; 45 | 46 | void resize(); 47 | size_t getHashCode(const Key& key) const; 48 | double loadFactor() const; 49 | }; 50 | 51 | 52 | template 53 | InsertionOrderHashSet::ConstIterator::ConstIterator( 54 | typename std::list::const_iterator curr) 55 | : currElement(curr) {} 56 | 57 | template 58 | const Key& InsertionOrderHashSet::ConstIterator::operator*() const 59 | { 60 | return *currElement; 61 | } 62 | 63 | template 64 | typename InsertionOrderHashSet::ConstIterator& 65 | InsertionOrderHashSet::ConstIterator::operator++() 66 | { 67 | ++currElement; 68 | return *this; 69 | } 70 | 71 | template 72 | typename InsertionOrderHashSet::ConstIterator 73 | InsertionOrderHashSet::ConstIterator::operator++(int) 74 | { 75 | ConstIterator temp = *this; 76 | ++(*this); 77 | return temp; 78 | } 79 | 80 | template 81 | const Key* InsertionOrderHashSet::ConstIterator::operator->() const 82 | { 83 | return &(*currElement); 84 | } 85 | 86 | template 87 | bool InsertionOrderHashSet::ConstIterator::operator==(const ConstIterator& other) const 88 | { 89 | return currElement == other.currElement; 90 | } 91 | 92 | template 93 | bool InsertionOrderHashSet::ConstIterator::operator!=(const ConstIterator& other) const 94 | { 95 | return currElement != other.currElement; 96 | } 97 | 98 | template 99 | InsertionOrderHashSet::InsertionOrderHashSet() 100 | { 101 | hashTable.resize(8); // initial number of buckets 102 | } 103 | 104 | template 105 | bool InsertionOrderHashSet::add(const Key& key) 106 | { 107 | if (loadFactor() >= maxLoadFactor) 108 | { 109 | resize(); 110 | } 111 | 112 | size_t hashCode = getHashCode(key); 113 | auto& bucket = hashTable[hashCode]; 114 | 115 | auto it = std::find_if(bucket.begin(), bucket.end(), 116 | [&key](auto listIt) { return *listIt == key; }); 117 | if (it != bucket.end()) { 118 | return false; 119 | } 120 | 121 | data.push_back(key); 122 | auto insertedIt = --data.end(); 123 | bucket.push_front(insertedIt); 124 | return true; 125 | } 126 | 127 | template 128 | bool InsertionOrderHashSet::remove(const Key& key) 129 | { 130 | size_t hashCode = getHashCode(key); 131 | auto& bucket = hashTable[hashCode]; 132 | 133 | size_t removed = bucket.remove_if([this, &key](const auto& listIt) { 134 | if (*listIt == key) 135 | { 136 | data.erase(listIt); 137 | return true; 138 | } 139 | return false; 140 | }); 141 | return removed; 142 | } 143 | 144 | template 145 | typename InsertionOrderHashSet::ConstIterator 146 | InsertionOrderHashSet::find(const Key& key) const 147 | { 148 | size_t hashCode = getHashCode(key); 149 | const auto& bucket = hashTable[hashCode]; 150 | 151 | auto it = std::find_if(bucket.begin(), bucket.end(), 152 | [&key](auto listIt) { return *listIt == key; }); 153 | if (it == bucket.end()) { 154 | return cend(); 155 | } 156 | return ConstIterator(*it); 157 | } 158 | 159 | template 160 | typename InsertionOrderHashSet::ConstIterator 161 | InsertionOrderHashSet::cbegin() const 162 | { 163 | return ConstIterator(data.cbegin()); 164 | } 165 | 166 | template 167 | typename InsertionOrderHashSet::ConstIterator 168 | InsertionOrderHashSet::cend() const 169 | { 170 | return ConstIterator(data.cend()); 171 | } 172 | 173 | template 174 | double InsertionOrderHashSet::loadFactor() const 175 | { 176 | return static_cast(data.size()) / hashTable.size(); 177 | } 178 | 179 | template 180 | void InsertionOrderHashSet::resize() 181 | { 182 | size_t newSize = hashTable.size() * 2; 183 | std::vector::iterator>> newHashTable(newSize); 184 | 185 | for (auto it = data.begin(); it != data.end(); ++it) 186 | { 187 | size_t newHashCode = getHash(*it) % newSize; 188 | newHashTable[newHashCode].push_front(it); 189 | } 190 | 191 | hashTable = std::move(newHashTable); 192 | } 193 | 194 | template 195 | size_t InsertionOrderHashSet::getHashCode(const Key& key) const 196 | { 197 | return getHash(key) % hashTable.size(); 198 | } 199 | -------------------------------------------------------------------------------- /SeparateChainingHash_InsertionOrderPerserve/Set/main.cpp: -------------------------------------------------------------------------------- 1 | #include "InsertionOrderHashSet.hpp" 2 | 3 | int main() 4 | { 5 | InsertionOrderHashSet hashSet; 6 | 7 | hashSet.add("Apple"); 8 | hashSet.add("Banana"); 9 | hashSet.add("Cherry"); 10 | hashSet.add("Date"); 11 | hashSet.add("Elderberry"); 12 | 13 | std::cout << "Contents of the set (in insertion order):\n"; 14 | for (auto it = hashSet.cbegin(); it != hashSet.cend(); ++it) 15 | std::cout << *it << "\n"; 16 | 17 | 18 | std::cout << "\nAdding duplicates:\n"; 19 | hashSet.add("Apple"); 20 | hashSet.add("Banana"); 21 | 22 | std::cout << "Contents of the set after attempting to add duplicates:\n"; 23 | for (auto it = hashSet.cbegin(); it != hashSet.cend(); ++it) 24 | std::cout << *it << "\n"; 25 | 26 | 27 | std::cout << "\nFinding elements:\n"; 28 | if (hashSet.find("Cherry") != hashSet.cend()) 29 | std::cout << "Found: Cherry\n"; 30 | else 31 | std::cout << "Cherry not found\n"; 32 | 33 | 34 | if (hashSet.find("Fig") != hashSet.cend()) 35 | std::cout << "Found: Fig\n"; 36 | 37 | else 38 | std::cout << "Fig not found\n"; 39 | 40 | 41 | std::cout << "\nRemoving elements:\n"; 42 | hashSet.remove("Banana"); 43 | hashSet.remove("Date"); 44 | 45 | std::cout << "Contents of the set after removal:\n"; 46 | for (auto it = hashSet.cbegin(); it != hashSet.cend(); ++it) 47 | std::cout << *it << "\n"; 48 | 49 | 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /Sorting/bubbleSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | template 6 | void bubbleSort(T* arr, unsigned len) 7 | { 8 | unsigned end = len - 1; 9 | for (int i = 0; i < len - 1; i++) 10 | { 11 | unsigned lastSwappedIndex = 0; 12 | 13 | for (int j = 0; j < end; j++) 14 | { 15 | if (arr[j] > arr[j + 1]) 16 | { 17 | std::swap(arr[j], arr[j + 1]); 18 | lastSwappedIndex = j; 19 | } 20 | } 21 | 22 | end = lastSwappedIndex; 23 | if (lastSwappedIndex == 0) // Is the array already sorted? 24 | return; 25 | } 26 | } 27 | 28 | int main() 29 | { 30 | int arr[] = { 7, 6, 5, 4, 3, 2, 1 }; 31 | 32 | bubbleSort(arr, 7); 33 | 34 | for (int i = 0; i < 7; i++) 35 | cout << arr[i] << " "; 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /Sorting/countSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | 6 | struct Student 7 | { 8 | std::string name; 9 | int grade; 10 | }; 11 | 12 | void countSortForGrades(Student* arr, size_t len) 13 | { 14 | const size_t GRADES_VALUES_COUNT = 5; 15 | 16 | size_t* countArr = new size_t[GRADES_VALUES_COUNT]{ 0 }; //2,3,4,5,6 17 | 18 | for (int i = 0; i < len; i++) 19 | countArr[arr[i].grade - 2]++; 20 | 21 | for (int i = 1; i < GRADES_VALUES_COUNT; i++) 22 | countArr[i] += countArr[i - 1]; 23 | 24 | Student* result = new Student[len]; 25 | for (int i = len - 1; i >= 0; i--) 26 | { 27 | Student& currentStudent = arr[i]; 28 | size_t index = --countArr[currentStudent.grade - 2]; 29 | result[index] = currentStudent; 30 | } 31 | 32 | for (int i = 0; i < len; i++) 33 | arr[i] = result[i]; 34 | delete[] result; 35 | delete[] countArr; 36 | } 37 | 38 | //Homework task: make stable 39 | int main() 40 | { 41 | Student arr[] = { { "Petur", 4 }, { "Ivan", 6 }, { "Alex", 4 }, { "Vladimir", 5 }, { "Katerina", 5 } }; 42 | 43 | countSortForGrades(arr, sizeof(arr)/sizeof(Student)); 44 | 45 | for (int i = 0; i < sizeof(arr) / sizeof(Student); i++) 46 | cout << "Name: " << arr[i].name << ", grade: " << arr[i].grade << endl; 47 | 48 | } -------------------------------------------------------------------------------- /Sorting/insertionSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | template 6 | void naiveInsertionSort(T* arr, int len) 7 | { 8 | for (int i = 1; i < len; i++) 9 | { 10 | int elIndex = i; 11 | while (elIndex > 0 && arr[elIndex] < arr[elIndex - 1]) 12 | { 13 | std::swap(arr[elIndex], arr[elIndex - 1]); 14 | elIndex--; 15 | } 16 | } 17 | } 18 | 19 | template 20 | void insertionSort(T* arr, int len) 21 | { 22 | for (int i = 1; i < len; i++) 23 | { 24 | T element = arr[i]; 25 | int index = i - 1; 26 | while (index >= 0 && arr[index] > element) 27 | { 28 | arr[index + 1] = arr[index]; 29 | index--; 30 | } 31 | arr[index + 1] = element; // Inserting the element at the correct position 32 | } 33 | } 34 | 35 | int main() 36 | { 37 | int arr[] = { 7, 6, 5, 4, 3, 2, 1 }; 38 | int len = sizeof(arr) / sizeof(arr[0]); 39 | 40 | // Using Naive Insertion Sort 41 | NaiveInsertionSort(arr, len); 42 | cout << "Sorted using Naive Insertion Sort: "; 43 | for (int i = 0; i < len; i++) 44 | cout << arr[i] << " "; 45 | cout << endl; 46 | 47 | // Resetting the array for the next sort 48 | int arr2[] = { 7, 6, 5, 4, 3, 2, 1 }; 49 | 50 | // Using Insertion Sort 51 | InsertionSort(arr2, len); 52 | cout << "Sorted using Insertion Sort: "; 53 | for (int i = 0; i < len; i++) 54 | cout << arr2[i] << " "; 55 | cout << endl; 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /Sorting/mergeSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | template 6 | void Merge(T* firstArr, size_t firstSize, T* secondArr, size_t secondSize, T* resultArr) 7 | { 8 | size_t resultIter = 0; 9 | size_t firstIter = 0; 10 | size_t secondIter = 0; 11 | 12 | while(firstIter < firstSize && secondIter < secondSize) 13 | resultArr[resultIter++] = (firstArr[firstIter] <= secondArr[secondIter] ? firstArr[firstIter++] : secondArr[secondIter++]); 14 | 15 | while(firstIter < firstSize) 16 | resultArr[resultIter++] = firstArr[firstIter++]; 17 | 18 | while(secondIter < secondSize) 19 | resultArr[resultIter++] = secondArr[secondIter++]; 20 | } 21 | 22 | template 23 | void MergeSortStep(T* pArr, size_t Size, T* pBuffer) 24 | { 25 | if(Size <= 1) 26 | return; 27 | 28 | size_t middle = Size / 2; 29 | 30 | MergeSortStep(pArr, middle, pBuffer); 31 | 32 | MergeSortStep(pArr + middle, Size - middle, pBuffer + middle); 33 | 34 | Merge(pArr, middle, pArr + middle, Size - middle, pBuffer); 35 | 36 | for(size_t i = 0; i < Size; i++) 37 | pArr[i] = pBuffer[i]; 38 | } 39 | 40 | template 41 | void MergeSort(T* pArr, size_t Size) 42 | { 43 | if (!pArr || Size == 0) 44 | return; 45 | 46 | T* pBuffer = new T[Size]; 47 | 48 | MergeSortStep(pArr, Size, pBuffer); 49 | 50 | delete[] pBuffer; 51 | } 52 | 53 | 54 | const int SIZE = 15; 55 | int main() 56 | { 57 | int arr1[] = { 15,14,13,12,11,30,90,8,7,6,5,4,3,2,1}; 58 | MergeSort(arr1, SIZE); 59 | 60 | for (int i = 0; i < SIZE; i++) 61 | cout << arr1[i] << " "; 62 | } 63 | -------------------------------------------------------------------------------- /Sorting/naiveMergeSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 6.0. Merge function - merges 2 sorted arrays 5 | template 6 | void Merge(T* arr1, int len1, T* arr2, int len2) 7 | { 8 | T* resultArray = new T[len1 + len2]; 9 | 10 | int cursor1 = 0; 11 | int cursor2 = 0; 12 | int resultCursor = 0; 13 | 14 | while (cursor1 < len1 && cursor2 < len2) 15 | { 16 | if (arr1[cursor1] <= arr2[cursor2]) 17 | resultArray[resultCursor++] = arr1[cursor1++]; 18 | else 19 | resultArray[resultCursor++] = arr2[cursor2++]; 20 | } 21 | 22 | while (cursor1 < len1) 23 | resultArray[resultCursor++] = arr1[cursor1++]; 24 | while (cursor2 < len2) 25 | resultArray[resultCursor++] = arr2[cursor2++]; 26 | 27 | for (int i = 0; i < len1 + len2; i++) 28 | arr1[i] = resultArray[i]; 29 | delete[] resultArray; 30 | } 31 | 32 | template 33 | void MergeSort(T* arr, int len) 34 | { 35 | if (len == 1) 36 | return; 37 | 38 | int mid = len / 2; 39 | 40 | MergeSort(arr, mid); 41 | MergeSort(arr + mid, len - mid); 42 | 43 | Merge(arr, mid, arr + mid, len - mid); 44 | } 45 | 46 | int main() 47 | { 48 | int arr[4] = { 9, 6, 5, 8 }; 49 | MergeSort(arr, 4); 50 | 51 | for (int i = 0; i < 4; i++) 52 | cout << arr[i] << " "; 53 | } 54 | -------------------------------------------------------------------------------- /Sorting/quickSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | template 5 | size_t partition(T* arr, size_t len) 6 | { 7 | T pivot = arr[len / 2]; 8 | 9 | int i = 0; 10 | int j = len - 1; 11 | 12 | while (true) 13 | { 14 | while (arr[i] < pivot) 15 | { 16 | i++; 17 | } 18 | while (arr[j] > pivot) 19 | { 20 | j--; 21 | } 22 | 23 | if (arr[i] == arr[j]) 24 | { 25 | i++; 26 | } 27 | if (i < j) 28 | { 29 | std::swap(arr[i], arr[j]); 30 | } 31 | else 32 | { 33 | return j; 34 | } 35 | } 36 | } 37 | 38 | template 39 | size_t advancedPartition(T* pArr, size_t len) 40 | { 41 | if (pArr[0] > pArr[len - 1]) 42 | std::swap(pArr[0], pArr[len - 1]); 43 | 44 | T& partitioningElement = pArr[len - 1]; 45 | size_t left = 0; 46 | size_t right = len - 1; 47 | 48 | while (true) 49 | { 50 | while (pArr[++left] < partitioningElement) 51 | ; 52 | 53 | while (pArr[--right] > partitioningElement) 54 | { 55 | if (left == right) 56 | break; 57 | } 58 | 59 | if (left >= right) 60 | break; 61 | 62 | std::swap(pArr[left], pArr[right]); 63 | } 64 | 65 | std::swap(pArr[left], partitioningElement); 66 | return left; 67 | } 68 | 69 | template 70 | void QuickSort(T* arr, size_t len) 71 | { 72 | if (len <= 1) 73 | return; 74 | 75 | size_t pivotIndex = partition(arr, len); 76 | QuickSort(arr, pivotIndex); 77 | QuickSort(arr + pivotIndex + 1, len - pivotIndex - 1); 78 | } 79 | 80 | const int SIZE = 15; 81 | int main() 82 | { 83 | int arr1[] = { 15, 14, 13, 12, 11, 30, 90, 8, 7, 6, 5, 4, 3, 2, 1 }; 84 | QuickSort(arr1, SIZE); 85 | 86 | for (int i = 0; i < SIZE; i++) 87 | cout << arr1[i] << " "; 88 | } 89 | -------------------------------------------------------------------------------- /Sorting/readme.md: -------------------------------------------------------------------------------- 1 | | **Algorithm** | **Best Case** | **Average Case** | **Worst Case** | **Space Complexity** | **Stable** | **Adaptive** | **Note** | 2 | |-------------------|--------------------|------------------|------------------|----------------------|------------|--------------|-----------------------------------------------------| 3 | | **Bubble Sort** | Θ(n) | Θ(n²) | Θ(n²) | O(1) | Yes | Yes | | 4 | | **Selection Sort** | Θ(n²) | Θ(n²) | Θ(n²) | O(1) | No | No | Minimizes the number of swaps | 5 | | **Insertion Sort** | Θ(n) | Θ(n²) | Θ(n²) | O(1) | Yes | Yes | Efficient when elements are near their correct positions | 6 | | **Merge Sort** | Θ(n log n) | Θ(n log n) | Θ(n log n) | O(n) | Yes | No | | 7 | | **Quick Sort** | Θ(n log n) | Θ(n log n) | Θ(n²) | O(log n) | No | No | | 8 | | **Counting Sort** | Θ(n+k) | Θ(n+k) | Θ(n+k) | O(k) | Yes | No | Best for sorting small integer ranges | 9 | -------------------------------------------------------------------------------- /Sorting/selectionSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | template 6 | void SelectionSort(T* arr, int size) 7 | { 8 | for (int i = 0; i < size - 1; i++) 9 | { 10 | int minElementIndex = i; 11 | 12 | for (int j = i + 1; j < size; j++) 13 | { 14 | if (arr[j] < arr[minElementIndex]) 15 | minElementIndex = j; 16 | } 17 | 18 | if (i != minElementIndex) 19 | std::swap(arr[i], arr[minElementIndex]); // Using std::swap 20 | } 21 | } 22 | 23 | int main() 24 | { 25 | int arr[] = { 7, 6, 5, 4, 3, 2, 1 }; 26 | int size = sizeof(arr) / sizeof(arr[0]); 27 | 28 | SelectionSort(arr, size); 29 | 30 | for (int i = 0; i < size; i++) 31 | cout << arr[i] << " "; 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /Stack/ArrayStack/ArrayStack.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //Same implementation as DynamicArray. We only use PushBack and PopBack from it. 4 | 5 | template 6 | class ArrayStack 7 | { 8 | 9 | private: 10 | T* data; 11 | size_t currentSize; 12 | size_t capacity; 13 | 14 | void copyFrom(const ArrayStack&); 15 | void free(); 16 | void resize(size_t); 17 | 18 | public: 19 | ArrayStack(); 20 | ArrayStack(const ArrayStack&); 21 | ArrayStack& operator=(const ArrayStack&); 22 | ~ArrayStack(); 23 | 24 | 25 | void push(const T&); 26 | void pop(); 27 | const T& peek() const; 28 | 29 | size_t size() const; 30 | size_t isEmpty() const; 31 | }; 32 | 33 | template 34 | ArrayStack::ArrayStack() : currentSize(0), capacity(4) 35 | { 36 | data = new T[capacity]; 37 | } 38 | 39 | 40 | template 41 | ArrayStack::ArrayStack(const ArrayStack& other) 42 | { 43 | copyFrom(other); 44 | } 45 | 46 | template 47 | ArrayStack& ArrayStack::operator=(const ArrayStack& other) 48 | { 49 | 50 | if (this != &other) 51 | { 52 | free(); 53 | copyFrom(other); 54 | } 55 | return *this; 56 | } 57 | 58 | template 59 | ArrayStack::~ArrayStack() 60 | { 61 | free(); 62 | } 63 | 64 | template 65 | void ArrayStack::copyFrom(const ArrayStack& other) 66 | { 67 | data = new T[other.capacity]; 68 | 69 | for (size_t i = 0; i < other.currentSize; i++) 70 | data[i] = other.data[i]; 71 | 72 | currentSize = other.currentSize; 73 | capacity = other.capacity; 74 | } 75 | 76 | template 77 | void ArrayStack::free() 78 | { 79 | delete[] data; 80 | } 81 | 82 | template 83 | void ArrayStack::resize(size_t newCap) 84 | { 85 | 86 | T* temp = data; 87 | data = new T[newCap]; 88 | 89 | for (size_t i = 0; i < currentSize; i++) 90 | data[i] = temp[i]; 91 | 92 | capacity = newCap; 93 | delete[] temp; 94 | } 95 | 96 | 97 | 98 | template 99 | void ArrayStack::push(const T& newElem) 100 | { 101 | 102 | if (currentSize >= capacity) 103 | resize(capacity * 2); 104 | 105 | data[currentSize++] = newElem; 106 | } 107 | 108 | template 109 | void ArrayStack::pop() 110 | { 111 | if (isEmpty()) 112 | throw std::runtime_error("Stack is empty!"); 113 | 114 | T el = data[--currentSize]; 115 | 116 | if (currentSize * 2 <= capacity && capacity > 1) 117 | resize(capacity / 2); 118 | } 119 | 120 | template 121 | const T& ArrayStack::peek() const 122 | { 123 | if (isEmpty()) 124 | throw std::runtime_error("Stack is empty!"); 125 | 126 | return data[currentSize - 1]; 127 | } 128 | 129 | template 130 | size_t ArrayStack::size() const 131 | { 132 | return currentSize; 133 | } 134 | 135 | template 136 | size_t ArrayStack::isEmpty() const 137 | { 138 | return size() == 0; 139 | } -------------------------------------------------------------------------------- /Stack/ArrayStack/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ArrayStack.hpp" 3 | 4 | int main() 5 | { 6 | 7 | ArrayStack arrStack; 8 | arrStack.push(3); 9 | arrStack.push(5); 10 | arrStack.push(7); 11 | std::cout << arrStack.size() << std::endl; 12 | std::cout << arrStack.peek() << std::endl; 13 | arrStack.pop(); 14 | std::cout << arrStack.peek() << std::endl; 15 | 16 | ArrayStack newArrStack = arrStack; 17 | std::cout << newArrStack.size() << std::endl; 18 | 19 | 20 | return 0; 21 | } -------------------------------------------------------------------------------- /Stack/LinkedStack/LinkedStack.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class LinkedStack 5 | { 6 | struct Node 7 | { 8 | Node(const T& data) 9 | { 10 | this->data = data; 11 | next = nullptr; 12 | } 13 | T data; 14 | Node* next; 15 | }; 16 | Node* head; 17 | 18 | void free(); 19 | void copyFrom(const LinkedStack& other); 20 | public: 21 | 22 | LinkedStack(); 23 | LinkedStack(const LinkedStack& other); 24 | LinkedStack operator=(const LinkedStack& other); 25 | ~LinkedStack(); 26 | 27 | 28 | void push(const T&); //O(1) 29 | void pop(); //O(1) 30 | const T& peek() const; // O(1) 31 | 32 | bool isEmpty() const; 33 | }; 34 | 35 | template 36 | void LinkedStack::free() 37 | { 38 | Node* iter = head; 39 | while (iter != nullptr) 40 | { 41 | Node* prev = iter; 42 | iter = iter->next; 43 | delete prev; 44 | } 45 | } 46 | 47 | template 48 | void LinkedStack::copyFrom(const LinkedStack& other) 49 | { 50 | head = nullptr; 51 | if (other.isEmpty()) 52 | return; 53 | 54 | Node* iterOther = other.head; 55 | 56 | head = new Node(iterOther->data); 57 | Node* iterThis = head; 58 | do 59 | { 60 | iterOther = iterOther->next; 61 | if (iterOther) 62 | { 63 | iterThis->next = new Node(iterOther->data); 64 | iterThis = iterThis->next; 65 | } 66 | } while (iterOther); 67 | 68 | } 69 | 70 | template 71 | LinkedStack::LinkedStack() 72 | { 73 | head = nullptr; 74 | } 75 | 76 | template 77 | LinkedStack::LinkedStack(const LinkedStack& other) 78 | { 79 | copyFrom(other); 80 | } 81 | 82 | template 83 | LinkedStack LinkedStack::operator=(const LinkedStack& other) 84 | { 85 | if (this != &other) 86 | { 87 | free(); 88 | copyFrom(other); 89 | } 90 | return *this; 91 | } 92 | 93 | 94 | template 95 | void LinkedStack::push(const T& el) 96 | { 97 | Node* newNode = new Node(el); 98 | if (isEmpty()) 99 | head = newNode; 100 | else 101 | { 102 | newNode->next = head; 103 | head = newNode; 104 | } 105 | } 106 | 107 | template 108 | void LinkedStack::pop() 109 | { 110 | if (isEmpty()) 111 | throw std::logic_error("The LinkedStack is empty"); 112 | else if (head->next == nullptr) //only one element left 113 | { 114 | delete head; 115 | head = nullptr; 116 | } 117 | else 118 | { 119 | Node* temp = head->next; 120 | delete head; 121 | head = temp; 122 | } 123 | 124 | } 125 | 126 | template 127 | const T& LinkedStack::peek() const 128 | { 129 | if(isEmpty()) 130 | throw std::logic_error("The LinkedStack is empty"); 131 | return head->data; 132 | } 133 | 134 | template 135 | bool LinkedStack::isEmpty() const 136 | { 137 | return head == nullptr; 138 | } 139 | 140 | template 141 | LinkedStack::~LinkedStack() 142 | { 143 | free(); 144 | } 145 | -------------------------------------------------------------------------------- /Stack/LinkedStack/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "LinkedStack.hpp" 3 | 4 | int main() 5 | { 6 | LinkedStack list; 7 | list.push(15); 8 | list.push(20); 9 | std::cout << list.peek() << std::endl; 10 | list.pop(); 11 | std::cout << list.isEmpty() << std::endl; 12 | std::cout << list.peek() << std::endl; 13 | list.pop(); 14 | 15 | list.push(100); 16 | 17 | LinkedStack newList = list; 18 | std::cout << newList.peek() << std::endl; 19 | 20 | return 0; 21 | } -------------------------------------------------------------------------------- /Stack/StackWithTemplateContainer/StackWithContainer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | template > 5 | class Stack 6 | { 7 | private: 8 | Container _c; 9 | 10 | public: 11 | T& top() 12 | { 13 | return _c.back(); 14 | } 15 | const T& top() const 16 | { 17 | return _c.back(); 18 | } 19 | 20 | bool empty() const 21 | { 22 | return _c.empty(); 23 | } 24 | size_t size() const 25 | { 26 | return _c.size(); 27 | } 28 | 29 | void push(const T& el) 30 | { 31 | _c.push_back(el); 32 | } 33 | void pop() 34 | { 35 | _c.pop_back(); 36 | } 37 | }; -------------------------------------------------------------------------------- /Stack/StackWithTemplateContainer/main.cpp: -------------------------------------------------------------------------------- 1 | #include "StackWithContainer.hpp" 2 | 3 | int main() 4 | { 5 | Stack s; 6 | s.push(3); 7 | s.pop(); 8 | } -------------------------------------------------------------------------------- /Vector/iterator/iterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | template 5 | class const_vector_iterator 6 | { 7 | public: 8 | const_vector_iterator(T* passedVal) : memPointer{passedVal} {} 9 | const_vector_iterator(T* passedVal, size_t _push) : memPointer{passedVal + _push} {} 10 | 11 | const_vector_iterator operator+(int off) const 12 | { 13 | return {memPointer + off}; 14 | } 15 | 16 | const_vector_iterator operator-(int off) const 17 | { 18 | return {memPointer - off}; 19 | } 20 | 21 | int operator-(const_vector_iterator other) const 22 | { 23 | return memPointer - other.memPointer; 24 | } 25 | 26 | const T* operator->() const noexcept 27 | { 28 | return memPointer; 29 | } 30 | 31 | const T& operator*() const noexcept 32 | { 33 | return *(memPointer); 34 | } 35 | 36 | bool operator==(const const_vector_iterator& it) const 37 | { 38 | return (memPointer == it.memPointer); 39 | } 40 | 41 | bool operator!=(const const_vector_iterator& it) const 42 | { 43 | return !(memPointer == it.memPointer); 44 | } 45 | 46 | private: 47 | T* memPointer; 48 | }; 49 | 50 | template 51 | class vector_iterator 52 | { 53 | public: 54 | vector_iterator(T* passedVal) : memPointer{passedVal} {}; 55 | vector_iterator(T* passedVal, size_t _push) : memPointer{passedVal + _push} {}; 56 | 57 | vector_iterator& operator++() 58 | { 59 | memPointer++; 60 | return *this; 61 | } 62 | 63 | vector_iterator operator++(int) 64 | { 65 | vector_iterator it = *this; 66 | ++(*this); 67 | return it; 68 | } 69 | 70 | vector_iterator& operator--() 71 | { 72 | memPointer--; 73 | return *this; 74 | } 75 | 76 | vector_iterator operator--(int) 77 | { 78 | vector_iterator it = *this; 79 | --(*this); 80 | return it; 81 | } 82 | 83 | operator const_vector_iterator() const 84 | { 85 | return const_vector_iterator(memPointer); 86 | } 87 | 88 | vector_iterator operator+(int off) const 89 | { 90 | return {memPointer + off}; 91 | } 92 | 93 | vector_iterator operator-(int off) const 94 | { 95 | return {memPointer - off}; 96 | } 97 | 98 | T* operator->() 99 | { 100 | return memPointer; 101 | } 102 | 103 | const T* operator->() const 104 | { 105 | return memPointer; 106 | } 107 | 108 | T& operator*() 109 | { 110 | return *(memPointer); 111 | } 112 | 113 | bool operator==(const vector_iterator& it) const 114 | { 115 | return (memPointer == it.memPointer); 116 | } 117 | 118 | bool operator!=(const vector_iterator& it) const 119 | { 120 | return !(memPointer == it.memPointer); 121 | } 122 | 123 | private: 124 | T* memPointer; 125 | }; 126 | 127 | 128 | 129 | template 130 | class reverse_vector_iterator 131 | { 132 | public: 133 | reverse_vector_iterator(T* passedVal) : memPointer{passedVal} {}; 134 | reverse_vector_iterator(T* passedVal, size_t _push) : memPointer{passedVal + _push} {}; 135 | 136 | reverse_vector_iterator& operator++() 137 | { 138 | memPointer--; 139 | return *this; 140 | } 141 | 142 | reverse_vector_iterator operator++(int) 143 | { 144 | reverse_vector_iterator it = *this; 145 | ++(*this); 146 | return it; 147 | } 148 | 149 | reverse_vector_iterator& operator--() 150 | { 151 | memPointer++; 152 | return *this; 153 | } 154 | 155 | reverse_vector_iterator operator--(int) 156 | { 157 | reverse_vector_iterator it = *this; 158 | --(*this); 159 | return it; 160 | } 161 | 162 | reverse_vector_iterator operator+(int off) const 163 | { 164 | return {memPointer - off}; 165 | } 166 | 167 | reverse_vector_iterator operator-(int off) const 168 | { 169 | return {memPointer + off}; 170 | } 171 | 172 | T* operator->() 173 | { 174 | return memPointer; 175 | } 176 | 177 | const T* operator->() const 178 | { 179 | return memPointer; 180 | } 181 | 182 | T& operator*() 183 | { 184 | return *(memPointer); 185 | } 186 | 187 | bool operator==(const reverse_vector_iterator& it) const 188 | { 189 | return (memPointer == it.memPointer); 190 | } 191 | 192 | bool operator!=(const reverse_vector_iterator& it) const 193 | { 194 | return !(memPointer == it.memPointer); 195 | } 196 | 197 | private: 198 | T* memPointer; 199 | }; --------------------------------------------------------------------------------