Merge branch 'master' into master

This commit is contained in:
David Leal 2021-10-17 14:04:35 -05:00 committed by GitHub
commit d1cb53379e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1224 additions and 97 deletions

View File

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

View File

@ -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. Lets 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 0s and
* 1s. 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

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

View File

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

View File

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

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

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

View File

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

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

View File

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