Median Of Running Stream of Numbers in C++

C++Server Side ProgrammingProgramming

In this problem, we are given a data stream that is continuously reading integers. Our task is to create a program that will read elements and calculate the medians for these elements.

The Median of an array is the middle element from a sorted sequence(it can be ascending or descending).

Calculating median

For odd count, the median is the middle element

For even count, the median is average of two middle element

Let’s take an example to understand the problem,

Input − 3, 65, 12, 20, 1

At each input,

Input - 3 : sequence -(3) : median - 3
Input - 65 : sequence -(3, 65) : median - 34
Input - 12 : sequence -(3, 12, 65) : median - 12
Input - 20 : sequence -(3, 12, 20, 65) : median - 16
Input - 1 : sequence -(1, 3, 12, 20, 65) : median - 12

We have used the sorted sequence here to make the median calculation easy.

To solve this problem, we have multiple solutions that are using sorting at each step and then finding the median, creating a self-balancing BST, or using heaps. The heap seems to be the most promising solution to find the median. Both max-heap or min-heap can provide us with the median at every insertion and is an effective solution too.

Example

Program to show the implementation of our solution,

 Live Demo

#include <iostream>
using namespace std;
#define MAX_HEAP_SIZE (128)
#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
void swap(int &a, int &b){
   int temp = a;
   a = b;
   b = temp;
}
bool Greater(int a, int b){
   return a > b;
}
bool Smaller(int a, int b){
   return a < b;
}
int Signum(int a, int b){
   if( a == b )
      return 0;
   return a < b ? -1 : 1;
}
class Heap{
   public:
      Heap(int *b, bool (*c)(int, int)) : A(b), comp(c)
      { heapSize = -1; }
      virtual bool Insert(int e) = 0;
      virtual int GetTop() = 0;
      virtual int ExtractTop() = 0;
      virtual int GetCount() = 0;
      protected:
      int left(int i) {
         return 2 * i + 1;
      }
      int right(int i) {
         return 2 * (i + 1);
      }
      int parent(int i) {
         if( i <= 0 ){
            return -1;
         }
         return (i - 1)/2;
      }
      int *A;
      bool (*comp)(int, int);
      int heapSize;
      int top(void){
         int max = -1;
         if( heapSize >= 0 )
            max = A[0];
         return max;
      }
      int count() {
         return heapSize + 1;
      }
      void heapify(int i){
         int p = parent(i);
         if( p >= 0 && comp(A[i], A[p]) ) {
            swap(A[i], A[p]);
            heapify(p);
         }
      }
      int deleteTop(){
         int del = -1;
         if( heapSize > -1){
            del = A[0];
            swap(A[0], A[heapSize]);
            heapSize--;
            heapify(parent(heapSize+1));
         }
         return del;
      }
      bool insertHelper(int key){
         bool ret = false;
         if( heapSize < MAX_HEAP_SIZE ){
            ret = true;
            heapSize++;
            A[heapSize] = key;
            heapify(heapSize);
         }
         return ret;
      }
};
class MaxHeap : public Heap {
   private:
   public:
      MaxHeap() : Heap(new int[MAX_HEAP_SIZE], &Greater) { }
      int GetTop() {
         return top();
      }
      int ExtractTop() {
         return deleteTop();
      }
      int GetCount() {
         return count();
      }
      bool Insert(int key) {
         return insertHelper(key);
      }
};
class MinHeap : public Heap{
   private:
   public:
      MinHeap() : Heap(new int[MAX_HEAP_SIZE], &Smaller) { }
      int GetTop() {
         return top();
      }
      int ExtractTop() {
         return deleteTop();
      }
      int GetCount() {
         return count();
      }
      bool Insert(int key) {
         return insertHelper(key);
      }
};
int findMedian(int e, int &median, Heap &left, Heap &right){
   switch(Signum(left.GetCount(), right.GetCount())){
      case 0: if( e < median ) {
         left.Insert(e);
         median = left.GetTop();
      }
      else{
         right.Insert(e);
         median = right.GetTop();
      }
      break;
      case 1: if( e < median ){
         right.Insert(left.ExtractTop());
         left.Insert(e);
      }
      else
         right.Insert(e);
         median = ((left.GetTop()+right.GetTop())/2);
      break;
      case -1: if( e < median )
         left.Insert(e);
      else {
         left.Insert(right.ExtractTop());
         right.Insert(e);
      }
      median = ((left.GetTop()+right.GetTop())/2);
      break;
   }
   return median;
}
void printMedianStream(int A[], int size){
   int median = 0;
   Heap *left = new MaxHeap();
   Heap *right = new MinHeap();
   for(int i = 0; i < size; i++) {
      median = findMedian(A[i], median, *left, *right);
      cout<<"Median of elements : ";
      for(int j = 0; j<=i;j++) cout<<A[j]<<" ";
      cout<<"is "<<median<<endl;
   }
}
int main(){
   int A[] = {12, 54, 9, 6, 1};
   int size = ARRAY_SIZE(A);
   printMedianStream(A, size);
   return 0;
}

Output

Median of elements : 12 is 12
Median of elements : 12 54 is 33
Median of elements : 12 54 9 is 12
Median of elements : 12 54 9 6 is 10
Median of elements : 12 54 9 6 1 is 9
raja
Published on 10-Feb-2020 14:59:06
Advertisements