Merge branch 'scheduling' of https://github.com/Pratyush219/C-Plus-Plus into scheduling

This commit is contained in:
Pratyush219 2021-10-12 11:53:37 +05:30
commit 295f0cc6d1
3 changed files with 263 additions and 21 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)
@ -267,6 +270,7 @@
* [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)
* [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)
## Range Queries
* [Fenwick Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/range_queries/fenwick_tree.cpp)

View File

@ -16,14 +16,14 @@
using std::cin;
using std::cout;
using std::get;
using std::priority_queue;
using std::unordered_set;
using std::make_tuple;
using std::vector;
using std::tuple;
using std::endl;
using std::get;
using std::left;
using std::make_tuple;
using std::priority_queue;
using std::tuple;
using std::unordered_set;
using std::vector;
/**
* @class Compare
@ -73,15 +73,19 @@ class FCFS{
* 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;
*/
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:
public:
/**
* @brief adds the process to the ready queue if it isn't already there
* @param ID: Process ID
@ -97,7 +101,6 @@ class FCFS{
schedule.push(t);
idList.insert(id);
}
}
/**
@ -115,11 +118,12 @@ class FCFS{
// Variable to keep track of time elapsed so far
double timeElapsed = 0;
while(!schedule.empty()){
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){
// If the next 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;
}
@ -165,8 +169,6 @@ class FCFS{
<< std::setw(17) << left << get<5>(result[i]) << endl;
}
}
};
/**
@ -174,17 +176,17 @@ class FCFS{
* @returns 0 on exit
*/
int main(){
FCFS<unsigned int ,unsigned int, unsigned int> readyQueue;
FCFS<uint32_t ,uint32_t, uint32_t> readyQueue;
//Sample test case
// Sample test case
int n = 3;
vector<tuple<unsigned int, unsigned int, unsigned int>> input = {
vector<tuple<uint32_t, uint32_t, uint32_t>> input = {
make_tuple(1, 0, 30),
make_tuple(2, 0, 5),
make_tuple(3, 0, 5)
};
for(unsigned int i{}; i < n; i++){
for(uint32_t i{}; i < n; i++){
readyQueue.addProcess(get<0>(input[i]), get<1>(input[i]), get<2>(input[i]));
}

View File

@ -0,0 +1,236 @@
/**
* @file
* @brief An implementation of a median calculation of a sliding window along a
* 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
* 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),
* with the proper modifications to account for the finite window size for which
* the median is requested
*
* ### Algorithm
* The sliding window is managed by a list, which guarantees O(1) for both
* 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)
*
* Time complexity: O(logN). Space complexity: O(N). N - size of window
* @author [Yaniv Hollander](https://github.com/YanivHollander)
*/
#include <cassert> /// for assert
#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
/**
* @namespace probability
* @brief Probability algorithms
*/
namespace probability {
/**
* @namespace windowed_median
* @brief Functions for the Windowed Median algorithm implementation
*/
namespace windowed_median {
using Window = std::list<int>;
using size_type = Window::size_type;
/**
* @class WindowedMedian
* @brief A class to calculate the median of a leading sliding window at the
* back of a stream of integer values.
*/
class WindowedMedian {
const size_type _windowSize; ///< sliding window size
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
_itMedian; ///< an iterator that points to the root of the multi-value
/// BST
/**
* @brief Inserts a value to a sorted multi-value BST
* @param value Value to insert
*/
void insertToSorted(int value) {
_sortedValues.insert(value); /// Insert value to BST - O(logN)
const auto sz = _sortedValues.size();
if (sz == 1) { /// For the first value, set median iterator to BST root
_itMedian = _sortedValues.begin();
return;
}
/// If new value goes to left tree branch, and number of elements is
/// even, the new median in the balanced tree is the left child of the
/// median before the insertion
if (value < *_itMedian && sz % 2 == 0) {
--_itMedian; // O(1) - traversing one step to the left child
}
/// However, if the new value goes to the right branch, the previous
/// median's right child is the new median in the balanced tree
else if (value >= *_itMedian && sz % 2 != 0) {
++_itMedian; /// O(1) - traversing one step to the right child
}
}
/**
* @brief Erases a value from a sorted multi-value BST
* @param value Value to insert
*/
void eraseFromSorted(int value) {
const auto sz = _sortedValues.size();
/// If the erased value is on the left branch or the median itself and
/// the number of elements is even, the new median will be the right
/// child of the current one
if (value <= *_itMedian && sz % 2 == 0) {
++_itMedian; /// O(1) - traversing one step to the right child
}
/// 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
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
const auto it = _sortedValues.find(value); // O(logN)
_sortedValues.erase(it); // O(logN)
}
public:
/**
* @brief Constructs a WindowedMedian object
* @param windowSize Sliding window size
*/
explicit WindowedMedian(size_type windowSize) : _windowSize(windowSize){};
/**
* @brief Insert a new value to the stream
* @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)
}
}
/**
* @brief Gets the median of the values in the sliding window
* @return Median of sliding window. For even window size return the average
* between the two values in the middle
*/
float getMedian() const {
if (_sortedValues.size() % 2 != 0) {
return *_itMedian; // O(1)
}
return 0.5f * *_itMedian + 0.5f * *next(_itMedian); /// O(1)
}
/**
* @brief A naive and inefficient method to obtain the median of the sliding
* window. Used for testing!
* @return Median of sliding window. For even window size return the average
* between the two values in the middle
*/
float getMedianNaive() const {
auto window = _window;
window.sort(); /// Sort window - O(NlogN)
auto median =
*next(window.begin(),
window.size() / 2); /// Find value in the middle - O(N)
if (window.size() % 2 != 0) {
return median;
}
return 0.5f * median +
0.5f * *next(window.begin(), window.size() / 2 - 1); /// O(N)
}
};
} // namespace windowed_median
} // namespace probability
/**
* @brief Self-test implementations
* @param vals Stream of values
* @param windowSize Size of sliding window
*/
static void test(const std::vector<int> &vals, int windowSize) {
probability::windowed_median::WindowedMedian windowedMedian(windowSize);
for (const auto val : vals) {
windowedMedian.insert(val);
/// Comparing medians: efficient function vs. Naive one
assert(windowedMedian.getMedian() == windowedMedian.getMedianNaive());
}
}
/**
* @brief Main function
* @param argc command line argument count (ignored)
* @param argv command line array of arguments (ignored)
* @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({470211272, 101027544, 1457850878, 1458777923, 2007237709, 823564440,
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]
vals.clear();
vals.reserve(n);
for (int i = 0; i < n; i++) {
vals.push_back(
rand() - RAND_MAX); /// Random array values (positive/negative)
}
test(vals, windowSize); /// Testing randomized test
}
return 0;
}