mirror of
https://github.com/TheAlgorithms/C-Plus-Plus.git
synced 2026-02-04 02:56:40 +08:00
Merge branch 'master' into lazeeez
This commit is contained in:
@@ -32,7 +32,7 @@ You can add new algorithms or data structures which are **not present in the rep
|
||||
- Please use the directory structure of the repository.
|
||||
- Make sure the file extensions should be `*.hpp`, `*.h` or `*.cpp`.
|
||||
- Don't use **`bits/stdc++.h`** because this is quite Linux-specific and slows down the compilation process.
|
||||
- Organize your code using **`struct`**, **`class`**, and/or **`namespace`** keywords
|
||||
- Organize your code using **`struct`**, **`class`**, and/or **`namespace`** keywords.
|
||||
- If an implementation of the algorithm already exists, please refer to the [file-name section below](#new-file-name-guidelines).
|
||||
- You can suggest reasonable changes to existing algorithms.
|
||||
- Strictly use snake_case (underscore_separated) in filenames.
|
||||
|
||||
11
DIRECTORY.md
11
DIRECTORY.md
@@ -19,6 +19,7 @@
|
||||
* [Hamming Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/hamming_distance.cpp)
|
||||
|
||||
## Ciphers
|
||||
* [Atbash Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/atbash_cipher.cpp)
|
||||
* [Base64 Encoding](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/base64_encoding.cpp)
|
||||
* [Caesar Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/caesar_cipher.cpp)
|
||||
* [Elliptic Curve Key Exchange](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/ciphers/elliptic_curve_key_exchange.cpp)
|
||||
@@ -29,6 +30,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)
|
||||
@@ -58,6 +62,7 @@
|
||||
* [Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack.h)
|
||||
* [Stack Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_array.cpp)
|
||||
* [Stack Using Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_linked_list.cpp)
|
||||
* [Stack Using Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/stack_using_queue.cpp)
|
||||
* [Test Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/test_queue.cpp)
|
||||
* [Test Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/test_stack.cpp)
|
||||
* [Test Stack Students](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/data_structures/test_stack_students.cpp)
|
||||
@@ -179,6 +184,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)
|
||||
@@ -236,6 +242,7 @@
|
||||
* [Inorder Successor Of Bst](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/inorder_successor_of_bst.cpp)
|
||||
* [Intersection Of 2 Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/intersection_of_2_arrays.cpp)
|
||||
* [Reverse A Linked List Using Recusion](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/reverse_a_linked_list_using_recusion.cpp)
|
||||
* [Reverse Binary Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/reverse_binary_tree.cpp)
|
||||
* [Selectionsortlinkedlist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/selectionsortlinkedlist.cpp)
|
||||
* [Trie Multiple Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/trie_multiple_search.cpp)
|
||||
* [Union Of 2 Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/operations_on_datastructures/union_of_2_arrays.cpp)
|
||||
@@ -245,9 +252,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 +275,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 +284,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
|
||||
|
||||
83
ciphers/atbash_cipher.cpp
Normal file
83
ciphers/atbash_cipher.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Atbash Cipher](https://en.wikipedia.org/wiki/Atbash) implementation
|
||||
* @details The Atbash cipher is a subsitution cipher where the letters of the
|
||||
* alphabet are in reverse. For example, A is replaced with Z, B is replaced
|
||||
* with Y, etc.
|
||||
*
|
||||
* ### Algorithm
|
||||
* The algorithm takes a string, and looks up the corresponding reversed letter
|
||||
* for each letter in the word and replaces it. Spaces are ignored and case is
|
||||
* preserved.
|
||||
*
|
||||
* @author [Focusucof](https://github.com/Focusucof)
|
||||
*/
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <map> /// for std::map
|
||||
#include <string> /// for std::string
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace atbash
|
||||
* \brief Functions for the [Atbash Cipher](https://en.wikipedia.org/wiki/Atbash) implementation
|
||||
*/
|
||||
namespace atbash {
|
||||
std::map<char, char> atbash_cipher_map = {
|
||||
{'a', 'z'}, {'b', 'y'}, {'c', 'x'}, {'d', 'w'}, {'e', 'v'}, {'f', 'u'},
|
||||
{'g', 't'}, {'h', 's'}, {'i', 'r'}, {'j', 'q'}, {'k', 'p'}, {'l', 'o'},
|
||||
{'m', 'n'}, {'n', 'm'}, {'o', 'l'}, {'p', 'k'}, {'q', 'j'}, {'r', 'i'},
|
||||
{'s', 'h'}, {'t', 'g'}, {'u', 'f'}, {'v', 'e'}, {'w', 'd'}, {'x', 'c'},
|
||||
{'y', 'b'}, {'z', 'a'}, {'A', 'Z'}, {'B', 'Y'}, {'C', 'X'}, {'D', 'W'},
|
||||
{'E', 'V'}, {'F', 'U'}, {'G', 'T'}, {'H', 'S'}, {'I', 'R'}, {'J', 'Q'},
|
||||
{'K', 'P'}, {'L', 'O'}, {'M', 'N'}, {'N', 'M'}, {'O', 'L'}, {'P', 'K'},
|
||||
{'Q', 'J'}, {'R', 'I'}, {'S', 'H'}, {'T', 'G'}, {'U', 'F'}, {'V', 'E'},
|
||||
{'W', 'D'}, {'X', 'C'}, {'Y', 'B'}, {'Z', 'A'}, {' ', ' '}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief atbash cipher encryption and decryption
|
||||
* @param text Plaintext to be encrypted
|
||||
* @returns encoded or decoded string
|
||||
*/
|
||||
std::string atbash_cipher(std::string text) {
|
||||
std::string result;
|
||||
for (char letter : text) {
|
||||
result += atbash_cipher_map[letter];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace atbash
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::string text = "Hello World";
|
||||
std::string expected = "Svool Dliow";
|
||||
std::string encrypted_text = ciphers::atbash::atbash_cipher(text);
|
||||
std::string decrypted_text = ciphers::atbash::atbash_cipher(encrypted_text);
|
||||
assert(expected == encrypted_text);
|
||||
assert(text == decrypted_text);
|
||||
std::cout << "Original text: " << text << std::endl;
|
||||
std::cout << ", Expected text: " << expected << std::endl;
|
||||
std::cout << ", Encrypted text: " << encrypted_text << std::endl;
|
||||
std::cout << ", Decrypted text: " << decrypted_text << std::endl;
|
||||
std::cout << "\nAll tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
|
||||
|
||||
126
data_structures/stack_using_queue.cpp
Normal file
126
data_structures/stack_using_queue.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @brief Stack Data Structure Using the Queue Data Structure
|
||||
* @details
|
||||
* Using 2 Queues inside the Stack class, we can easily implement Stack
|
||||
* data structure with heavy computation in push function.
|
||||
*
|
||||
* References used: [StudyTonight](https://www.studytonight.com/data-structures/stack-using-queue)
|
||||
* @author [tushar2407](https://github.com/tushar2407)
|
||||
*/
|
||||
#include <iostream> /// for IO operations
|
||||
#include <queue> /// for queue data structure
|
||||
#include <cassert> /// for assert
|
||||
|
||||
/**
|
||||
* @namespace data_strcutres
|
||||
* @brief Data structures algorithms
|
||||
*/
|
||||
namespace data_structures {
|
||||
/**
|
||||
* @namespace stack_using_queue
|
||||
* @brief Functions for the [Stack Using Queue](https://www.studytonight.com/data-structures/stack-using-queue) implementation
|
||||
*/
|
||||
namespace stack_using_queue {
|
||||
/**
|
||||
* @brief Stack Class implementation for basic methods of Stack Data Structure.
|
||||
*/
|
||||
struct Stack
|
||||
{
|
||||
std::queue<int64_t> main_q; ///< stores the current state of the stack
|
||||
std::queue<int64_t> auxiliary_q; ///< used to carry out intermediate operations to implement stack
|
||||
uint32_t current_size = 0; ///< stores the current size of the stack
|
||||
|
||||
/**
|
||||
* Returns the top most element of the stack
|
||||
* @returns top element of the queue
|
||||
*/
|
||||
int top()
|
||||
{
|
||||
return main_q.front();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an element to the top of the stack.
|
||||
* @param val the element that will be inserted into the stack
|
||||
* @returns void
|
||||
*/
|
||||
void push(int val)
|
||||
{
|
||||
auxiliary_q.push(val);
|
||||
while(!main_q.empty())
|
||||
{
|
||||
auxiliary_q.push(main_q.front());
|
||||
main_q.pop();
|
||||
}
|
||||
swap(main_q, auxiliary_q);
|
||||
current_size++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the topmost element from the stack
|
||||
* @returns void
|
||||
*/
|
||||
void pop()
|
||||
{
|
||||
if(main_q.empty()) {
|
||||
return;
|
||||
}
|
||||
main_q.pop();
|
||||
current_size--;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to return the current size of the stack
|
||||
* @returns current size of stack
|
||||
*/
|
||||
int size()
|
||||
{
|
||||
return current_size;
|
||||
}
|
||||
};
|
||||
} // namespace stack_using_queue
|
||||
} // namespace data_structures
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test()
|
||||
{
|
||||
data_structures::stack_using_queue::Stack s;
|
||||
s.push(1); /// insert an element into the stack
|
||||
s.push(2); /// insert an element into the stack
|
||||
s.push(3); /// insert an element into the stack
|
||||
|
||||
assert(s.size()==3); /// size should be 3
|
||||
|
||||
assert(s.top()==3); /// topmost element in the stack should be 3
|
||||
|
||||
s.pop(); /// remove the topmost element from the stack
|
||||
assert(s.top()==2); /// topmost element in the stack should now be 2
|
||||
|
||||
s.pop(); /// remove the topmost element from the stack
|
||||
assert(s.top()==1);
|
||||
|
||||
s.push(5); /// insert an element into the stack
|
||||
assert(s.top()==5); /// topmost element in the stack should now be 5
|
||||
|
||||
s.pop(); /// remove the topmost element from the stack
|
||||
assert(s.top()==1); /// topmost element in the stack should now be 1
|
||||
|
||||
assert(s.size()==1); /// size should be 1
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* Creates a stack and pushed some value into it.
|
||||
* Through a series of push and pop functions on stack,
|
||||
* it demostrates the functionality of the custom stack
|
||||
* declared above.
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
test(); // run self-test implementations
|
||||
return 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;
|
||||
}
|
||||
255
operations_on_datastructures/reverse_binary_tree.cpp
Normal file
255
operations_on_datastructures/reverse_binary_tree.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation for the [Reversing a Binary
|
||||
* Tree](https://www.geeksforgeeks.org/reverse-tree-path/) recursively
|
||||
* algorithm.
|
||||
* @details A binary tree can be reversed by swapping the left and
|
||||
* right child of a node at each node, starting from the root, and
|
||||
* cascading below. This solution aims to provide an implementation of
|
||||
* a recursive reversal of a binary tree.
|
||||
* @author [Alvin](https://github.com/polarvoid)
|
||||
*/
|
||||
|
||||
#include <cassert> /// For assert
|
||||
#include <iostream> /// For IO operations
|
||||
#include <queue> /// For std::queue
|
||||
#include <vector> /// For std::vector
|
||||
|
||||
/**
|
||||
* @namespace operations_on_datastructures
|
||||
* @brief Operations on Data Structures
|
||||
*/
|
||||
namespace operations_on_datastructures {
|
||||
|
||||
/**
|
||||
* @namespace reverse_binary_tree
|
||||
* @brief Functions for the [Reverse a Binary
|
||||
* Tree](https://www.geeksforgeeks.org/reverse-tree-path/) implementation
|
||||
*/
|
||||
namespace reverse_binary_tree {
|
||||
|
||||
/**
|
||||
* @brief A Node struct that represents a single node in a Binary Tree
|
||||
*/
|
||||
struct Node {
|
||||
int64_t data; ///< The value of the Node
|
||||
Node* left; ///< The Node's left child
|
||||
Node* right; ///< The Node's right child
|
||||
/**
|
||||
* @brief Creates a new Node with some initial data
|
||||
*/
|
||||
explicit Node(int64_t _data) {
|
||||
data = _data; ///< Set value of Node data
|
||||
left = nullptr; ///< Initialize left child to NULL
|
||||
right = nullptr; ///< Initialize right child to NULL
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A Binary Tree class that implements a Binary Search Tree
|
||||
*(BST) by default.
|
||||
*/
|
||||
class BinaryTree {
|
||||
private:
|
||||
Node* root; ///< Pointer to root node of Binary Tree
|
||||
/**
|
||||
* @brief inserts a node in the Binary Tree, with the behaviouur of
|
||||
* a Binary Search Tree.
|
||||
* @details Nodes with smaller values are inserted in the left
|
||||
* subtree, and Nodes with larger values are inserted into the
|
||||
* right subtree recursively. Time Complexity: O(log(n))
|
||||
* @param data The data/value of the Node to be inserted
|
||||
* @param pivot A pointer to the root node of the (sub)tree
|
||||
* @returns Node pointer to the root
|
||||
*/
|
||||
Node* insert(int64_t data, Node* pivot) {
|
||||
if (pivot == nullptr) {
|
||||
return new Node(data); ///< Create new node
|
||||
}
|
||||
if (data <= pivot->data) {
|
||||
pivot->left =
|
||||
insert(data, pivot->left); ///< Insert Node to the left
|
||||
} else {
|
||||
pivot->right =
|
||||
insert(data, pivot->right); ///< Insert node to the right
|
||||
}
|
||||
return pivot;
|
||||
}
|
||||
/**
|
||||
* @brief Reverses a Binary Tree recursively by swapping the left and
|
||||
* right subtrees and their children.
|
||||
* @param pivot A reference to the root of the (sub)tree
|
||||
* @returns Node pointer to root node
|
||||
*/
|
||||
Node* reverseBinaryTree(Node* pivot) {
|
||||
if (pivot == nullptr) {
|
||||
return pivot; ///< Base case
|
||||
}
|
||||
Node* temp = pivot->left; ///< pointer to the left subtree
|
||||
pivot->left = reverseBinaryTree(pivot->right); ///< Swap
|
||||
pivot->right = reverseBinaryTree(temp); ///< Swap
|
||||
return pivot;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a BinaryTree with a root pointing to NULL.
|
||||
*/
|
||||
BinaryTree() { root = nullptr; }
|
||||
/**
|
||||
* @brief Creates a BinaryTree with a root with an initial value.
|
||||
*/
|
||||
explicit BinaryTree(int64_t data) { root = new Node(data); }
|
||||
/**
|
||||
* @brief Adds a new Node to the Binary Tree
|
||||
*/
|
||||
void add(int64_t data) { root = insert(data, root); }
|
||||
/**
|
||||
* Reverses the Binary Tree
|
||||
*/
|
||||
void reverse() { root = reverseBinaryTree(root); }
|
||||
/**
|
||||
* @brief Level order traversal of a tree consists of visiting its
|
||||
* elements, top to bottom, left to right. This function performs
|
||||
* level order traversal and returns the node datas as a vector.
|
||||
* @details The function uses a queue to append and remove elements
|
||||
* as they are visited, and then adds their children, if any. This
|
||||
* ensures that the elements are visited layer-by-layer, starting
|
||||
* from the root of the Tree.
|
||||
* @returns vector<int64_t> of nodes of the tree.
|
||||
*/
|
||||
std::vector<int64_t> get_level_order() {
|
||||
std::vector<int64_t> data; ///< Result vector of int
|
||||
if (root == nullptr) {
|
||||
return data; ///< Return empty vector if root is Invalid
|
||||
}
|
||||
std::queue<Node*> nodes; ///< Queue of the nodes in the tree
|
||||
nodes.push(root); ///< Insert root into the queue
|
||||
while (!nodes.empty()) {
|
||||
Node* temp = nodes.front(); ///< Copy the first element
|
||||
data.push_back(temp->data); ///< Add the element to the data
|
||||
nodes.pop(); ///< Remove element
|
||||
if (temp->left != nullptr) {
|
||||
nodes.push(temp->left); ///< Insert left node
|
||||
}
|
||||
if (temp->right != nullptr) {
|
||||
nodes.push(temp->right); ///< Insert right node
|
||||
}
|
||||
} /// Add nodes while Tree is not empty
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* @brief Prints all of the elements in the tree to stdout
|
||||
* level-by-level, using the get_level_order() function.
|
||||
* @returns void
|
||||
*/
|
||||
void print() {
|
||||
for (int i : get_level_order()) {
|
||||
std::cout << i << " "; /// Print each element in the tree
|
||||
}
|
||||
std::cout << "\n"; /// Print newline
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace reverse_binary_tree
|
||||
} // namespace operations_on_datastructures
|
||||
|
||||
/**
|
||||
* @namespace tests
|
||||
* @brief Testcases to check Reversal of Binary Tree.
|
||||
*/
|
||||
namespace tests {
|
||||
using operations_on_datastructures::reverse_binary_tree::
|
||||
BinaryTree; ///< Use the BinaryTree
|
||||
/**
|
||||
* @brief A Test to check an edge case (single element reversal)
|
||||
*/
|
||||
void test1() {
|
||||
BinaryTree bst;
|
||||
std::vector<int64_t> pre_reversal, post_reversal;
|
||||
std::cout << "TEST CASE 1\n";
|
||||
std::cout << "Initializing tree with a single element (5)\n";
|
||||
bst.add(5);
|
||||
pre_reversal = bst.get_level_order();
|
||||
std::cout << "Before reversal: ";
|
||||
bst.print();
|
||||
std::cout << "After reversal: ";
|
||||
bst.reverse();
|
||||
post_reversal = bst.get_level_order();
|
||||
assert(pre_reversal.size() ==
|
||||
post_reversal.size()); ///< Check for equal sizes
|
||||
assert(pre_reversal.size() ==
|
||||
1); ///< Ensure that there is only one element
|
||||
assert(pre_reversal[0] ==
|
||||
post_reversal[0]); ///< Check if both elements are same
|
||||
bst.print();
|
||||
std::cout << "TEST PASSED!\n\n";
|
||||
}
|
||||
/**
|
||||
* @brief A Test to check an edge case (NULL root element)
|
||||
*/
|
||||
void test2() {
|
||||
BinaryTree bst;
|
||||
std::vector<int64_t> pre_reversal, post_reversal;
|
||||
std::cout << "TEST CASE 2\n";
|
||||
std::cout << "Creating empty tree (root points to NULL)\n";
|
||||
pre_reversal = bst.get_level_order();
|
||||
std::cout << "Before reversal: ";
|
||||
bst.print();
|
||||
std::cout << "After reversal: ";
|
||||
bst.reverse();
|
||||
post_reversal = bst.get_level_order();
|
||||
assert(pre_reversal.size() ==
|
||||
post_reversal.size()); ///< Check for equal sizes
|
||||
assert(pre_reversal.size() ==
|
||||
0); ///< Ensure that there is only one element
|
||||
bst.print();
|
||||
std::cout << "TEST PASSED!\n\n";
|
||||
}
|
||||
/**
|
||||
* @brief A Test to check correct reversal of a Binary Tree
|
||||
*/
|
||||
void test3() {
|
||||
BinaryTree bst;
|
||||
std::vector<int64_t> pre_reversal, post_reversal;
|
||||
std::vector<int64_t> pre_res = {4, 3, 6, 2, 5, 7, 1};
|
||||
std::vector<int64_t> post_res = {4, 6, 3, 7, 5, 2, 1};
|
||||
std::cout << "TEST CASE 3\n";
|
||||
std::cout << "Creating tree with elements (4, 6, 3, 2, 5, 7, 1)\n";
|
||||
bst.add(4);
|
||||
bst.add(6);
|
||||
bst.add(3);
|
||||
bst.add(2);
|
||||
bst.add(5);
|
||||
bst.add(7);
|
||||
bst.add(1);
|
||||
pre_reversal = bst.get_level_order();
|
||||
assert(pre_reversal == pre_res); ///< Check for equality
|
||||
std::cout << "Before reversal: ";
|
||||
bst.print();
|
||||
std::cout << "After reversal: ";
|
||||
bst.reverse();
|
||||
post_reversal = bst.get_level_order();
|
||||
assert(post_reversal == post_res); ///< Check for equality
|
||||
bst.print();
|
||||
std::cout << "TEST PASSED!\n\n";
|
||||
}
|
||||
} // namespace tests
|
||||
|
||||
/**
|
||||
* @brief Function to test the correctness of the Tree Reversal
|
||||
*/
|
||||
static void test() {
|
||||
tests::test1(); ///< Single element test
|
||||
tests::test2(); ///< No element test
|
||||
tests::test3(); ///< Correct reversal test
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
@@ -1,79 +1,218 @@
|
||||
//#include <bits/stdc++.h>
|
||||
#incldue < iostream >
|
||||
#define MAX 4000000
|
||||
using namespace std;
|
||||
typedef long long ll;
|
||||
void ConsTree(ll arr[], ll segtree[], ll low, ll high, ll pos) {
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Segment Tree]
|
||||
* (https://en.wikipedia.org/wiki/Segment_tree) data structure
|
||||
*
|
||||
* @details
|
||||
* A segment tree, also known as a statistic tree, is a tree data structure used
|
||||
* for storing information about intervals, or segments. Its classical version
|
||||
* allows querying which of the stored segments contain a given point, but our
|
||||
* modification allows us to perform (query) any binary operation on any range
|
||||
* in the array in O(logN) time. Here, we have used addition (+).
|
||||
* For range updates, we have used lazy propagation.
|
||||
*
|
||||
* * Space Complexity : O(NlogN) \n
|
||||
* * Build Time Complexity : O(NlogN) \n
|
||||
* * Query Time Complexity : O(logN) \n
|
||||
*
|
||||
* @author [Madhav Gaba](https://github.com/madhavgaba)
|
||||
* @author [Soham Roy](https://github.com/sohamroy19)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cmath> /// for log2
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @brief Constructs the initial segment tree
|
||||
*
|
||||
* @param arr input to construct the tree out of
|
||||
* @param segtree the segment tree
|
||||
* @param low inclusive lowest index of arr to begin at
|
||||
* @param high inclusive highest index of arr to end at
|
||||
* @param pos index of segtree to fill (eg. root node)
|
||||
* @returns void
|
||||
*/
|
||||
void ConsTree(const std::vector<int64_t> &arr, std::vector<int64_t> *segtree,
|
||||
uint64_t low, uint64_t high, uint64_t pos) {
|
||||
if (low == high) {
|
||||
segtree[pos] = arr[low];
|
||||
(*segtree)[pos] = arr[low];
|
||||
return;
|
||||
}
|
||||
ll mid = (low + high) / 2;
|
||||
|
||||
uint64_t mid = (low + high) / 2;
|
||||
ConsTree(arr, segtree, low, mid, 2 * pos + 1);
|
||||
ConsTree(arr, segtree, mid + 1, high, 2 * pos + 2);
|
||||
segtree[pos] = segtree[2 * pos + 1] + segtree[2 * pos + 2];
|
||||
(*segtree)[pos] = (*segtree)[2 * pos + 1] + (*segtree)[2 * pos + 2];
|
||||
}
|
||||
ll query(ll segtree[], ll lazy[], ll qlow, ll qhigh, ll low, ll high, ll pos) {
|
||||
if (low > high)
|
||||
|
||||
/**
|
||||
* @brief Returns the sum of all elements in a range
|
||||
*
|
||||
* @param segtree the segment tree
|
||||
* @param lazy for lazy propagation
|
||||
* @param qlow lower index of the required query
|
||||
* @param qhigh higher index of the required query
|
||||
* @param low lower index of query for this function call
|
||||
* @param high higher index of query for this function call
|
||||
* @param pos index of segtree to consider (eg. root node)
|
||||
* @return result of the range query for this function call
|
||||
*/
|
||||
int64_t query(std::vector<int64_t> *segtree, std::vector<int64_t> *lazy,
|
||||
uint64_t qlow, uint64_t qhigh, uint64_t low, uint64_t high,
|
||||
uint64_t pos) {
|
||||
if (low > high || qlow > high || low > qhigh) {
|
||||
return 0;
|
||||
if (qlow > high || qhigh < low)
|
||||
return 0;
|
||||
if (lazy[pos] != 0) {
|
||||
segtree[pos] += lazy[pos] * (high - low + 1);
|
||||
if (low != high) {
|
||||
lazy[2 * pos + 1] += lazy[pos];
|
||||
lazy[2 * pos + 2] += lazy[pos];
|
||||
}
|
||||
lazy[pos] = 0;
|
||||
}
|
||||
if (qlow <= low && qhigh >= high)
|
||||
return segtree[pos];
|
||||
ll mid = (low + high) / 2;
|
||||
|
||||
if ((*lazy)[pos] != 0) {
|
||||
(*segtree)[pos] += (*lazy)[pos] * (high - low + 1);
|
||||
|
||||
if (low != high) {
|
||||
(*lazy)[2 * pos + 1] += (*lazy)[pos];
|
||||
(*lazy)[2 * pos + 2] += (*lazy)[pos];
|
||||
}
|
||||
(*lazy)[pos] = 0;
|
||||
}
|
||||
|
||||
if (qlow <= low && qhigh >= high) {
|
||||
return (*segtree)[pos];
|
||||
}
|
||||
|
||||
uint64_t mid = (low + high) / 2;
|
||||
|
||||
return query(segtree, lazy, qlow, qhigh, low, mid, 2 * pos + 1) +
|
||||
query(segtree, lazy, qlow, qhigh, mid + 1, high, 2 * pos + 2);
|
||||
}
|
||||
void update(ll segtree[], ll lazy[], ll start, ll end, ll delta, ll low,
|
||||
ll high, ll pos) {
|
||||
if (low > high)
|
||||
|
||||
/**
|
||||
* @brief Updates a range of the segment tree
|
||||
*
|
||||
* @param segtree the segment tree
|
||||
* @param lazy for lazy propagation
|
||||
* @param start lower index of the required query
|
||||
* @param end higher index of the required query
|
||||
* @param delta integer to add to each element of the range
|
||||
* @param low lower index of query for this function call
|
||||
* @param high higher index of query for this function call
|
||||
* @param pos index of segtree to consider (eg. root node)
|
||||
* @returns void
|
||||
*/
|
||||
void update(std::vector<int64_t> *segtree, std::vector<int64_t> *lazy,
|
||||
int64_t start, int64_t end, int64_t delta, uint64_t low,
|
||||
uint64_t high, uint64_t pos) {
|
||||
if (low > high) {
|
||||
return;
|
||||
if (lazy[pos] != 0) {
|
||||
segtree[pos] += lazy[pos] * (high - low + 1);
|
||||
if (low != high) {
|
||||
lazy[2 * pos + 1] += lazy[pos];
|
||||
lazy[2 * pos + 2] += lazy[pos];
|
||||
}
|
||||
lazy[pos] = 0;
|
||||
}
|
||||
if (start > high || end < low)
|
||||
|
||||
if ((*lazy)[pos] != 0) {
|
||||
(*segtree)[pos] += (*lazy)[pos] * (high - low + 1);
|
||||
|
||||
if (low != high) {
|
||||
(*lazy)[2 * pos + 1] += (*lazy)[pos];
|
||||
(*lazy)[2 * pos + 2] += (*lazy)[pos];
|
||||
}
|
||||
(*lazy)[pos] = 0;
|
||||
}
|
||||
|
||||
if (start > high || end < low) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (start <= low && end >= high) {
|
||||
segtree[pos] += delta * (high - low + 1);
|
||||
(*segtree)[pos] += delta * (high - low + 1);
|
||||
|
||||
if (low != high) {
|
||||
lazy[2 * pos + 1] += delta;
|
||||
lazy[2 * pos + 2] += delta;
|
||||
(*lazy)[2 * pos + 1] += delta;
|
||||
(*lazy)[2 * pos + 2] += delta;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
ll mid = (low + high) / 2;
|
||||
|
||||
uint64_t mid = (low + high) / 2;
|
||||
|
||||
update(segtree, lazy, start, end, delta, low, mid, 2 * pos + 1);
|
||||
update(segtree, lazy, start, end, delta, mid + 1, high, 2 * pos + 2);
|
||||
segtree[pos] = segtree[2 * pos + 1] + segtree[2 * pos + 2];
|
||||
(*segtree)[pos] = (*segtree)[2 * pos + 1] + (*segtree)[2 * pos + 2];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self-test implementation
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
int64_t max = static_cast<int64_t>(2 * pow(2, ceil(log2(7))) - 1);
|
||||
assert(max == 15);
|
||||
|
||||
std::vector<int64_t> arr{1, 2, 3, 4, 5, 6, 7}, lazy(max), segtree(max);
|
||||
ConsTree(arr, &segtree, 0, 7 - 1, 0);
|
||||
|
||||
assert(query(&segtree, &lazy, 1, 5, 0, 7 - 1, 0) == 2 + 3 + 4 + 5 + 6);
|
||||
|
||||
update(&segtree, &lazy, 2, 4, 1, 0, 7 - 1, 0);
|
||||
assert(query(&segtree, &lazy, 1, 5, 0, 7 - 1, 0) == 2 + 4 + 5 + 6 + 6);
|
||||
|
||||
update(&segtree, &lazy, 0, 6, -2, 0, 7 - 1, 0);
|
||||
assert(query(&segtree, &lazy, 0, 4, 0, 7 - 1, 0) == -1 + 0 + 2 + 3 + 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
*
|
||||
* @return 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
ll n, c;
|
||||
scanf("%lld %lld", &n, &c);
|
||||
ll arr[n] = {0}, p, q, v, choice;
|
||||
ll segtree[MAX], lazy[MAX] = {0};
|
||||
ConsTree(arr, segtree, 0, n - 1, 0);
|
||||
while (c--) {
|
||||
scanf("%lld", &choice);
|
||||
if (choice == 0) {
|
||||
scanf("%lld %lld %lld", &p, &q, &v);
|
||||
update(segtree, lazy, p - 1, q - 1, v, 0, n - 1, 0);
|
||||
} else {
|
||||
scanf("%lld %lld", &p, &q);
|
||||
printf("%lld\n", query(segtree, lazy, p - 1, q - 1, 0, n - 1, 0));
|
||||
test(); // run self-test implementations
|
||||
|
||||
std::cout << "Enter number of elements: ";
|
||||
|
||||
uint64_t n = 0;
|
||||
std::cin >> n;
|
||||
|
||||
uint64_t max = static_cast<uint64_t>(2 * pow(2, ceil(log2(n))) - 1);
|
||||
std::vector<int64_t> arr(n), lazy(max), segtree(max);
|
||||
|
||||
int choice = 0;
|
||||
std::cout << "\nDo you wish to enter each number?:\n"
|
||||
"1: Yes\n"
|
||||
"0: No (default initialize them to 0)\n";
|
||||
|
||||
std::cin >> choice;
|
||||
if (choice == 1) {
|
||||
std::cout << "Enter " << n << " numbers:\n";
|
||||
for (int i = 1; i <= n; i++) {
|
||||
std::cout << i << ": ";
|
||||
std::cin >> arr[i];
|
||||
}
|
||||
}
|
||||
|
||||
ConsTree(arr, &segtree, 0, n - 1, 0);
|
||||
|
||||
do {
|
||||
std::cout << "\nMake your choice:\n"
|
||||
"1: Range update (input)\n"
|
||||
"2: Range query (output)\n"
|
||||
"0: Exit\n";
|
||||
std::cin >> choice;
|
||||
|
||||
if (choice == 1) {
|
||||
std::cout << "Enter 1-indexed lower bound, upper bound & value:\n";
|
||||
|
||||
uint64_t p = 1, q = 1, v = 0;
|
||||
std::cin >> p >> q >> v;
|
||||
update(&segtree, &lazy, p - 1, q - 1, v, 0, n - 1, 0);
|
||||
} else if (choice == 2) {
|
||||
std::cout << "Enter 1-indexed lower bound & upper bound:\n";
|
||||
|
||||
uint64_t p = 1, q = 1;
|
||||
std::cin >> p >> q;
|
||||
std::cout << query(&segtree, &lazy, p - 1, q - 1, 0, n - 1, 0);
|
||||
std::cout << "\n";
|
||||
}
|
||||
} while (choice > 0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user