#include <iostream>
#include <set>
#include <vector>
using namespace std;
// Pair class for the value and its index
struct Pair {
int value, index;
// Constructor
Pair(int v, int p)
: value(v)
, index(p)
{
}
// This method will be used by the set to
// search a value by index and setting the tree
// nodes (left or right)
bool operator<(const Pair& o) const
{
// Two nodes are equal only when
// their indices are the same
if (index == o.index) {
return false;
}
else if (value == o.value) {
return index < o.index;
}
else {
return value < o.value;
}
}
// Function to return the value
// of the current object
int getValue() const { return value; }
// Update the value and the position
// for the same object to save space
void renew(int v, int p)
{
value = v;
index = p;
}
// Override the << operator for easy printing
friend ostream& operator<<(ostream& os,
const Pair& pair)
{
return os << "(" << pair.value << ", " << pair.index
<< ")";
}
};
// Function to print the median for the current window
void printMedian(multiset<Pair>& minSet,
multiset<Pair>& maxSet, int window)
{
// If the window size is even then the
// median will be the average of the
// two middle elements
if (window % 2 == 0) {
auto minSetLast = minSet.rbegin();
auto maxSetFirst = maxSet.begin();
double median = (minSetLast->getValue()
+ maxSetFirst->getValue())
/ 2.0;
cout << median << " ";
}
// Else it will be the middle element
else {
if (minSet.size() > maxSet.size()) {
auto minSetLast = minSet.rbegin();
cout << minSetLast->getValue() << " ";
}
else {
auto maxSetFirst = maxSet.begin();
cout << maxSetFirst->getValue() << " ";
}
}
}
// Function to find the median
// of every window of size k
void findMedian(int arr[], int n, int k)
{
multiset<Pair> minSet;
multiset<Pair> maxSet;
// To hold the pairs, we will use a vector
vector<Pair> windowPairs(
k, Pair(0, 0)); // Initialize with dummy values
for (int i = 0; i < k; i++) {
windowPairs[i].renew(arr[i], i);
}
// Add k/2 items to maxSet
for (int i = 0; i < k / 2; i++) {
maxSet.insert(windowPairs[i]);
}
for (int i = k / 2; i < k; i++) {
// Below logic is to maintain the
// maxSet and the minSet criteria
if (arr[i] < maxSet.begin()->getValue()) {
minSet.insert(windowPairs[i]);
}
else {
minSet.insert(*maxSet.begin());
maxSet.erase(maxSet.begin());
maxSet.insert(windowPairs[i]);
}
}
printMedian(minSet, maxSet, k);
for (int i = k; i < n; i++) {
// Get the pair at the start of the window, this
// will reset to 0 at every k, 2k, 3k, ...
Pair& temp = windowPairs[i % k];
if (temp.getValue()
<= minSet.rbegin()->getValue()) {
// Remove the starting pair of the window
minSet.erase(minSet.find(temp));
// Renew window start to new window end
temp.renew(arr[i], i);
// Below logic is to maintain the
// maxSet and the minSet criteria
if (temp.getValue()
< maxSet.begin()->getValue()) {
minSet.insert(temp);
}
else {
minSet.insert(*maxSet.begin());
maxSet.erase(maxSet.begin());
maxSet.insert(temp);
}
}
else {
maxSet.erase(maxSet.find(temp));
temp.renew(arr[i], i);
// Below logic is to maintain the
// maxSet and the minSet criteria
if (temp.getValue()
> minSet.rbegin()->getValue()) {
maxSet.insert(temp);
}
else {
maxSet.insert(*minSet.rbegin());
minSet.erase(--minSet.end());
minSet.insert(temp);
}
}
printMedian(minSet, maxSet, k);
}
}
// Driver code
int main()
{
int arr[] = { 0, 9, 1, 8, 2, 7, 3, 6, 4, 5 };
int k = 3;
int n = sizeof(arr) / sizeof(arr[0]);
findMedian(arr, n, k);
return 0;
}