Merge branch 'TheAlgorithms:master' into temp

This commit is contained in:
futoid
2023-04-06 10:52:46 +05:30
committed by GitHub
8 changed files with 709 additions and 75 deletions

View File

@@ -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)

View 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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View 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 Kadanes 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;
}

View File

@@ -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}

View 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
View 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;
}