mirror of
https://hub.njuu.cf/TheAlgorithms/C-Plus-Plus.git
synced 2023-10-11 13:05:55 +08:00
Merge branch 'master' into master
This commit is contained in:
commit
d1cb53379e
@ -29,6 +29,9 @@
|
||||
* [Vigenere Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/vigenere_cipher.cpp)
|
||||
* [Xor Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/xor_cipher.cpp)
|
||||
|
||||
## Cpu Scheduling Algorithms
|
||||
* [Fcfs Scheduling](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/cpu_scheduling_algorithms/fcfs_scheduling.cpp)
|
||||
|
||||
## Data Structures
|
||||
* [Avltree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/avltree.cpp)
|
||||
* [Binary Search Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/binary_search_tree.cpp)
|
||||
@ -179,6 +182,7 @@
|
||||
* [Gcd Of N Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/gcd_of_n_numbers.cpp)
|
||||
* [Gcd Recursive Euclidean](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/gcd_recursive_euclidean.cpp)
|
||||
* [Integral Approximation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/integral_approximation.cpp)
|
||||
* [Integral Approximation2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/integral_approximation2.cpp)
|
||||
* [Inv Sqrt](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/inv_sqrt.cpp)
|
||||
* [Large Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/large_factorial.cpp)
|
||||
* [Large Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/large_number.h)
|
||||
@ -245,9 +249,11 @@
|
||||
* [Decimal To Binary](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_binary.cpp)
|
||||
* [Decimal To Hexadecimal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_hexadecimal.cpp)
|
||||
* [Decimal To Roman Numeral](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/decimal_to_roman_numeral.cpp)
|
||||
* [Easter](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/easter.cpp)
|
||||
* [Fast Integer Input](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/fast_integer_input.cpp)
|
||||
* [Happy Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/happy_number.cpp)
|
||||
* [Iterative Tree Traversals](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/iterative_tree_traversals.cpp)
|
||||
* [Kadanes3](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/kadanes3.cpp)
|
||||
* [Lru Cache](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/lru_cache.cpp)
|
||||
* [Matrix Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/matrix_exponentiation.cpp)
|
||||
* [Palindrome Of Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/others/palindrome_of_number.cpp)
|
||||
@ -266,6 +272,7 @@
|
||||
* [Addition Rule](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/addition_rule.cpp)
|
||||
* [Bayes Theorem](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/bayes_theorem.cpp)
|
||||
* [Binomial Dist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/binomial_dist.cpp)
|
||||
* [Geometric Dist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/geometric_dist.cpp)
|
||||
* [Poisson Dist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/poisson_dist.cpp)
|
||||
* [Windowed Median](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/probability/windowed_median.cpp)
|
||||
|
||||
@ -274,6 +281,7 @@
|
||||
* [Heavy Light Decomposition](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/heavy_light_decomposition.cpp)
|
||||
* [Mo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/mo.cpp)
|
||||
* [Persistent Seg Tree Lazy Prop](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/persistent_seg_tree_lazy_prop.cpp)
|
||||
* [Prefix Sum Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/prefix_sum_array.cpp)
|
||||
* [Segtree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/segtree.cpp)
|
||||
* [Sparse Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/sparse_table.cpp)
|
||||
|
||||
|
@ -1,26 +1,21 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation to [count sets
|
||||
* bits](https://www.geeksforgeeks.org/count-set-bits-in-an-integer/) in an
|
||||
* @brief Implementation to [count number of set bits of a number]
|
||||
* (https://www.geeksforgeeks.org/count-set-bits-in-an-integer/) in an
|
||||
* integer.
|
||||
*
|
||||
* @details
|
||||
* We are given an integer number. Let’s say, number. The task is to first
|
||||
* calculate the binary digit of a number and then calculate the total set bits
|
||||
* of a number.
|
||||
* We are given an integer number. We need to calculate the number of set bits in it.
|
||||
*
|
||||
* Set bits in a binary number is represented by 1. Whenever we calculate the
|
||||
* binary number of an integer value it is formed as the combination of 0’s and
|
||||
* 1’s. So digit 1 is known as a set bit in computer terms.
|
||||
* Time Complexity: O(log n)
|
||||
* 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(log n)
|
||||
* Space complexity: O(1)
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
* @author [Prashant Thakur](https://github.com/prashant-th18)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for io operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
#include <iostream> /// for IO operations
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
@ -36,24 +31,27 @@ namespace count_of_set_bits {
|
||||
/**
|
||||
* @brief The main function implements set bit count
|
||||
* @param n is the number whose set bit will be counted
|
||||
* @returns the count of the number set bit in the binary representation of `n`
|
||||
* @returns total number of set-bits in the binary representation of number `n`
|
||||
*/
|
||||
std::uint64_t countSetBits(int n) {
|
||||
int count = 0; // "count" variable is used to count number of 1's in binary
|
||||
// representation of the number
|
||||
while (n != 0) {
|
||||
count += n & 1;
|
||||
n = n >> 1; // n=n/2
|
||||
std::uint64_t countSetBits(std :: int64_t n) { // int64_t is preferred over int so that
|
||||
// no Overflow can be there.
|
||||
|
||||
int count = 0; // "count" variable is used to count number of set-bits('1') in
|
||||
// binary representation of number 'n'
|
||||
while (n != 0)
|
||||
{
|
||||
++count;
|
||||
n = (n & (n - 1));
|
||||
}
|
||||
return count;
|
||||
// Why this algorithm is better than the standard one?
|
||||
// Because this algorithm runs the same number of times as the number of
|
||||
// set-bits in it. Means if my number is having "3" set bits, then this while loop
|
||||
// will run only "3" times!!
|
||||
}
|
||||
} // namespace count_of_set_bits
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// n = 4 return 1
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(4) == 1);
|
||||
@ -67,9 +65,12 @@ static void test() {
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(15) == 4);
|
||||
// n = 25 return 3
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(25) == 3);
|
||||
// n = 97 return 3
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(97) == 3);
|
||||
// n = 31 return 5
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(31) == 5);
|
||||
std::cout << "All test cases successfully passed!" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
|
290
cpu_scheduling_algorithms/fcfs_scheduling.cpp
Normal file
290
cpu_scheduling_algorithms/fcfs_scheduling.cpp
Normal file
@ -0,0 +1,290 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of FCFS CPU scheduling algorithm
|
||||
* @details
|
||||
* FCFS is a non-preemptive CPU scheduling algorithm in which whichever process
|
||||
* arrives first, gets executed first. If two or more processes arrive
|
||||
* simultaneously, the process with smaller process ID gets executed first.
|
||||
* @link https://bit.ly/3ABNXOC
|
||||
* @author [Pratyush Vatsa](https://github.com/Pratyush219)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for sorting
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdlib> /// random number generation
|
||||
#include <ctime> /// for time
|
||||
#include <iomanip> /// for formatting the output
|
||||
#include <iostream> /// for IO operations
|
||||
#include <queue> /// for std::priority_queue
|
||||
#include <unordered_set> /// for std::unordered_set
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::get;
|
||||
using std::left;
|
||||
using std::make_tuple;
|
||||
using std::priority_queue;
|
||||
using std::rand;
|
||||
using std::srand;
|
||||
using std::tuple;
|
||||
using std::unordered_set;
|
||||
using std::vector;
|
||||
/**
|
||||
* @brief Comparator function for sorting a vector
|
||||
* @tparam S Data type of Process ID
|
||||
* @tparam T Data type of Arrival time
|
||||
* @tparam E Data type of Burst time
|
||||
* @param t1 First tuple
|
||||
* @param t2 Second tuple
|
||||
* @returns true if t1 and t2 are in the CORRECT order
|
||||
* @returns false if t1 and t2 are in the INCORRECT order
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
bool sortcol(tuple<S, T, E>& t1, tuple<S, T, E>& t2) {
|
||||
if (get<1>(t1) < get<1>(t2)) {
|
||||
return true;
|
||||
} else if (get<1>(t1) == get<1>(t2) && get<0>(t1) < get<0>(t2)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Compare
|
||||
* @brief Comparator class for priority queue
|
||||
* @tparam S Data type of Process ID
|
||||
* @tparam T Data type of Arrival time
|
||||
* @tparam E Data type of Burst time
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
class Compare {
|
||||
public:
|
||||
/**
|
||||
* @param t1 First tuple
|
||||
* @param t2 Second tuple
|
||||
* @brief A comparator function that checks whether to swap the two tuples
|
||||
* or not.
|
||||
* @link Refer to
|
||||
* https://www.geeksforgeeks.org/comparator-class-in-c-with-examples/ for
|
||||
* detailed description of comparator
|
||||
* @returns true if the tuples SHOULD be swapped
|
||||
* @returns false if the tuples SHOULDN'T be swapped
|
||||
*/
|
||||
bool operator()(tuple<S, T, E, double, double, double>& t1,
|
||||
tuple<S, T, E, double, double, double>& t2) {
|
||||
// Compare arrival times
|
||||
if (get<1>(t2) < get<1>(t1)) {
|
||||
return true;
|
||||
}
|
||||
// If arrival times are same, then compare Process IDs
|
||||
else if (get<1>(t2) == get<1>(t1)) {
|
||||
return get<0>(t2) < get<0>(t1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class FCFS
|
||||
* @brief Class which implements the FCFS scheduling algorithm
|
||||
* @tparam S Data type of Process ID
|
||||
* @tparam T Data type of Arrival time
|
||||
* @tparam E Data type of Burst time
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
class FCFS {
|
||||
/**
|
||||
* Priority queue of schedules(stored as tuples) of processes.
|
||||
* In each tuple
|
||||
* 1st element: Process ID
|
||||
* 2nd element: Arrival Time
|
||||
* 3rd element: Burst time
|
||||
* 4th element: Completion time
|
||||
* 5th element: Turnaround time
|
||||
* 6th element: Waiting time
|
||||
*/
|
||||
priority_queue<tuple<S, T, E, double, double, double>,
|
||||
vector<tuple<S, T, E, double, double, double>>,
|
||||
Compare<S, T, E>>
|
||||
schedule;
|
||||
|
||||
// Stores final status of all the processes after completing the execution.
|
||||
vector<tuple<S, T, E, double, double, double>> result;
|
||||
|
||||
// Stores process IDs. Used for confirming absence of a process while adding
|
||||
// it.
|
||||
unordered_set<S> idList;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Adds the process to the ready queue if it isn't already there
|
||||
* @param id Process ID
|
||||
* @param arrival Arrival time of the process
|
||||
* @param burst Burst time of the process
|
||||
* @returns void
|
||||
*
|
||||
*/
|
||||
void addProcess(S id, T arrival, E burst) {
|
||||
// Add if a process with process ID as id is not found in idList.
|
||||
if (idList.find(id) == idList.end()) {
|
||||
tuple<S, T, E, double, double, double> t =
|
||||
make_tuple(id, arrival, burst, 0, 0, 0);
|
||||
schedule.push(t);
|
||||
idList.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Algorithm for scheduling CPU processes according to the First Come
|
||||
* First Serve(FCFS) scheduling algorithm.
|
||||
*
|
||||
* @details FCFS is a non-preemptive algorithm in which the process which
|
||||
* arrives first gets executed first. If two or more processes arrive
|
||||
* together then the process with smaller process ID runs first (each
|
||||
* process has a unique proces ID).
|
||||
*
|
||||
* I used a min priority queue of tuples to accomplish this task. The
|
||||
* processes are ordered by their arrival times. If arrival times of some
|
||||
* processes are equal, then they are ordered by their process ID.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
vector<tuple<S, T, E, double, double, double>> scheduleForFcfs() {
|
||||
// Variable to keep track of time elapsed so far
|
||||
double timeElapsed = 0;
|
||||
|
||||
while (!schedule.empty()) {
|
||||
tuple<S, T, E, double, double, double> cur = schedule.top();
|
||||
|
||||
// If the current process arrived at time t2, the last process
|
||||
// completed its execution at time t1, and t2 > t1.
|
||||
if (get<1>(cur) > timeElapsed) {
|
||||
timeElapsed += get<1>(cur) - timeElapsed;
|
||||
}
|
||||
|
||||
// Add Burst time to time elapsed
|
||||
timeElapsed += get<2>(cur);
|
||||
|
||||
// Completion time of the current process will be same as time
|
||||
// elapsed so far
|
||||
get<3>(cur) = timeElapsed;
|
||||
|
||||
// Turnaround time = Completion time - Arrival time
|
||||
get<4>(cur) = get<3>(cur) - get<1>(cur);
|
||||
|
||||
// Waiting time = Turnaround time - Burst time
|
||||
get<5>(cur) = get<4>(cur) - get<2>(cur);
|
||||
|
||||
result.push_back(cur);
|
||||
schedule.pop();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function for printing the status of each process after
|
||||
* execution
|
||||
* @returns void
|
||||
*/
|
||||
void printResult() {
|
||||
cout << "Status of all the proceses post completion is as follows:"
|
||||
<< endl;
|
||||
|
||||
cout << std::setw(17) << left << "Process ID" << std::setw(17) << left
|
||||
<< "Arrival Time" << std::setw(17) << left << "Burst Time"
|
||||
<< std::setw(17) << left << "Completion Time" << std::setw(17)
|
||||
<< left << "Turnaround Time" << std::setw(17) << left
|
||||
<< "Waiting Time" << endl;
|
||||
|
||||
for (size_t i{}; i < result.size(); i++) {
|
||||
cout << std::setprecision(2) << std::fixed << std::setw(17) << left
|
||||
<< get<0>(result[i]) << std::setw(17) << left
|
||||
<< get<1>(result[i]) << std::setw(17) << left
|
||||
<< get<2>(result[i]) << std::setw(17) << left
|
||||
<< get<3>(result[i]) << std::setw(17) << left
|
||||
<< get<4>(result[i]) << std::setw(17) << left
|
||||
<< get<5>(result[i]) << endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Function to be used for testing purposes. This function guarantees the
|
||||
* correct solution for FCFS scheduling algorithm.
|
||||
* @param input the input data
|
||||
* @details Sorts the input vector according to arrival time. Processes whose
|
||||
* arrival times are same get sorted according to process ID For each process,
|
||||
* completion time, turnaround time and completion time are calculated, inserted
|
||||
* in a tuple, which is added to the vector result.
|
||||
* @returns A vector of tuples consisting of process ID, arrival time, burst
|
||||
* time, completion time, turnaround time and waiting time for each process.
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
vector<tuple<S, T, E, double, double, double>> get_final_status(
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t>> input) {
|
||||
sort(input.begin(), input.end(), sortcol<S, T, E>);
|
||||
vector<tuple<S, T, E, double, double, double>> result(input.size());
|
||||
double timeElapsed = 0;
|
||||
for (size_t i{}; i < input.size(); i++) {
|
||||
T arrival = get<1>(input[i]);
|
||||
E burst = get<2>(input[i]);
|
||||
|
||||
if (arrival > timeElapsed) {
|
||||
timeElapsed += arrival - timeElapsed;
|
||||
}
|
||||
timeElapsed += burst;
|
||||
double completion = timeElapsed;
|
||||
double turnaround = completion - arrival;
|
||||
double waiting = turnaround - burst;
|
||||
|
||||
get<0>(result[i]) = get<0>(input[i]);
|
||||
get<1>(result[i]) = arrival;
|
||||
get<2>(result[i]) = burst;
|
||||
get<3>(result[i]) = completion;
|
||||
get<4>(result[i]) = turnaround;
|
||||
get<5>(result[i]) = waiting;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
for (int i{}; i < 1000; i++) {
|
||||
srand(time(nullptr));
|
||||
uint32_t n = 1 + rand() % 1000;
|
||||
FCFS<uint32_t, uint32_t, uint32_t> readyQueue;
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t>> input(n);
|
||||
|
||||
for (uint32_t i{}; i < n; i++) {
|
||||
get<0>(input[i]) = i;
|
||||
srand(time(nullptr));
|
||||
get<1>(input[i]) = 1 + rand() % 10000;
|
||||
srand(time(nullptr));
|
||||
get<2>(input[i]) = 1 + rand() % 10000;
|
||||
}
|
||||
|
||||
for (uint32_t i{}; i < n; i++) {
|
||||
readyQueue.addProcess(get<0>(input[i]), get<1>(input[i]),
|
||||
get<2>(input[i]));
|
||||
}
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t, double, double, double>>
|
||||
res = get_final_status<uint32_t, uint32_t, uint32_t>(input);
|
||||
assert(res == readyQueue.scheduleForFcfs());
|
||||
// readyQueue.printResult();
|
||||
}
|
||||
cout << "All the tests have successfully passed!" << endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Entry point of the program
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
@ -15,7 +15,7 @@ void push(int x) {
|
||||
}
|
||||
|
||||
void pop() {
|
||||
if (top_var == NULL) {
|
||||
if (top_var == nullptr) {
|
||||
std::cout << "\nUnderflow";
|
||||
} else {
|
||||
node *t = top_var;
|
||||
@ -27,28 +27,38 @@ void pop() {
|
||||
|
||||
void show() {
|
||||
node *t = top_var;
|
||||
while (t != NULL) {
|
||||
while (t != nullptr) {
|
||||
std::cout << t->val << "\n";
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int ch, x;
|
||||
int ch = 0, x = 0;
|
||||
do {
|
||||
std::cout << "\n0. Exit or Ctrl+C";
|
||||
std::cout << "\n1. Push";
|
||||
std::cout << "\n2. Pop";
|
||||
std::cout << "\n3. Print";
|
||||
std::cout << "\nEnter Your Choice : ";
|
||||
std::cout << "\nEnter Your Choice: ";
|
||||
std::cin >> ch;
|
||||
if (ch == 1) {
|
||||
std::cout << "\nInsert : ";
|
||||
std::cin >> x;
|
||||
push(x);
|
||||
} else if (ch == 2) {
|
||||
pop();
|
||||
} else if (ch == 3) {
|
||||
show();
|
||||
switch (ch) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
std::cout << "\nInsert : ";
|
||||
std::cin >> x;
|
||||
push(x);
|
||||
break;
|
||||
case 2:
|
||||
pop();
|
||||
break;
|
||||
case 3:
|
||||
show();
|
||||
break;
|
||||
default:
|
||||
std::cout << "Invalid option!\n";
|
||||
break;
|
||||
}
|
||||
} while (ch != 0);
|
||||
|
||||
|
@ -1,21 +1,39 @@
|
||||
// Program to check whether a number is an armstrong number or not
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
|
||||
int main() {
|
||||
int n, k, d, s = 0;
|
||||
cout << "Enter a number:";
|
||||
int n = 0, temp = 0, rem = 0, count = 0, sum = 0;
|
||||
cout << "Enter a number: ";
|
||||
cin >> n;
|
||||
k = n;
|
||||
while (k != 0) {
|
||||
d = k % 10;
|
||||
s += d * d * d;
|
||||
k /= 10;
|
||||
|
||||
temp = n;
|
||||
|
||||
/* First Count the number of digits
|
||||
in the given number */
|
||||
while (temp != 0) {
|
||||
temp /= 10;
|
||||
count++;
|
||||
}
|
||||
if (s == n)
|
||||
cout << n << "is an armstrong number";
|
||||
else
|
||||
cout << n << "is not an armstrong number";
|
||||
|
||||
/* Calaculation for checking of armstrongs number i.e.
|
||||
in a n digit number sum of the digits raised to a power of n
|
||||
is equal to the original number */
|
||||
|
||||
temp = n;
|
||||
while (temp != 0) {
|
||||
rem = temp % 10;
|
||||
sum += static_cast<int>(pow(rem, count));
|
||||
temp /= 10;
|
||||
}
|
||||
|
||||
if (sum == n) {
|
||||
cout << n << " is an armstrong number";
|
||||
} else {
|
||||
cout << n << " is not an armstrong number";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
196
math/integral_approximation2.cpp
Normal file
196
math/integral_approximation2.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Monte Carlo Integration](https://en.wikipedia.org/wiki/Monte_Carlo_integration)
|
||||
*
|
||||
* @details
|
||||
* In mathematics, Monte Carlo integration is a technique for numerical integration using random numbers.
|
||||
* It is a particular Monte Carlo method that numerically computes a definite integral.
|
||||
* While other algorithms usually evaluate the integrand at a regular grid, Monte Carlo randomly chooses points at which the integrand is evaluated.
|
||||
* This method is particularly useful for higher-dimensional integrals.
|
||||
*
|
||||
* This implementation supports arbitrary pdfs.
|
||||
* These pdfs are sampled using the [Metropolis-Hastings algorithm](https://en.wikipedia.org/wiki/Metropolis–Hastings_algorithm).
|
||||
* This can be swapped out by every other sampling techniques for example the inverse method.
|
||||
* Metropolis-Hastings was chosen because it is the most general and can also be extended for a higher dimensional sampling space.
|
||||
*
|
||||
* @author [Domenic Zingsheim](https://github.com/DerAndereDomenic)
|
||||
*/
|
||||
|
||||
#define _USE_MATH_DEFINES /// for M_PI on windows
|
||||
#include <cmath> /// for math functions
|
||||
#include <cstdint> /// for fixed size data types
|
||||
#include <ctime> /// for time to initialize rng
|
||||
#include <functional> /// for function pointers
|
||||
#include <iostream> /// for std::cout
|
||||
#include <random> /// for random number generation
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace math
|
||||
* @brief Math algorithms
|
||||
*/
|
||||
namespace math {
|
||||
/**
|
||||
* @namespace monte_carlo
|
||||
* @brief Functions for the [Monte Carlo Integration](https://en.wikipedia.org/wiki/Monte_Carlo_integration) implementation
|
||||
*/
|
||||
namespace monte_carlo {
|
||||
|
||||
using Function = std::function<double(double&)>; /// short-hand for std::functions used in this implementation
|
||||
|
||||
/**
|
||||
* @brief Generate samples according to some pdf
|
||||
* @details This function uses Metropolis-Hastings to generate random numbers. It generates a sequence of random numbers by using a markov chain.
|
||||
* Therefore, we need to define a start_point and the number of samples we want to generate.
|
||||
* Because the first samples generated by the markov chain may not be distributed according to the given pdf, one can specify how many samples
|
||||
* should be discarded before storing samples.
|
||||
* @param start_point The starting point of the markov chain
|
||||
* @param pdf The pdf to sample
|
||||
* @param num_samples The number of samples to generate
|
||||
* @param discard How many samples should be discarded at the start
|
||||
* @returns A vector of size num_samples with samples distributed according to the pdf
|
||||
*/
|
||||
std::vector<double> generate_samples(const double& start_point, const Function& pdf, const uint32_t& num_samples, const uint32_t& discard = 100000) {
|
||||
std::vector<double> samples;
|
||||
samples.reserve(num_samples);
|
||||
|
||||
double x_t = start_point;
|
||||
|
||||
std::default_random_engine generator;
|
||||
std::uniform_real_distribution<double> uniform(0.0, 1.0);
|
||||
std::normal_distribution<double> normal(0.0, 1.0);
|
||||
generator.seed(time(nullptr));
|
||||
|
||||
for(uint32_t t = 0; t < num_samples + discard; ++t) {
|
||||
// Generate a new proposal according to some mutation strategy.
|
||||
// This is arbitrary and can be swapped.
|
||||
double x_dash = normal(generator) + x_t;
|
||||
double acceptance_probability = std::min(pdf(x_dash)/pdf(x_t), 1.0);
|
||||
double u = uniform(generator);
|
||||
|
||||
// Accept "new state" according to the acceptance_probability
|
||||
if(u <= acceptance_probability) {
|
||||
x_t = x_dash;
|
||||
}
|
||||
|
||||
if(t >= discard) {
|
||||
samples.push_back(x_t);
|
||||
}
|
||||
}
|
||||
|
||||
return samples;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute an approximation of an integral using Monte Carlo integration
|
||||
* @details The integration domain [a,b] is given by the pdf.
|
||||
* The pdf has to fulfill the following conditions:
|
||||
* 1) for all x \in [a,b] : p(x) > 0
|
||||
* 2) for all x \not\in [a,b] : p(x) = 0
|
||||
* 3) \int_a^b p(x) dx = 1
|
||||
* @param start_point The start point of the Markov Chain (see generate_samples)
|
||||
* @param function The function to integrate
|
||||
* @param pdf The pdf to sample
|
||||
* @param num_samples The number of samples used to approximate the integral
|
||||
* @returns The approximation of the integral according to 1/N \sum_{i}^N f(x_i) / p(x_i)
|
||||
*/
|
||||
double integral_monte_carlo(const double& start_point, const Function& function, const Function& pdf, const uint32_t& num_samples = 1000000) {
|
||||
double integral = 0.0;
|
||||
std::vector<double> samples = generate_samples(start_point, pdf, num_samples);
|
||||
|
||||
for(double sample : samples) {
|
||||
integral += function(sample) / pdf(sample);
|
||||
}
|
||||
|
||||
return integral / static_cast<double>(samples.size());
|
||||
}
|
||||
|
||||
} // namespace monte_carlo
|
||||
} // namespace math
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::cout << "Disclaimer: Because this is a randomized algorithm," << std::endl;
|
||||
std::cout << "it may happen that singular samples deviate from the true result." << std::endl << std::endl;;
|
||||
|
||||
math::monte_carlo::Function f;
|
||||
math::monte_carlo::Function pdf;
|
||||
double integral = 0;
|
||||
double lower_bound = 0, upper_bound = 0;
|
||||
|
||||
/* \int_{-2}^{2} -x^2 + 4 dx */
|
||||
f = [&](double& x) {
|
||||
return -x*x + 4.0;
|
||||
};
|
||||
|
||||
lower_bound = -2.0;
|
||||
upper_bound = 2.0;
|
||||
pdf = [&](double& x) {
|
||||
if(x >= lower_bound && x <= -1.0) {
|
||||
return 0.1;
|
||||
}
|
||||
if(x <= upper_bound && x >= 1.0) {
|
||||
return 0.1;
|
||||
}
|
||||
if(x > -1.0 && x < 1.0) {
|
||||
return 0.4;
|
||||
}
|
||||
return 0.0;
|
||||
};
|
||||
|
||||
integral = math::monte_carlo::integral_monte_carlo((upper_bound - lower_bound) / 2.0, f, pdf);
|
||||
|
||||
std::cout << "This number should be close to 10.666666: " << integral << std::endl;
|
||||
|
||||
/* \int_{0}^{1} e^x dx */
|
||||
f = [&](double& x) {
|
||||
return std::exp(x);
|
||||
};
|
||||
|
||||
lower_bound = 0.0;
|
||||
upper_bound = 1.0;
|
||||
pdf = [&](double& x) {
|
||||
if(x >= lower_bound && x <= 0.2) {
|
||||
return 0.1;
|
||||
}
|
||||
if(x > 0.2 && x <= 0.4) {
|
||||
return 0.4;
|
||||
}
|
||||
if(x > 0.4 && x < upper_bound) {
|
||||
return 1.5;
|
||||
}
|
||||
return 0.0;
|
||||
};
|
||||
|
||||
integral = math::monte_carlo::integral_monte_carlo((upper_bound - lower_bound) / 2.0, f, pdf);
|
||||
|
||||
std::cout << "This number should be close to 1.7182818: " << integral << std::endl;
|
||||
|
||||
/* \int_{-\infty}^{\infty} sinc(x) dx, sinc(x) = sin(pi * x) / (pi * x)
|
||||
This is a difficult integral because of its infinite domain.
|
||||
Therefore, it may deviate largely from the expected result.
|
||||
*/
|
||||
f = [&](double& x) {
|
||||
return std::sin(M_PI * x) / (M_PI * x);
|
||||
};
|
||||
|
||||
pdf = [&](double& x) {
|
||||
return 1.0 / std::sqrt(2.0 * M_PI) * std::exp(-x * x / 2.0);
|
||||
};
|
||||
|
||||
integral = math::monte_carlo::integral_monte_carlo(0.0, f, pdf, 10000000);
|
||||
|
||||
std::cout << "This number should be close to 1.0: " << integral << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
109
others/easter.cpp
Normal file
109
others/easter.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* @file
|
||||
* @brief Determines the [Date of
|
||||
* Easter](https://en.wikipedia.org/wiki/Date_of_Easter) after 1582
|
||||
*
|
||||
* @details
|
||||
* The date of Easter is determined in each year through a calculation known as
|
||||
* "computus." Easter is celebrated on the first Sunday after the Paschal full
|
||||
* moon, which is the first full moon on or after 21 March. Determining this
|
||||
* date in advance requires a correlation between the lunar months and the solar
|
||||
* year, while also accounting for the month, date, and weekday of the Julian or
|
||||
* Gregorian calendar. The complexity of the algorithm arises because of the
|
||||
* desire to associate the date of Easter with the date of the Jewish feast of
|
||||
* Passover which, Christians believe, is when Jesus was crucified.
|
||||
*
|
||||
*
|
||||
* @author [AlternateWalls](https://github.com/AlternateWalls)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/*
|
||||
* @brief Contains information for Easter date
|
||||
*/
|
||||
class EasterYearMonthDay {
|
||||
public:
|
||||
uint64_t year; ///< year Easter is on
|
||||
uint64_t month; ///< month Easter is on
|
||||
uint64_t day; ///< day Easter is on
|
||||
|
||||
EasterYearMonthDay(uint64_t newYear, uint64_t newMonth, uint64_t newDay) {
|
||||
year = newYear; // Assigns year to class
|
||||
month = newMonth;
|
||||
day = newDay;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief Function that finds the month and day of Easter
|
||||
* @params param1 An int "y" of the year you want to find Easter on after
|
||||
* 1582
|
||||
* @returns An instance of the easterYearMonthDay calss that contains the
|
||||
* information (Ex. 420 - 4/20 or April 20th)
|
||||
*/
|
||||
EasterYearMonthDay findEaster(uint64_t y) {
|
||||
if (y > 1582) {
|
||||
uint64_t a = y % 19; // Year's location on Metonic Calendar
|
||||
uint64_t b = y / 100; // Century index
|
||||
uint64_t c = y % 100;
|
||||
uint64_t d = b / 4;
|
||||
uint64_t e = b % 4; // Takes into account leap years
|
||||
uint64_t f = (b + 8) / 25;
|
||||
uint64_t g = (b - f + 1) / 3;
|
||||
uint64_t h = (19 * a + b - d - g + 15) %
|
||||
30; // Days from Mar. 21st until the full moon
|
||||
uint64_t i = c / 4;
|
||||
uint64_t k = c % 4;
|
||||
uint64_t r =
|
||||
(32 + 2 * e + 2 * i - h - k) %
|
||||
7; // The number of days from Paschal full moon to next Sunday
|
||||
uint64_t m = (a + 11 * h + 22 * r) / 451;
|
||||
uint64_t n = (h + r - 7 * m + 114) / 31; // Month of Easter
|
||||
uint64_t p = (h + r - 7 * m + 114) % 31; // p + 1 is the day of Easter
|
||||
|
||||
// Assign values
|
||||
EasterYearMonthDay date(
|
||||
y, n, p + 1); // Assign values to new instance of class
|
||||
|
||||
// Return date
|
||||
return date;
|
||||
} else {
|
||||
EasterYearMonthDay date(0, 0, 0);
|
||||
|
||||
// Return date
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 2003 | April 20th
|
||||
assert(findEaster(2003).month == 4); // Should return true
|
||||
assert(findEaster(2003).day == 20); // Should return true
|
||||
|
||||
// 1910 | March 27th
|
||||
assert(findEaster(1910).month == 3); // Should return true
|
||||
assert(findEaster(1910).day == 27); // Should return true
|
||||
|
||||
// 1877 | April 1st
|
||||
assert(findEaster(1877).month != 3); // Should return true
|
||||
assert(findEaster(1877).day != 22); // Should return true
|
||||
|
||||
// 1400 | Invalid date
|
||||
assert(findEaster(1400).month == 0); // Should return true
|
||||
assert(findEaster(1400).day == 0); // Should return true
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
86
others/kadanes3.cpp
Normal file
86
others/kadanes3.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Efficient implementation for maximum contiguous subarray sum by
|
||||
* [Kadane's
|
||||
* algorithm](https://www.geeksforgeeks.org/largest-sum-contiguous-subarray/).
|
||||
* @details
|
||||
* Our task is to take length of array and then the whole array as input from
|
||||
* the user and then calculate the maximum contiguos subarray sum for the
|
||||
* input array, using the kadane's algorithm.
|
||||
*
|
||||
* There can be a case that all the elements in the input array are negative.
|
||||
* In that case, the least value among all elements is the maximum sum with
|
||||
* subarray length = 1.
|
||||
* @author [Abhijeet Tiwari](https://github.com/thisabhijeet)
|
||||
*/
|
||||
|
||||
#include <array> /// for std::array
|
||||
#include <cassert> /// for assert
|
||||
#include <climits> /// for INT_MIN value
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @brief Utility function to check the current maximum number
|
||||
* \param arr input array
|
||||
* \param length length of the input array
|
||||
* \returns maximum contiguous subarray sum
|
||||
*/
|
||||
template <std::size_t SIZE>
|
||||
int max_subarray_sum(std::array<int64_t, SIZE> arr, uint64_t length) {
|
||||
int64_t current_max = INT_MIN, current_sum = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
current_sum = current_sum + arr[i];
|
||||
if (current_max < current_sum) {
|
||||
current_max = current_sum;
|
||||
}
|
||||
|
||||
if (current_sum < 0) {
|
||||
current_sum = 0;
|
||||
}
|
||||
}
|
||||
return current_max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::array<int64_t, 4> arr = {1, 2, 3, 4};
|
||||
std::array<int64_t, 5> arr1 = {-1, -2, -4, -6, 7};
|
||||
assert(max_subarray_sum(arr, 4) == 10);
|
||||
assert(max_subarray_sum(arr1, 5) == 7);
|
||||
std::cout << "All test cases have passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
// Below is the code for accepting array from the user and then
|
||||
// calling the function for the required output.
|
||||
// It has been commented for now so that the test() function can run
|
||||
// and the test cases can be verified.
|
||||
// code for accepting array from user starts
|
||||
|
||||
// std::size_t n; // variable for length of input array
|
||||
// std::cout << "Enter length of the array: ";
|
||||
// std::cin >> n;
|
||||
// std::array<int64_t, 100> arr = {0};
|
||||
// // we need to give a constant in size. Hence we have allocated 100
|
||||
// for now.
|
||||
// for (int i = 0; i < n; i++)
|
||||
// taking input of each element of the array
|
||||
// {
|
||||
// std::cin >> arr[i];
|
||||
// }
|
||||
// code for accepting array from user ends
|
||||
|
||||
// int max_sum = max_subarray_sum(arr, n);
|
||||
// std::cout << "Maximum contiguous sum for this array is : " << max_sum
|
||||
// << std::endl;
|
||||
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
260
probability/geometric_dist.cpp
Normal file
260
probability/geometric_dist.cpp
Normal file
@ -0,0 +1,260 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Geometric
|
||||
* Distribution](https://en.wikipedia.org/wiki/Geometric_distribution)
|
||||
*
|
||||
* @details
|
||||
* The geometric distribution models the experiment of doing Bernoulli trials
|
||||
* until a sucess was observed. There are two formulations of the geometric
|
||||
* distribution: 1) The probability distribution of the number X of Bernoulli
|
||||
* trials needed to get one success, supported on the set { 1, 2, 3, ... } 2)
|
||||
* The probability distribution of the number Y = X − 1 of failures before the
|
||||
* first success, supported on the set { 0, 1, 2, 3, ... } Here, the first one
|
||||
* is implemented.
|
||||
*
|
||||
* Common variables used:
|
||||
* p - The success probability
|
||||
* k - The number of tries
|
||||
*
|
||||
* @author [Domenic Zingsheim](https://github.com/DerAndereDomenic)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cmath> /// for math functions
|
||||
#include <cstdint> /// for fixed size data types
|
||||
#include <ctime> /// for time to initialize rng
|
||||
#include <iostream> /// for std::cout
|
||||
#include <limits> /// for std::numeric_limits
|
||||
#include <random> /// for random numbers
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace probability
|
||||
* @brief Probability algorithms
|
||||
*/
|
||||
namespace probability {
|
||||
/**
|
||||
* @namespace geometric_dist
|
||||
* @brief Functions for the [Geometric
|
||||
* Distribution](https://en.wikipedia.org/wiki/Geometric_distribution) algorithm
|
||||
* implementation
|
||||
*/
|
||||
namespace geometric_dist {
|
||||
/**
|
||||
* @brief Returns a random number between [0,1]
|
||||
* @returns A uniformly distributed random number between 0 (included) and 1
|
||||
* (included)
|
||||
*/
|
||||
float generate_uniform() {
|
||||
return static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A class to model the geometric distribution
|
||||
*/
|
||||
class geometric_distribution {
|
||||
private:
|
||||
float p; ///< The succes probability p
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for the geometric distribution
|
||||
* @param p The success probability
|
||||
*/
|
||||
explicit geometric_distribution(const float& p) : p(p) {}
|
||||
|
||||
/**
|
||||
* @brief The expected value of a geometrically distributed random variable
|
||||
* X
|
||||
* @returns E[X] = 1/p
|
||||
*/
|
||||
float expected_value() const { return 1.0f / p; }
|
||||
|
||||
/**
|
||||
* @brief The variance of a geometrically distributed random variable X
|
||||
* @returns V[X] = (1 - p) / p^2
|
||||
*/
|
||||
float variance() const { return (1.0f - p) / (p * p); }
|
||||
|
||||
/**
|
||||
* @brief The standard deviation of a geometrically distributed random
|
||||
* variable X
|
||||
* @returns \sigma = \sqrt{V[X]}
|
||||
*/
|
||||
float standard_deviation() const { return std::sqrt(variance()); }
|
||||
|
||||
/**
|
||||
* @brief The probability density function
|
||||
* @details As we use the first definition of the geometric series (1),
|
||||
* we are doing k - 1 failed trials and the k-th trial is a success.
|
||||
* @param k The number of trials to observe the first success in [1,\infty)
|
||||
* @returns A number between [0,1] according to p * (1-p)^{k-1}
|
||||
*/
|
||||
float probability_density(const uint32_t& k) const {
|
||||
return std::pow((1.0f - p), static_cast<float>(k - 1)) * p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The cumulative distribution function
|
||||
* @details The sum of all probabilities up to (and including) k trials.
|
||||
* Basically CDF(k) = P(x <= k)
|
||||
* @param k The number of trials in [1,\infty)
|
||||
* @returns The probability to have success within k trials
|
||||
*/
|
||||
float cumulative_distribution(const uint32_t& k) const {
|
||||
return 1.0f - std::pow((1.0f - p), static_cast<float>(k));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The inverse cumulative distribution function
|
||||
* @details This functions answers the question: Up to how many trials are
|
||||
* needed to have success with a probability of cdf? The exact floating
|
||||
* point value is reported.
|
||||
* @param cdf The probability in [0,1]
|
||||
* @returns The number of (exact) trials.
|
||||
*/
|
||||
float inverse_cumulative_distribution(const float& cdf) const {
|
||||
return std::log(1.0f - cdf) / std::log(1.0f - p);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates a (discrete) sample according to the geometrical
|
||||
* distribution
|
||||
* @returns A geometrically distributed number in [1,\infty)
|
||||
*/
|
||||
uint32_t draw_sample() const {
|
||||
float uniform_sample = generate_uniform();
|
||||
return static_cast<uint32_t>(
|
||||
inverse_cumulative_distribution(uniform_sample)) +
|
||||
1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function computes the probability to have success in a given
|
||||
* range of tries
|
||||
* @details Computes P(min_tries <= x <= max_tries).
|
||||
* Can be used to calculate P(x >= min_tries) by not passing a second
|
||||
* argument. Can be used to calculate P(x <= max_tries) by passing 1 as the
|
||||
* first argument
|
||||
* @param min_tries The minimum number of tries in [1,\infty) (inclusive)
|
||||
* @param max_tries The maximum number of tries in [min_tries, \infty)
|
||||
* (inclusive)
|
||||
* @returns The probability of having success within a range of tries
|
||||
* [min_tries, max_tries]
|
||||
*/
|
||||
float range_tries(const uint32_t& min_tries = 1,
|
||||
const uint32_t& max_tries =
|
||||
std::numeric_limits<uint32_t>::max()) const {
|
||||
float cdf_lower = cumulative_distribution(min_tries - 1);
|
||||
float cdf_upper = max_tries == std::numeric_limits<uint32_t>::max()
|
||||
? 1.0f
|
||||
: cumulative_distribution(max_tries);
|
||||
return cdf_upper - cdf_lower;
|
||||
}
|
||||
};
|
||||
} // namespace geometric_dist
|
||||
} // namespace probability
|
||||
|
||||
/**
|
||||
* @brief Tests the sampling method of the geometric distribution
|
||||
* @details Draws 1000000 random samples and estimates mean and variance
|
||||
* These should be close to the expected value and variance of the given
|
||||
* distribution to pass.
|
||||
* @param dist The distribution to test
|
||||
*/
|
||||
void sample_test(
|
||||
const probability::geometric_dist::geometric_distribution& dist) {
|
||||
uint32_t n_tries = 1000000;
|
||||
std::vector<float> tries;
|
||||
tries.resize(n_tries);
|
||||
|
||||
float mean = 0.0f;
|
||||
for (uint32_t i = 0; i < n_tries; ++i) {
|
||||
tries[i] = static_cast<float>(dist.draw_sample());
|
||||
mean += tries[i];
|
||||
}
|
||||
|
||||
mean /= static_cast<float>(n_tries);
|
||||
|
||||
float var = 0.0f;
|
||||
for (uint32_t i = 0; i < n_tries; ++i) {
|
||||
var += (tries[i] - mean) * (tries[i] - mean);
|
||||
}
|
||||
|
||||
// Unbiased estimate of variance
|
||||
var /= static_cast<float>(n_tries - 1);
|
||||
|
||||
std::cout << "This value should be near " << dist.expected_value() << ": "
|
||||
<< mean << std::endl;
|
||||
std::cout << "This value should be near " << dist.variance() << ": " << var
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
probability::geometric_dist::geometric_distribution dist(0.3);
|
||||
|
||||
const float threshold = 1e-3f;
|
||||
|
||||
std::cout << "Starting tests for p = 0.3..." << std::endl;
|
||||
assert(std::abs(dist.expected_value() - 3.33333333f) < threshold);
|
||||
assert(std::abs(dist.variance() - 7.77777777f) < threshold);
|
||||
assert(std::abs(dist.standard_deviation() - 2.788866755) < threshold);
|
||||
assert(std::abs(dist.probability_density(5) - 0.07203) < threshold);
|
||||
assert(std::abs(dist.cumulative_distribution(6) - 0.882351) < threshold);
|
||||
assert(std::abs(dist.inverse_cumulative_distribution(
|
||||
dist.cumulative_distribution(8)) -
|
||||
8) < threshold);
|
||||
assert(std::abs(dist.range_tries() - 1.0f) < threshold);
|
||||
assert(std::abs(dist.range_tries(3) - 0.49f) < threshold);
|
||||
assert(std::abs(dist.range_tries(5, 11) - 0.2203267f) < threshold);
|
||||
std::cout << "All tests passed" << std::endl;
|
||||
sample_test(dist);
|
||||
|
||||
dist = probability::geometric_dist::geometric_distribution(0.5f);
|
||||
|
||||
std::cout << "Starting tests for p = 0.5..." << std::endl;
|
||||
assert(std::abs(dist.expected_value() - 2.0f) < threshold);
|
||||
assert(std::abs(dist.variance() - 2.0f) < threshold);
|
||||
assert(std::abs(dist.standard_deviation() - 1.4142135f) < threshold);
|
||||
assert(std::abs(dist.probability_density(5) - 0.03125) < threshold);
|
||||
assert(std::abs(dist.cumulative_distribution(6) - 0.984375) < threshold);
|
||||
assert(std::abs(dist.inverse_cumulative_distribution(
|
||||
dist.cumulative_distribution(8)) -
|
||||
8) < threshold);
|
||||
assert(std::abs(dist.range_tries() - 1.0f) < threshold);
|
||||
assert(std::abs(dist.range_tries(3) - 0.25f) < threshold);
|
||||
assert(std::abs(dist.range_tries(5, 11) - 0.062011f) < threshold);
|
||||
std::cout << "All tests passed" << std::endl;
|
||||
sample_test(dist);
|
||||
|
||||
dist = probability::geometric_dist::geometric_distribution(0.8f);
|
||||
|
||||
std::cout << "Starting tests for p = 0.8..." << std::endl;
|
||||
assert(std::abs(dist.expected_value() - 1.25f) < threshold);
|
||||
assert(std::abs(dist.variance() - 0.3125f) < threshold);
|
||||
assert(std::abs(dist.standard_deviation() - 0.559016f) < threshold);
|
||||
assert(std::abs(dist.probability_density(5) - 0.00128) < threshold);
|
||||
assert(std::abs(dist.cumulative_distribution(6) - 0.999936) < threshold);
|
||||
assert(std::abs(dist.inverse_cumulative_distribution(
|
||||
dist.cumulative_distribution(8)) -
|
||||
8) < threshold);
|
||||
assert(std::abs(dist.range_tries() - 1.0f) < threshold);
|
||||
assert(std::abs(dist.range_tries(3) - 0.04f) < threshold);
|
||||
assert(std::abs(dist.range_tries(5, 11) - 0.00159997f) < threshold);
|
||||
std::cout << "All tests have successfully passed!" << std::endl;
|
||||
sample_test(dist);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @return 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
srand(time(nullptr));
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
* data stream
|
||||
*
|
||||
* @details
|
||||
* Given a stream of integers, the algorithm calculates the median of a fixed size
|
||||
* window at the back of the stream. The leading time complexity of this
|
||||
* Given a stream of integers, the algorithm calculates the median of a fixed
|
||||
* size window at the back of the stream. The leading time complexity of this
|
||||
* algorithm is O(log(N), and it is inspired by the known algorithm to [find
|
||||
* median from (infinite) data
|
||||
* stream](https://www.tutorialcup.com/interview/algorithm/find-median-from-data-stream.htm),
|
||||
@ -17,13 +17,13 @@
|
||||
* pushing and popping. Each new value is pushed to the window back, while a
|
||||
* value from the front of the window is popped. In addition, the algorithm
|
||||
* manages a multi-value binary search tree (BST), implemented by std::multiset.
|
||||
* For each new value that is inserted into the window, it is also inserted to the
|
||||
* BST. When a value is popped from the window, it is also erased from the BST.
|
||||
* Both insertion and erasion to/from the BST are O(logN) in time, with N the
|
||||
* size of the window. Finally, the algorithm keeps a pointer to the root of the
|
||||
* BST, and updates its position whenever values are inserted or erased to/from
|
||||
* BST. The root of the tree is the median! Hence, median retrieval is always
|
||||
* O(1)
|
||||
* For each new value that is inserted into the window, it is also inserted to
|
||||
* the BST. When a value is popped from the window, it is also erased from the
|
||||
* BST. Both insertion and erasion to/from the BST are O(logN) in time, with N
|
||||
* the size of the window. Finally, the algorithm keeps a pointer to the root of
|
||||
* the BST, and updates its position whenever values are inserted or erased
|
||||
* to/from BST. The root of the tree is the median! Hence, median retrieval is
|
||||
* always O(1)
|
||||
*
|
||||
* Time complexity: O(logN). Space complexity: O(N). N - size of window
|
||||
* @author [Yaniv Hollander](https://github.com/YanivHollander)
|
||||
@ -32,8 +32,8 @@
|
||||
#include <cstdlib> /// for std::rand - needed in testing
|
||||
#include <ctime> /// for std::time - needed in testing
|
||||
#include <list> /// for std::list - used to manage sliding window
|
||||
#include <set> /// for std::multiset - used to manage multi-value sorted sliding window values
|
||||
#include <vector> /// for std::vector - needed in testing
|
||||
#include <set> /// for std::multiset - used to manage multi-value sorted sliding window values
|
||||
#include <vector> /// for std::vector - needed in testing
|
||||
|
||||
/**
|
||||
* @namespace probability
|
||||
@ -55,7 +55,7 @@ using size_type = Window::size_type;
|
||||
*/
|
||||
class WindowedMedian {
|
||||
const size_type _windowSize; ///< sliding window size
|
||||
Window _window; ///< a sliding window of values along the stream
|
||||
Window _window; ///< a sliding window of values along the stream
|
||||
std::multiset<int> _sortedValues; ///< a DS to represent a balanced
|
||||
/// multi-value binary search tree (BST)
|
||||
std::multiset<int>::const_iterator
|
||||
@ -103,13 +103,14 @@ class WindowedMedian {
|
||||
}
|
||||
|
||||
/// However, if the erased value is on the right branch or the median
|
||||
/// itself, and the number of elements is odd, the new median will be the
|
||||
/// left child of the current one
|
||||
/// itself, and the number of elements is odd, the new median will be
|
||||
/// the left child of the current one
|
||||
else if (value >= *_itMedian && sz % 2 != 0) {
|
||||
--_itMedian; // O(1) - traversing one step to the left child
|
||||
}
|
||||
|
||||
/// Find the (first) position of the value we want to erase, and erase it
|
||||
/// Find the (first) position of the value we want to erase, and erase
|
||||
/// it
|
||||
const auto it = _sortedValues.find(value); // O(logN)
|
||||
_sortedValues.erase(it); // O(logN)
|
||||
}
|
||||
@ -126,16 +127,16 @@ class WindowedMedian {
|
||||
* @param value New value to insert
|
||||
*/
|
||||
void insert(int value) {
|
||||
|
||||
/// Push new value to the back of the sliding window - O(1)
|
||||
_window.push_back(value);
|
||||
insertToSorted(value); // Insert value to the multi-value BST - O(logN)
|
||||
if (_window.size() > _windowSize) { /// If exceeding size of window, pop
|
||||
/// from its left side
|
||||
eraseFromSorted(_window.front()); /// Erase from the multi-value BST
|
||||
/// the window left side value
|
||||
_window
|
||||
.pop_front(); /// Pop the left side value from the window - O(1)
|
||||
if (_window.size() > _windowSize) { /// If exceeding size of window,
|
||||
/// pop from its left side
|
||||
eraseFromSorted(
|
||||
_window.front()); /// Erase from the multi-value BST
|
||||
/// the window left side value
|
||||
_window.pop_front(); /// Pop the left side value from the window -
|
||||
/// O(1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,8 +171,8 @@ class WindowedMedian {
|
||||
0.5f * *next(window.begin(), window.size() / 2 - 1); /// O(N)
|
||||
}
|
||||
};
|
||||
} /// namespace windowed_median
|
||||
} /// namespace probability
|
||||
} // namespace windowed_median
|
||||
} // namespace probability
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
@ -195,32 +196,41 @@ static void test(const std::vector<int> &vals, int windowSize) {
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main(int argc, const char *argv[]) {
|
||||
|
||||
/// A few fixed test cases
|
||||
test({1, 2, 3, 4, 5, 6, 7, 8, 9}, 3); /// Array of sorted values; odd window size
|
||||
test({9, 8, 7, 6, 5, 4, 3, 2, 1}, 3); /// Array of sorted values - decreasing; odd window size
|
||||
test({9, 8, 7, 6, 5, 4, 5, 6}, 4); /// Even window size
|
||||
test({3, 3, 3, 3, 3, 3, 3, 3, 3}, 3); /// Array with repeating values
|
||||
test({3, 3, 3, 3, 7, 3, 3, 3, 3}, 3); /// Array with same values except one
|
||||
test({4, 3, 3, -5, -5, 1, 3, 4, 5}, 5); /// Array that includes repeating values including negatives
|
||||
|
||||
/// Array with large values - sum of few pairs exceeds MAX_INT. Window size is even - testing calculation of
|
||||
/// average median between two middle values
|
||||
test({1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||
3); /// Array of sorted values; odd window size
|
||||
test({9, 8, 7, 6, 5, 4, 3, 2, 1},
|
||||
3); /// Array of sorted values - decreasing; odd window size
|
||||
test({9, 8, 7, 6, 5, 4, 5, 6}, 4); /// Even window size
|
||||
test({3, 3, 3, 3, 3, 3, 3, 3, 3}, 3); /// Array with repeating values
|
||||
test({3, 3, 3, 3, 7, 3, 3, 3, 3}, 3); /// Array with same values except one
|
||||
test({4, 3, 3, -5, -5, 1, 3, 4, 5},
|
||||
5); /// Array that includes repeating values including negatives
|
||||
|
||||
/// Array with large values - sum of few pairs exceeds MAX_INT. Window size
|
||||
/// is even - testing calculation of average median between two middle
|
||||
/// values
|
||||
test({470211272, 101027544, 1457850878, 1458777923, 2007237709, 823564440,
|
||||
1115438165, 1784484492, 74243042, 114807987}, 6);
|
||||
|
||||
1115438165, 1784484492, 74243042, 114807987},
|
||||
6);
|
||||
|
||||
/// Random test cases
|
||||
std::srand(static_cast<unsigned int>(std::time(nullptr)));
|
||||
std::vector<int> vals;
|
||||
for (int i = 8; i < 100; i++) {
|
||||
const auto n = 1 + std::rand() / ((RAND_MAX + 5u) / 20); /// Array size in the range [5, 20]
|
||||
auto windowSize = 1 + std::rand() / ((RAND_MAX + 3u) / 10); /// Window size in the range [3, 10]
|
||||
const auto n =
|
||||
1 + std::rand() /
|
||||
((RAND_MAX + 5u) / 20); /// Array size in the range [5, 20]
|
||||
auto windowSize =
|
||||
1 + std::rand() / ((RAND_MAX + 3u) /
|
||||
10); /// Window size in the range [3, 10]
|
||||
vals.clear();
|
||||
vals.reserve(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
vals.push_back(rand() - RAND_MAX); /// Random array values (positive/negative)
|
||||
vals.push_back(
|
||||
rand() - RAND_MAX); /// Random array values (positive/negative)
|
||||
}
|
||||
test(vals, windowSize); /// Testing randomized test
|
||||
test(vals, windowSize); /// Testing randomized test
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
83
range_queries/prefix_sum_array.cpp
Normal file
83
range_queries/prefix_sum_array.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* [Prefix Sum
|
||||
* Array](https://en.wikipedia.org/wiki/Prefix_sum) data structure
|
||||
* implementation.
|
||||
*
|
||||
* @details
|
||||
* Prefix Sum Array is a data structure, that allows answering sum in some range
|
||||
* queries. It can answer most sum range queries in O(1), with a build time
|
||||
* complexity of O(N). But it hasn't an update querie.
|
||||
*
|
||||
* * Running Time Complexity \n
|
||||
* * Build : O(N) \n
|
||||
* * Range Query : O(1) \n
|
||||
* @author [Paulo Vitor Lima Borges](https://github.com/PauloVLB)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace range_queries
|
||||
* @brief Range Queries algorithms
|
||||
*/
|
||||
namespace range_queries {
|
||||
/**
|
||||
* @namespace prefix_sum_array
|
||||
* @brief Range sum queries using prefix-sum-array
|
||||
*/
|
||||
namespace prefix_sum_array {
|
||||
|
||||
std::vector<int64_t> PSA(1, 0);
|
||||
|
||||
/**
|
||||
* @brief function that builds the PSA
|
||||
* @param original_array original array of values
|
||||
* @returns void
|
||||
*/
|
||||
void build(std::vector<int64_t> original_array) {
|
||||
for (int i = 1; i <= static_cast<int>(original_array.size()); i++) {
|
||||
PSA.push_back(PSA[i - 1] + original_array[i]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief query function
|
||||
* @param beg begin of the interval to sum
|
||||
* @param end end of the interval to sum
|
||||
* @returns sum of the range [beg, end]
|
||||
*/
|
||||
int64_t query(int64_t beg, int64_t end) { return PSA[end] - PSA[beg - 1]; }
|
||||
|
||||
} // namespace prefix_sum_array
|
||||
} // namespace range_queries
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::vector<int64_t> values{0, 123, 0, 2, -2, 5,
|
||||
24, 0, 23, -1, -1}; // original array
|
||||
|
||||
range_queries::prefix_sum_array::build(values);
|
||||
// queries are of the type: sum of the range [a, b] = psa[b] - psa[a-1]
|
||||
|
||||
assert(range_queries::prefix_sum_array::query(1, 10) ==
|
||||
173); // sum of the entire array
|
||||
assert(range_queries::prefix_sum_array::query(4, 6) ==
|
||||
27); // the sum of the interval [4, 6]
|
||||
assert(range_queries::prefix_sum_array::query(5, 9) ==
|
||||
51); // the sum of the interval [5, 9]
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
* \file
|
||||
* \brief Search for words in a long textual paragraph.
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#ifdef _MSC_VER
|
||||
@ -10,9 +11,38 @@
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
/** Main function
|
||||
/**
|
||||
* @brief function to convert a C++ string to lower case
|
||||
* @param word takes an std::string as input
|
||||
* @returns std::string
|
||||
*/
|
||||
std::string lower(std::string word) {
|
||||
int length = word.length();
|
||||
std::string lc = "";
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
lc += tolower(word[i]);
|
||||
}
|
||||
|
||||
return lc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
assert(lower("abcd").compare("abcd") == 0);
|
||||
assert(lower("abc").compare("abcd") == -1);
|
||||
assert(lower("abcd").compare("abc") == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
std::string paragraph;
|
||||
std::cout << "Please enter your paragraph: \n";
|
||||
std::getline(std::cin, paragraph);
|
||||
@ -23,20 +53,46 @@ int main() {
|
||||
if (paragraph.empty()) {
|
||||
std::cout << "\nThe paragraph is empty" << std::endl;
|
||||
} else {
|
||||
int ch = 0;
|
||||
while (true) {
|
||||
std::string word;
|
||||
std::cout << "Please enter the word you are searching for: ";
|
||||
std::getline(std::cin, word);
|
||||
std::cout << "Hello, your word is " << word << "!\n";
|
||||
if (paragraph.find(word) == std::string::npos) {
|
||||
std::cout << word << " does not exist in the sentence"
|
||||
<< std::endl;
|
||||
std::cout << "Ignore case-sensitive? 1 = Yes, 0 = No" << std::endl;
|
||||
std::cin >> ch;
|
||||
if (ch == 1) {
|
||||
std::string lowerCase = lower(
|
||||
paragraph); // convert std::string paragraph to lowercase
|
||||
// and store it in std::string lowerCase
|
||||
std::string lowerCaseWord =
|
||||
lower(word); // convert std::string paragraph to lowercase
|
||||
// and store it in std::string lowerCase
|
||||
|
||||
std::cout << "Hello, your word is " << word << "!\n";
|
||||
if (lowerCase.find(lowerCaseWord) == std::string::npos) {
|
||||
std::cout << word << " does not exist in the sentence"
|
||||
<< std::endl;
|
||||
} else {
|
||||
std::cout << "The word " << word
|
||||
<< " is now found at location "
|
||||
<< lowerCase.find(lowerCaseWord) << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cout << "The word " << word << " is now found at location "
|
||||
<< paragraph.find(word) << std::endl
|
||||
<< std::endl;
|
||||
std::cout << "Hello, your word is " << word << "!\n";
|
||||
if (paragraph.find(word) == std::string::npos) {
|
||||
std::cout << word << " does not exist in the sentence"
|
||||
<< std::endl;
|
||||
} else {
|
||||
std::cout << "The word " << word
|
||||
<< " is now found at location "
|
||||
<< paragraph.find(word) << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "\nPress Ctrl + C to exit the program.\n\n";
|
||||
std::cin.get();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user