mirror of
https://github.com/TheAlgorithms/C-Plus-Plus.git
synced 2026-02-04 02:56:40 +08:00
Merge branch 'TheAlgorithms:master' into temp
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
* [Count Of Trailing Ciphers In Factorial N](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/count_of_trailing_ciphers_in_factorial_n.cpp)
|
||||
* [Find Non Repeating Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/find_non_repeating_number.cpp)
|
||||
* [Hamming Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/hamming_distance.cpp)
|
||||
* [Power Of 2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/power_of_2.cpp)
|
||||
* [Set Kth Bit](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/set_kth_bit.cpp)
|
||||
* [Travelling Salesman Using Bit Manipulation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/travelling_salesman_using_bit_manipulation.cpp)
|
||||
|
||||
@@ -107,6 +108,7 @@
|
||||
* [Longest Increasing Subsequence (Nlogn)](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/longest_increasing_subsequence_(nlogn).cpp)
|
||||
* [Longest Palindromic Subsequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/longest_palindromic_subsequence.cpp)
|
||||
* [Matrix Chain Multiplication](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/matrix_chain_multiplication.cpp)
|
||||
* [Maximum Circular Subarray](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/maximum_circular_subarray.cpp)
|
||||
* [Minimum Edit Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/minimum_edit_distance.cpp)
|
||||
* [Palindrome Partitioning](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/palindrome_partitioning.cpp)
|
||||
* [Partition Problem](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/partition_problem.cpp)
|
||||
@@ -168,6 +170,7 @@
|
||||
## Machine Learning
|
||||
* [A Star Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/a_star_search.cpp)
|
||||
* [Adaline Learning](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/adaline_learning.cpp)
|
||||
* [K Nearest Neighbors](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/k_nearest_neighbors.cpp)
|
||||
* [Kohonen Som Topology](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/kohonen_som_topology.cpp)
|
||||
* [Kohonen Som Trace](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/kohonen_som_trace.cpp)
|
||||
* [Neural Network](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/neural_network.cpp)
|
||||
@@ -186,6 +189,7 @@
|
||||
* [Check Prime](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/check_prime.cpp)
|
||||
* [Complex Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/complex_numbers.cpp)
|
||||
* [Double Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/double_factorial.cpp)
|
||||
* [Eratosthenes](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/eratosthenes.cpp)
|
||||
* [Eulers Totient Function](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/eulers_totient_function.cpp)
|
||||
* [Extended Euclid Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/extended_euclid_algorithm.cpp)
|
||||
* [Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/factorial.cpp)
|
||||
|
||||
74
bit_manipulation/power_of_2.cpp
Normal file
74
bit_manipulation/power_of_2.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Find whether a given number is power of 2]
|
||||
* (https://www.geeksforgeeks.org/program-to-find-whether-a-given-number-is-power-of-2/)
|
||||
* implementation
|
||||
*
|
||||
* @details
|
||||
* We are given a positive integer number. We need to check whether the number
|
||||
* is power of 2 or not.
|
||||
*
|
||||
* A binary number consists of two digits. They are 0 & 1. Digit 1 is known as
|
||||
* set bit in computer terms.
|
||||
* Worst Case Time Complexity: O(1)
|
||||
* Space complexity: O(1)
|
||||
* @author [Prafful Gupta](https://github.com/EcstaticPG-25811)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @brief The main function implements check for power of 2
|
||||
* @param n is the number who will be checked
|
||||
* @returns either true or false
|
||||
*/
|
||||
bool isPowerOfTwo(std ::int64_t n) { // int64_t is preferred over int so that
|
||||
// no Overflow can be there.
|
||||
|
||||
return n > 0 && !(n & n - 1); // If we subtract a power of 2 numbers by 1
|
||||
// then all unset bits after the only set bit become set; and the set bit
|
||||
// becomes unset.
|
||||
|
||||
// If a number n is a power of 2 then bitwise and of n-1 and n will be zero.
|
||||
// The expression n&(n-1) will not work when n is 0.
|
||||
// To handle this case also, our expression will become n& (!n&(n-1))
|
||||
}
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// n = 4 return true
|
||||
assert(bit_manipulation::isPowerOfTwo(4) == true);
|
||||
// n = 6 return false
|
||||
assert(bit_manipulation::isPowerOfTwo(6) == false);
|
||||
// n = 13 return false
|
||||
assert(bit_manipulation::isPowerOfTwo(13) == false);
|
||||
// n = 64 return true
|
||||
assert(bit_manipulation::isPowerOfTwo(64) == true);
|
||||
// n = 15 return false
|
||||
assert(bit_manipulation::isPowerOfTwo(15) == false);
|
||||
// n = 32 return true
|
||||
assert(bit_manipulation::isPowerOfTwo(32) == true);
|
||||
// n = 97 return false
|
||||
assert(bit_manipulation::isPowerOfTwo(97) == false);
|
||||
// n = 1024 return true
|
||||
assert(bit_manipulation::isPowerOfTwo(1024) == true);
|
||||
std::cout << "All test cases successfully passed!" << std::endl;
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -6,38 +6,52 @@
|
||||
* \warning This program is a poor implementation and does not utilize any of
|
||||
* the C++ STL features.
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <algorithm> /// for std::max
|
||||
#include <iostream> /// for std::cout
|
||||
#include <queue> /// for std::queue
|
||||
|
||||
typedef struct node {
|
||||
using node = struct node {
|
||||
int data;
|
||||
int height;
|
||||
struct node *left;
|
||||
struct node *right;
|
||||
} node;
|
||||
};
|
||||
|
||||
/** Create and return a new Node */
|
||||
/**
|
||||
* @brief creates and returns a new node
|
||||
* @param[in] data value stored in the node
|
||||
* @return newly created node
|
||||
*/
|
||||
node *createNode(int data) {
|
||||
node *nn = new node();
|
||||
nn->data = data;
|
||||
nn->height = 0;
|
||||
nn->left = NULL;
|
||||
nn->right = NULL;
|
||||
nn->left = nullptr;
|
||||
nn->right = nullptr;
|
||||
return nn;
|
||||
}
|
||||
|
||||
/** Returns height of tree */
|
||||
/**
|
||||
* @param[in] root the root of the tree
|
||||
* @return height of tree
|
||||
*/
|
||||
int height(node *root) {
|
||||
if (root == NULL)
|
||||
if (root == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return 1 + std::max(height(root->left), height(root->right));
|
||||
}
|
||||
|
||||
/** Returns difference between height of left and right subtree */
|
||||
/**
|
||||
* @param[in] root of the tree
|
||||
* @return difference between height of left and right subtree
|
||||
*/
|
||||
int getBalance(node *root) { return height(root->left) - height(root->right); }
|
||||
|
||||
/** Returns Node after Right Rotation */
|
||||
/**
|
||||
* @param root of the tree to be rotated
|
||||
* @return node after right rotation
|
||||
*/
|
||||
node *rightRotate(node *root) {
|
||||
node *t = root->left;
|
||||
node *u = t->right;
|
||||
@@ -46,7 +60,10 @@ node *rightRotate(node *root) {
|
||||
return t;
|
||||
}
|
||||
|
||||
/** Returns Node after Left Rotation */
|
||||
/**
|
||||
* @param root of the tree to be rotated
|
||||
* @return node after left rotation
|
||||
*/
|
||||
node *leftRotate(node *root) {
|
||||
node *t = root->right;
|
||||
node *u = t->left;
|
||||
@@ -55,55 +72,67 @@ node *leftRotate(node *root) {
|
||||
return t;
|
||||
}
|
||||
|
||||
/** Returns node with minimum value in the tree */
|
||||
/**
|
||||
* @param root of the tree
|
||||
* @returns node with minimum value in the tree
|
||||
*/
|
||||
node *minValue(node *root) {
|
||||
if (root->left == NULL)
|
||||
if (root->left == nullptr) {
|
||||
return root;
|
||||
}
|
||||
return minValue(root->left);
|
||||
}
|
||||
|
||||
/** Balanced Insertion */
|
||||
/**
|
||||
* @brief inserts a new element into AVL tree
|
||||
* @param root of the tree
|
||||
* @param[in] item the element to be insterted into the tree
|
||||
* @return root of the updated tree
|
||||
*/
|
||||
node *insert(node *root, int item) {
|
||||
node *nn = createNode(item);
|
||||
if (root == NULL)
|
||||
return nn;
|
||||
if (item < root->data)
|
||||
if (root == nullptr) {
|
||||
return createNode(item);
|
||||
}
|
||||
if (item < root->data) {
|
||||
root->left = insert(root->left, item);
|
||||
else
|
||||
} else {
|
||||
root->right = insert(root->right, item);
|
||||
}
|
||||
int b = getBalance(root);
|
||||
if (b > 1) {
|
||||
if (getBalance(root->left) < 0)
|
||||
if (getBalance(root->left) < 0) {
|
||||
root->left = leftRotate(root->left); // Left-Right Case
|
||||
return rightRotate(root); // Left-Left Case
|
||||
}
|
||||
return rightRotate(root); // Left-Left Case
|
||||
} else if (b < -1) {
|
||||
if (getBalance(root->right) > 0)
|
||||
if (getBalance(root->right) > 0) {
|
||||
root->right = rightRotate(root->right); // Right-Left Case
|
||||
return leftRotate(root); // Right-Right Case
|
||||
}
|
||||
return leftRotate(root); // Right-Right Case
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
/** Balanced Deletion */
|
||||
node *deleteNode(node *root, int key) {
|
||||
if (root == NULL)
|
||||
/**
|
||||
* @brief removes a given element from AVL tree
|
||||
* @param root of the tree
|
||||
* @param[in] element the element to be deleted from the tree
|
||||
* @return root of the updated tree
|
||||
*/
|
||||
node *deleteNode(node *root, int element) {
|
||||
if (root == nullptr) {
|
||||
return root;
|
||||
if (key < root->data)
|
||||
root->left = deleteNode(root->left, key);
|
||||
else if (key > root->data)
|
||||
root->right = deleteNode(root->right, key);
|
||||
}
|
||||
if (element < root->data) {
|
||||
root->left = deleteNode(root->left, element);
|
||||
} else if (element > root->data) {
|
||||
root->right = deleteNode(root->right, element);
|
||||
|
||||
else {
|
||||
} else {
|
||||
// Node to be deleted is leaf node or have only one Child
|
||||
if (!root->right) {
|
||||
node *temp = root->left;
|
||||
delete (root);
|
||||
root = NULL;
|
||||
return temp;
|
||||
} else if (!root->left) {
|
||||
node *temp = root->right;
|
||||
delete (root);
|
||||
root = NULL;
|
||||
if (!root->right || !root->left) {
|
||||
node *temp = !root->right ? root->left : root->right;
|
||||
delete root;
|
||||
return temp;
|
||||
}
|
||||
// Node to be deleted have both left and right subtrees
|
||||
@@ -115,7 +144,22 @@ node *deleteNode(node *root, int key) {
|
||||
return root;
|
||||
}
|
||||
|
||||
/** LevelOrder (Breadth First Search) */
|
||||
/**
|
||||
* @brief calls delete on every node
|
||||
* @param root of the tree
|
||||
*/
|
||||
void deleteAllNodes(const node *const root) {
|
||||
if (root) {
|
||||
deleteAllNodes(root->left);
|
||||
deleteAllNodes(root->right);
|
||||
delete root;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief prints given tree in the LevelOrder
|
||||
* @param[in] root of the tree
|
||||
*/
|
||||
void levelOrder(node *root) {
|
||||
std::queue<node *> q;
|
||||
q.push(root);
|
||||
@@ -123,18 +167,23 @@ void levelOrder(node *root) {
|
||||
root = q.front();
|
||||
std::cout << root->data << " ";
|
||||
q.pop();
|
||||
if (root->left)
|
||||
if (root->left) {
|
||||
q.push(root->left);
|
||||
if (root->right)
|
||||
}
|
||||
if (root->right) {
|
||||
q.push(root->right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
// Testing AVL Tree
|
||||
node *root = NULL;
|
||||
int i;
|
||||
node *root = nullptr;
|
||||
int i = 0;
|
||||
for (i = 1; i <= 7; i++) root = insert(root, i);
|
||||
std::cout << "LevelOrder: ";
|
||||
levelOrder(root);
|
||||
@@ -144,5 +193,6 @@ int main() {
|
||||
root = deleteNode(root, 4); // Deletin key with value 4
|
||||
std::cout << "\nLevelOrder: ";
|
||||
levelOrder(root);
|
||||
deleteAllNodes(root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for I/O operations
|
||||
#include <memory> /// for dynamic memory
|
||||
#include <new> /// for managing dynamic storage
|
||||
|
||||
/**
|
||||
@@ -43,29 +42,47 @@ namespace linked_list {
|
||||
class Node {
|
||||
public:
|
||||
int32_t val; /// value of the current link
|
||||
Node *next; /// pointer to the next value on the list
|
||||
Node* next; /// pointer to the next value on the list
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief creates a deep copy of a list starting at the input node
|
||||
* @param[in] node pointer to the first node/head of the list to be copied
|
||||
* @return pointer to the first node/head of the copied list or nullptr
|
||||
*/
|
||||
Node* copy_all_nodes(const Node* const node) {
|
||||
if (node) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
|
||||
Node* res = new Node();
|
||||
res->val = node->val;
|
||||
res->next = copy_all_nodes(node->next);
|
||||
return res;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list class containing a sequence of links
|
||||
*/
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
|
||||
class list {
|
||||
private:
|
||||
Node *head; // link before the actual first element
|
||||
Node* head = nullptr; // link before the actual first element
|
||||
void delete_all_nodes();
|
||||
void copy_all_nodes_from_list(const list& other);
|
||||
|
||||
public:
|
||||
/**
|
||||
* List constructor. Initializes the first link.
|
||||
*/
|
||||
list() {
|
||||
head = nullptr; // Initialize the first link
|
||||
}
|
||||
bool isEmpty();
|
||||
bool isEmpty() const;
|
||||
void insert(int32_t new_elem);
|
||||
void reverseList();
|
||||
void display();
|
||||
int32_t top();
|
||||
int32_t last();
|
||||
int32_t traverse(int32_t index);
|
||||
void display() const;
|
||||
int32_t top() const;
|
||||
int32_t last() const;
|
||||
int32_t traverse(int32_t index) const;
|
||||
~list();
|
||||
list() = default;
|
||||
list(const list& other);
|
||||
list& operator=(const list& other);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -73,7 +90,7 @@ class list {
|
||||
* @returns true if the list is empty
|
||||
* @returns false if the list is not empty
|
||||
*/
|
||||
bool list::isEmpty() { return head == nullptr; }
|
||||
bool list::isEmpty() const { return head == nullptr; }
|
||||
|
||||
/**
|
||||
* @brief Utility function that adds a new element at the end of the list
|
||||
@@ -81,8 +98,9 @@ bool list::isEmpty() { return head == nullptr; }
|
||||
*/
|
||||
void list::insert(int32_t n) {
|
||||
try {
|
||||
Node *new_node = new Node();
|
||||
Node *temp = nullptr;
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
|
||||
Node* new_node = new Node();
|
||||
Node* temp = nullptr;
|
||||
new_node->val = n;
|
||||
new_node->next = nullptr;
|
||||
if (isEmpty()) {
|
||||
@@ -94,7 +112,7 @@ void list::insert(int32_t n) {
|
||||
}
|
||||
temp->next = new_node;
|
||||
}
|
||||
} catch (std::bad_alloc &exception) {
|
||||
} catch (std::bad_alloc& exception) {
|
||||
std::cerr << "bad_alloc detected: " << exception.what() << "\n";
|
||||
}
|
||||
}
|
||||
@@ -105,8 +123,9 @@ void list::insert(int32_t n) {
|
||||
* @returns void
|
||||
*/
|
||||
void list::reverseList() {
|
||||
Node *curr = head;
|
||||
Node *prev = nullptr, *next_node = nullptr;
|
||||
Node* curr = head;
|
||||
Node* prev = nullptr;
|
||||
Node* next_node = nullptr;
|
||||
while (curr != nullptr) {
|
||||
next_node = curr->next;
|
||||
curr->next = prev;
|
||||
@@ -120,7 +139,7 @@ void list::reverseList() {
|
||||
* @brief Utility function to find the top element of the list
|
||||
* @returns the top element of the list
|
||||
*/
|
||||
int32_t list::top() {
|
||||
int32_t list::top() const {
|
||||
if (!isEmpty()) {
|
||||
return head->val;
|
||||
} else {
|
||||
@@ -131,9 +150,9 @@ int32_t list::top() {
|
||||
* @brief Utility function to find the last element of the list
|
||||
* @returns the last element of the list
|
||||
*/
|
||||
int32_t list::last() {
|
||||
int32_t list::last() const {
|
||||
if (!isEmpty()) {
|
||||
Node *t = head;
|
||||
Node* t = head;
|
||||
while (t->next != nullptr) {
|
||||
t = t->next;
|
||||
}
|
||||
@@ -146,8 +165,8 @@ int32_t list::last() {
|
||||
* @brief Utility function to find the i th element of the list
|
||||
* @returns the i th element of the list
|
||||
*/
|
||||
int32_t list::traverse(int32_t index) {
|
||||
Node *current = head;
|
||||
int32_t list::traverse(int32_t index) const {
|
||||
Node* current = head;
|
||||
|
||||
int count = 0;
|
||||
while (current != nullptr) {
|
||||
@@ -163,6 +182,42 @@ int32_t list::traverse(int32_t index) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief calls delete operator on every node in the represented list
|
||||
*/
|
||||
void list::delete_all_nodes() {
|
||||
while (head != nullptr) {
|
||||
const auto tmp_node = head->next;
|
||||
delete head;
|
||||
head = tmp_node;
|
||||
}
|
||||
}
|
||||
|
||||
list::~list() { delete_all_nodes(); }
|
||||
|
||||
void list::copy_all_nodes_from_list(const list& other) {
|
||||
assert(isEmpty());
|
||||
head = copy_all_nodes(other.head);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief copy constructor creating a deep copy of every node of the input
|
||||
*/
|
||||
list::list(const list& other) { copy_all_nodes_from_list(other); }
|
||||
|
||||
/**
|
||||
* @brief assignment operator creating a deep copy of every node of the input
|
||||
*/
|
||||
list& list::operator=(const list& other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
delete_all_nodes();
|
||||
|
||||
copy_all_nodes_from_list(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace linked_list
|
||||
} // namespace data_structures
|
||||
|
||||
@@ -194,11 +249,58 @@ static void test() {
|
||||
std::cout << "All tests have successfully passed!" << std::endl;
|
||||
}
|
||||
|
||||
void test_copy_constructor() {
|
||||
data_structures::linked_list::list L;
|
||||
L.insert(10);
|
||||
L.insert(20);
|
||||
L.insert(30);
|
||||
data_structures::linked_list::list otherList(L);
|
||||
otherList.insert(40);
|
||||
|
||||
L.insert(400);
|
||||
|
||||
assert(L.top() == 10);
|
||||
assert(otherList.top() == 10);
|
||||
assert(L.traverse(1) == 20);
|
||||
assert(otherList.traverse(1) == 20);
|
||||
|
||||
assert(L.traverse(2) == 30);
|
||||
assert(otherList.traverse(2) == 30);
|
||||
|
||||
assert(L.last() == 400);
|
||||
assert(otherList.last() == 40);
|
||||
}
|
||||
|
||||
void test_assignment_operator() {
|
||||
data_structures::linked_list::list L;
|
||||
data_structures::linked_list::list otherList;
|
||||
L.insert(10);
|
||||
L.insert(20);
|
||||
L.insert(30);
|
||||
otherList = L;
|
||||
|
||||
otherList.insert(40);
|
||||
L.insert(400);
|
||||
|
||||
assert(L.top() == 10);
|
||||
assert(otherList.top() == 10);
|
||||
assert(L.traverse(1) == 20);
|
||||
assert(otherList.traverse(1) == 20);
|
||||
|
||||
assert(L.traverse(2) == 30);
|
||||
assert(otherList.traverse(2) == 30);
|
||||
|
||||
assert(L.last() == 400);
|
||||
assert(otherList.last() == 40);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
test_copy_constructor();
|
||||
test_assignment_operator();
|
||||
return 0;
|
||||
}
|
||||
|
||||
90
dynamic_programming/maximum_circular_subarray.cpp
Normal file
90
dynamic_programming/maximum_circular_subarray.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief C++ program for maximum contiguous circular sum problem using [Kadane's Algorithm](https://en.wikipedia.org/wiki/Maximum_subarray_problem)
|
||||
* @details
|
||||
* The idea is to modify Kadane’s algorithm to find a minimum contiguous subarray sum and the maximum contiguous subarray sum,
|
||||
* then check for the maximum value between the max_value and the value left after subtracting min_value from the total sum.
|
||||
* For more information, check [Geeks For Geeks](https://www.geeksforgeeks.org/maximum-contiguous-circular-sum/) explanation page.
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @brief returns the maximum contiguous circular sum of an array
|
||||
*
|
||||
* @param arr is the array/vector
|
||||
* @return int which is the maximum sum
|
||||
*/
|
||||
int maxCircularSum(std::vector<int>& arr)
|
||||
{
|
||||
// Edge Case
|
||||
if (arr.size() == 1)
|
||||
return arr[0];
|
||||
|
||||
// Sum variable which stores total sum of the array.
|
||||
int sum = 0;
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
sum += arr[i];
|
||||
}
|
||||
|
||||
// Every variable stores first value of the array.
|
||||
int current_max = arr[0], max_so_far = arr[0], current_min = arr[0], min_so_far = arr[0];
|
||||
|
||||
// Concept of Kadane's Algorithm
|
||||
for (int i = 1; i < arr.size(); i++) {
|
||||
// Kadane's Algorithm to find Maximum subarray sum.
|
||||
current_max = std::max(current_max + arr[i], arr[i]);
|
||||
max_so_far = std::max(max_so_far, current_max);
|
||||
|
||||
// Kadane's Algorithm to find Minimum subarray sum.
|
||||
current_min = std::min(current_min + arr[i], arr[i]);
|
||||
min_so_far = std::min(min_so_far, current_min);
|
||||
}
|
||||
|
||||
if (min_so_far == sum)
|
||||
return max_so_far;
|
||||
|
||||
// Return the maximum value
|
||||
return std::max(max_so_far, sum - min_so_far);
|
||||
}
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementation
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Description of the test
|
||||
// Input: arr[] = {8, -8, 9, -9, 10, -11, 12}
|
||||
// Output: 22
|
||||
// Explanation: Subarray 12, 8, -8, 9, -9, 10 gives the maximum sum, that is 22.
|
||||
|
||||
int n = 7; // size of the array
|
||||
std::vector<int> arr = {8, -8, 9, -9, 10, -11, 12};
|
||||
assert(dynamic_programming::maxCircularSum(arr) == 22); // this ensures that the algorithm works as expected
|
||||
|
||||
arr = {8, -8, 10, -9, 10, -11, 12};
|
||||
assert(dynamic_programming::maxCircularSum(arr) == 23);
|
||||
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @param argc commandline argument count (ignored)
|
||||
* @param argv commandline array of arguments (ignored)
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -6,8 +6,8 @@ if(OpenGL_FOUND)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add (
|
||||
FREEGLUT-PRJ
|
||||
URL https://github.com/FreeGLUTProject/freeglut/releases/download/v3.2.1/freeglut-3.2.1.tar.gz
|
||||
URL_MD5 cd5c670c1086358598a6d4a9d166949d
|
||||
URL https://github.com/FreeGLUTProject/freeglut/releases/download/v3.2.2/freeglut-3.2.2.tar.gz
|
||||
URL_MD5 485c1976165315fc42c0b0a1802816d9
|
||||
CMAKE_GENERATOR ${CMAKE_GENERATOR}
|
||||
CMAKE_GENERATOR_TOOLSET ${CMAKE_GENERATOR_TOOLSET}
|
||||
CMAKE_GENERATOR_PLATFORM ${CMAKE_GENERATOR_PLATFORM}
|
||||
|
||||
196
machine_learning/k_nearest_neighbors.cpp
Normal file
196
machine_learning/k_nearest_neighbors.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [K-Nearest Neighbors algorithm]
|
||||
* (https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm).
|
||||
* @author [Luiz Carlos Cosmi Filho](https://github.com/luizcarloscf)
|
||||
* @details K-nearest neighbors algorithm, also known as KNN or k-NN, is a
|
||||
* supervised learning classifier, which uses proximity to make classifications.
|
||||
* This implementantion uses the Euclidean Distance as distance metric to find
|
||||
* the K-nearest neighbors.
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::transform and std::sort
|
||||
#include <cassert> /// for assert
|
||||
#include <cmath> /// for std::pow and std::sqrt
|
||||
#include <iostream> /// for std::cout
|
||||
#include <numeric> /// for std::accumulate
|
||||
#include <unordered_map> /// for std::unordered_map
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace machine_learning
|
||||
* @brief Machine learning algorithms
|
||||
*/
|
||||
namespace machine_learning {
|
||||
|
||||
/**
|
||||
* @namespace k_nearest_neighbors
|
||||
* @brief Functions for the [K-Nearest Neighbors algorithm]
|
||||
* (https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm) implementation
|
||||
*/
|
||||
namespace k_nearest_neighbors {
|
||||
|
||||
/**
|
||||
* @brief Compute the Euclidean distance between two vectors.
|
||||
*
|
||||
* @tparam T typename of the vector
|
||||
* @param a first unidimentional vector
|
||||
* @param b second unidimentional vector
|
||||
* @return double scalar representing the Euclidean distance between provided
|
||||
* vectors
|
||||
*/
|
||||
template <typename T>
|
||||
double euclidean_distance(const std::vector<T>& a, const std::vector<T>& b) {
|
||||
std::vector<double> aux;
|
||||
std::transform(a.begin(), a.end(), b.begin(), std::back_inserter(aux),
|
||||
[](T x1, T x2) { return std::pow((x1 - x2), 2); });
|
||||
aux.shrink_to_fit();
|
||||
return std::sqrt(std::accumulate(aux.begin(), aux.end(), 0.0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief K-Nearest Neighbors (Knn) class using Euclidean distance as
|
||||
* distance metric.
|
||||
*/
|
||||
class Knn {
|
||||
private:
|
||||
std::vector<std::vector<double>> X_{}; ///< attributes vector
|
||||
std::vector<int> Y_{}; ///< labels vector
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Knn object.
|
||||
* @details Using lazy-learning approch, just holds in memory the dataset.
|
||||
* @param X attributes vector
|
||||
* @param Y labels vector
|
||||
*/
|
||||
explicit Knn(std::vector<std::vector<double>>& X, std::vector<int>& Y)
|
||||
: X_(X), Y_(Y){};
|
||||
|
||||
/**
|
||||
* Copy Constructor for class Knn.
|
||||
*
|
||||
* @param model instance of class to be copied
|
||||
*/
|
||||
Knn(const Knn& model) = default;
|
||||
|
||||
/**
|
||||
* Copy assignment operator for class Knn
|
||||
*/
|
||||
Knn& operator=(const Knn& model) = default;
|
||||
|
||||
/**
|
||||
* Move constructor for class Knn
|
||||
*/
|
||||
Knn(Knn&&) = default;
|
||||
|
||||
/**
|
||||
* Move assignment operator for class Knn
|
||||
*/
|
||||
Knn& operator=(Knn&&) = default;
|
||||
|
||||
/**
|
||||
* @brief Destroy the Knn object
|
||||
*/
|
||||
~Knn() = default;
|
||||
|
||||
/**
|
||||
* @brief Classify sample.
|
||||
* @param sample sample
|
||||
* @param k number of neighbors
|
||||
* @return int label of most frequent neighbors
|
||||
*/
|
||||
int predict(std::vector<double>& sample, int k) {
|
||||
std::vector<int> neighbors;
|
||||
std::vector<std::pair<double, int>> distances;
|
||||
for (size_t i = 0; i < this->X_.size(); ++i) {
|
||||
auto current = this->X_.at(i);
|
||||
auto label = this->Y_.at(i);
|
||||
auto distance = euclidean_distance(current, sample);
|
||||
distances.emplace_back(distance, label);
|
||||
}
|
||||
std::sort(distances.begin(), distances.end());
|
||||
for (int i = 0; i < k; i++) {
|
||||
auto label = distances.at(i).second;
|
||||
neighbors.push_back(label);
|
||||
}
|
||||
std::unordered_map<int, int> frequency;
|
||||
for (auto neighbor : neighbors) {
|
||||
++frequency[neighbor];
|
||||
}
|
||||
std::pair<int, int> predicted;
|
||||
predicted.first = -1;
|
||||
predicted.second = -1;
|
||||
for (auto& kv : frequency) {
|
||||
if (kv.second > predicted.second) {
|
||||
predicted.second = kv.second;
|
||||
predicted.first = kv.first;
|
||||
}
|
||||
}
|
||||
return predicted.first;
|
||||
}
|
||||
};
|
||||
} // namespace k_nearest_neighbors
|
||||
} // namespace machine_learning
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::cout << "------- Test 1 -------" << std::endl;
|
||||
std::vector<std::vector<double>> X1 = {{0.0, 0.0}, {0.25, 0.25},
|
||||
{0.0, 0.5}, {0.5, 0.5},
|
||||
{1.0, 0.5}, {1.0, 1.0}};
|
||||
std::vector<int> Y1 = {1, 1, 1, 1, 2, 2};
|
||||
auto model1 = machine_learning::k_nearest_neighbors::Knn(X1, Y1);
|
||||
std::vector<double> sample1 = {1.2, 1.2};
|
||||
std::vector<double> sample2 = {0.1, 0.1};
|
||||
std::vector<double> sample3 = {0.1, 0.5};
|
||||
std::vector<double> sample4 = {1.0, 0.75};
|
||||
assert(model1.predict(sample1, 2) == 2);
|
||||
assert(model1.predict(sample2, 2) == 1);
|
||||
assert(model1.predict(sample3, 2) == 1);
|
||||
assert(model1.predict(sample4, 2) == 2);
|
||||
std::cout << "... Passed" << std::endl;
|
||||
std::cout << "------- Test 2 -------" << std::endl;
|
||||
std::vector<std::vector<double>> X2 = {
|
||||
{0.0, 0.0, 0.0}, {0.25, 0.25, 0.0}, {0.0, 0.5, 0.0}, {0.5, 0.5, 0.0},
|
||||
{1.0, 0.5, 0.0}, {1.0, 1.0, 0.0}, {1.0, 1.0, 1.0}, {1.5, 1.5, 1.0}};
|
||||
std::vector<int> Y2 = {1, 1, 1, 1, 2, 2, 3, 3};
|
||||
auto model2 = machine_learning::k_nearest_neighbors::Knn(X2, Y2);
|
||||
std::vector<double> sample5 = {1.2, 1.2, 0.0};
|
||||
std::vector<double> sample6 = {0.1, 0.1, 0.0};
|
||||
std::vector<double> sample7 = {0.1, 0.5, 0.0};
|
||||
std::vector<double> sample8 = {1.0, 0.75, 1.0};
|
||||
assert(model2.predict(sample5, 2) == 2);
|
||||
assert(model2.predict(sample6, 2) == 1);
|
||||
assert(model2.predict(sample7, 2) == 1);
|
||||
assert(model2.predict(sample8, 2) == 3);
|
||||
std::cout << "... Passed" << std::endl;
|
||||
std::cout << "------- Test 3 -------" << std::endl;
|
||||
std::vector<std::vector<double>> X3 = {{0.0}, {1.0}, {2.0}, {3.0},
|
||||
{4.0}, {5.0}, {6.0}, {7.0}};
|
||||
std::vector<int> Y3 = {1, 1, 1, 1, 2, 2, 2, 2};
|
||||
auto model3 = machine_learning::k_nearest_neighbors::Knn(X3, Y3);
|
||||
std::vector<double> sample9 = {0.5};
|
||||
std::vector<double> sample10 = {2.9};
|
||||
std::vector<double> sample11 = {5.5};
|
||||
std::vector<double> sample12 = {7.5};
|
||||
assert(model3.predict(sample9, 3) == 1);
|
||||
assert(model3.predict(sample10, 3) == 1);
|
||||
assert(model3.predict(sample11, 3) == 2);
|
||||
assert(model3.predict(sample12, 3) == 2);
|
||||
std::cout << "... Passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @param argc commandline argument count (ignored)
|
||||
* @param argv commandline array of arguments (ignored)
|
||||
* @return int 0 on exit
|
||||
*/
|
||||
int main(int argc, char* argv[]) {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
118
math/eratosthenes.cpp
Normal file
118
math/eratosthenes.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [The Sieve of
|
||||
* Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes)
|
||||
* @details
|
||||
* Store an array of booleans where a true value indicates that it's index is
|
||||
* prime. For all the values in the array starting from 2 which we know is
|
||||
* prime, we walk the array in multiples of the current outer value setting them
|
||||
* to not prime. If we remove all multiples of a value as we see it, we'll be
|
||||
* left with just primes.
|
||||
*
|
||||
* Pass "print" as a command line arg to see the generated list of primes
|
||||
* @author [Keval Kapdee](https://github.com/thechubbypanda)
|
||||
*/
|
||||
|
||||
#include <cassert> /// For assert
|
||||
#include <chrono> /// For timing the sieve
|
||||
#include <iostream> /// For IO operations
|
||||
#include <string> /// For string handling
|
||||
#include <vector> /// For std::vector
|
||||
|
||||
/**
|
||||
* @namespace math
|
||||
* @brief Mathematical algorithms
|
||||
*/
|
||||
namespace math {
|
||||
/**
|
||||
* @brief Performs the sieve
|
||||
* @param vec Array of bools, all initialised to true, where the number of
|
||||
* elements is the highest number we wish to check for primeness
|
||||
* @returns void
|
||||
*/
|
||||
void sieve(std::vector<bool> *vec) {
|
||||
(*vec)[0] = false;
|
||||
(*vec)[1] = false;
|
||||
|
||||
// The sieve sets values to false as they are found not prime
|
||||
for (uint64_t n = 2; n < vec->size(); n++) {
|
||||
for (uint64_t multiple = n << 1; multiple < vec->size();
|
||||
multiple += n) {
|
||||
(*vec)[multiple] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prints all the indexes of true values in the passed std::vector
|
||||
* @param primes The vector that has been passed through `sieve(...)`
|
||||
* @returns void
|
||||
*/
|
||||
void print_primes(std::vector<bool> const &primes) {
|
||||
for (uint64_t i = 0; i < primes.size(); i++) {
|
||||
if (primes[i]) {
|
||||
std::cout << i << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace math
|
||||
|
||||
/**
|
||||
* @brief Self-tests the sieve function for major inconsistencies
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
auto primes = std::vector<bool>(10, true);
|
||||
math::sieve(&primes);
|
||||
assert(primes[0] == false);
|
||||
assert(primes[1] == false);
|
||||
assert(primes[2] == true);
|
||||
assert(primes[3] == true);
|
||||
assert(primes[4] == false);
|
||||
assert(primes[5] == true);
|
||||
assert(primes[6] == false);
|
||||
assert(primes[7] == true);
|
||||
assert(primes[8] == false);
|
||||
assert(primes[9] == false);
|
||||
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @param argc commandline argument count
|
||||
* @param argv commandline array of arguments
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
test(); // run self-test implementations
|
||||
|
||||
// The largest prime we will check for
|
||||
auto max = 10000;
|
||||
|
||||
// Store a boolean for every number which states if that index is prime or
|
||||
// not
|
||||
auto primes = std::vector<bool>(max, true);
|
||||
|
||||
// Store the algorithm start time
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Run the sieve
|
||||
math::sieve(&primes);
|
||||
|
||||
// Time difference calculation
|
||||
auto time = std::chrono::duration_cast<
|
||||
std::chrono::duration<double, std::ratio<1>>>(
|
||||
std::chrono::high_resolution_clock::now() - start)
|
||||
.count();
|
||||
|
||||
// Print the primes if we see that "print" was passed as an arg
|
||||
if (argc > 1 && argv[1] == std::string("print")) {
|
||||
math::print_primes(primes);
|
||||
}
|
||||
|
||||
// Print the time taken we found earlier
|
||||
std::cout << "Time taken: " << time << " seconds" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user