Open In App

Find Median from Running Data Stream

Last Updated : 15 Oct, 2025
Suggest changes
Share
138 Likes
Like
Report

Given a data stream arr[] where integers are read sequentially, Determine the median of the elements encountered so far after each new integer is read.

There are two cases for median on the basis of data set size.

  • If the data set has an odd number then the middle one will be consider as median.
  • If the data set has an even number then there is no distinct middle value and the median will be the arithmetic mean of the two middle values.

Example:

Input: arr[] = [5, 15, 1, 3, 2, 8]
Output: [5.00, 10.00, 5.00, 4.00, 3.00, 4.00]
Explanation:
After reading 1st element of stream - 5 -> median = 5
After reading 2nd element of stream - 5, 15 -> median = (5+15)/2 = 10
After reading 3rd element of stream - 5, 15, 1 -> median = 5
After reading 4th element of stream - 5, 15, 1, 3 -> median = (3+5)/2 = 4
After reading 5th element of stream - 5, 15, 1, 3, 2 -> median = 3
After reading 6th element of stream - 5, 15, 1, 3, 2, 8 -> median = (3+5)/2 = 4

Input: arr[] = [2, 2, 2, 2]
Output: [2.00, 2.00, 2.00, 2.00]
Explanation:
After reading 1st element of stream - 2 -> median = 2
After reading 2nd element of stream - 2, 2 -> median = (2+2)/2 = 2
After reading 3rd element of stream - 2, 2, 2 -> median = 2
After reading 4th element of stream - 2, 2, 2, 2 -> median = (2+2)/2 = 2

[Naive Approach] Using Insertion Sort

If we know the sorted order of elements till the current index, we can easily find the median of running stream through the middle element. To keep the sorted order, we use the insertion sort approach at each step, insert the new element into its correct position. Once the list is sorted up to the current index, we find the median using the total number of elements so far:

  • If the count is even, take the arithmetic mean of the two middle elements.
  • If the count is odd, take the middle element as the median.

Why Insertion Sort?
Insertion Sort allows to maintain the running sorted array. At each step, we simply insert the current element into its correct position in the already sorted part, making it easy to find the median.

C++
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;

vector<double> getMedian(vector<int> &arr) {
    vector<double> res;

    res.push_back(arr[0]);

    for (int i = 1; i < arr.size(); i++) {
        int j = i - 1;
        int num = arr[i];

        // shift elements to right to create space to insert
        // the current element at its correct position
        while (j >= 0 && arr[j] > num) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = num;
        
        int len = i + 1;
        double median;

        // If odd number of integers are read from stream
        // then middle element in sorted order is median
        // else average of middle elements is median
        if (len % 2 != 0) {
            median = arr[len / 2];
        }
        else {
            median = (double)(arr[(len / 2) - 1] + arr[len / 2]) / 2;
        }

        res.push_back(median);
    }
    
    return res;
}

int main() {
    vector<int> arr = {5, 15, 1, 3, 2, 8};
    vector<double> res = getMedian(arr);
    cout << fixed << setprecision(2);
    
    for (double median: res) 
        cout << median << " ";
    return 0;
}
Java
import java.util.ArrayList;
import java.util.Arrays;

class GfG {
    
    static ArrayList<Double> getMedian(int[] arr) {
        ArrayList<Double> res = new ArrayList<>();
        res.add((double) arr[0]);

        for (int i = 1; i < arr.length; i++) {
            int j = i - 1;
            int num = arr[i];

            // shift elements to right to create space to insert
            // the current element at its correct position
            while (j >= 0 && arr[j] > num) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = num;

            int len = i + 1;
            double median;

            // If odd number of integers are read from stream
            // then middle element in sorted order is median
            // else average of middle elements is median
            if (len % 2 != 0) {
                median = arr[len / 2];
            } else {
                median = (arr[(len / 2) - 1] + arr[len / 2]) / 2.0;
            }

            res.add(median);
        }

        return res;
    }

    public static void main(String[] args) {
        int[] arr = {5, 15, 1, 3, 2, 8};
        ArrayList<Double> res = getMedian(arr);
        
        for (int i = 0; i < res.size(); i++) {
            System.out.printf("%.2f ", res.get(i));
        }
    }
}
Python
def getMedian(arr):
    res = []
    
    res.append(float(arr[0]))

    for i in range(1, len(arr)):
        j = i - 1
        num = arr[i]

        # shift elements to right to create space to insert
        # the current element at its correct position
        while j >= 0 and arr[j] > num:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = num

        length = i + 1

        # If odd number of integers are read from stream
        # then middle element in sorted order is median
        # else average of middle elements is median
        if length % 2 != 0:
            median = arr[length // 2]
        else:
            median = (arr[(length // 2) - 1] + arr[length // 2]) / 2.0

        res.append(median)

    return res

if __name__ == '__main__':
    arr = [5, 15, 1, 3, 2, 8]
    res = getMedian(arr)
    
    print(" ".join(f"{median:.2f}" for median in res))
C#
using System;
using System.Collections.Generic;

class GfG {
    
    static List<double> getMedian(int[] arr) {
        List<double> res = new List<double>();
        res.Add(arr[0]);

        for (int i = 1; i < arr.Length; i++) {
            int j = i - 1;
            int num = arr[i];

            // shift elements to right to create space to insert
            // the current element at its correct position
            while (j >= 0 && arr[j] > num) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = num;

            int len = i + 1;
            double median;

            // If odd number of integers are read from stream
            // then middle element in sorted order is median
            // else average of middle elements is median
            if (len % 2 != 0) {
                median = arr[len / 2];
            }
            else {
                median = (arr[(len / 2) - 1] + arr[len / 2]) / 2.0;
            }

            res.Add(median);
        }

        return res;
    }

    static void Main() {
        int[] arr = { 5, 15, 1, 3, 2, 8 };
        List<double> res = getMedian(arr);
        
        for (int i = 0; i < res.Count; i++)
            Console.Write(res[i].ToString("0.00") + " ");
        
    }
}
JavaScript
function getMedian(arr) {
    let res = [];

    res.push(arr[0]);

    for (let i = 1; i < arr.length; i++) {
        let j = i - 1;
        let num = arr[i];

        // shift elements to right to create space to insert
        // the current element at its correct position
        while (j >= 0 && arr[j] > num) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = num;

        let len = i + 1;
        let median;

        // If odd number of integers are read from stream
        // then middle element in sorted order is median
        // else average of middle elements is median
        if (len % 2 !== 0) {
            median = arr[Math.floor(len / 2)];
        } else {
            median = (arr[len / 2 - 1] + arr[len / 2]) / 2.0;
        }

        res.push(median);
    }

    return res;
}

// Driver Code
let arr = [5, 15, 1, 3, 2, 8];
let res = getMedian(arr);

console.log(res.map(median => median.toFixed(2)).join(" "));

Output
5.00 10.00 5.00 4.00 3.00 4.00 

Time Complexity: O(n2), Insertion Sort takes O(n²) time to sort n elements. Using binary search can find the position for the next element in O(log n) time, but moving the elements still takes linear time. So, even with optimizations, Insertion Sort remains a polynomial-time algorithm.

Auxiliary Space: O(1)

[Expected Approach] Using Heaps

The median of an array occurs at the center of sorted array, so the idea is to store the current elements in two nearly equal parts. A max heap (left half) stores the smaller elements, ensuring the largest among them is at the top, while a min heap (right half) stores the larger elements, keeping the smallest at the top.

There are three steps to find the median of running stream.

Step 1: Process each new element

  • If the new element is less than or equal to max of left heap, push it into max-heap, Otherwise, push it into min-heap.

Step 2: Balance the heaps

  • The size difference of heaps should be at most 1.If one heap has more than 1 extra element, move the top element to the other heap.

Step 3: Find the median

  • If both heaps have same size, median = (max of left + min of right) / 2.
  • If heaps have different sizes, median = top of the heap with more elements.
C++
#include <iostream>
#include <vector>
#include <queue>
#include <iomanip>
using namespace std;

vector<double> getMedian(vector<int> &arr) {
    
    // Max heap to store the smaller half of numbers
    priority_queue<int> leftMaxHeap;
    
    // Min heap to store the greater half of numbers
    priority_queue<int, vector<int>, greater<int>> rightMinHeap;
    
    vector<double> res;
  
    for (int i = 0; i < arr.size(); i++) {
        
        // Insert new element into max heap
        leftMaxHeap.push(arr[i]);
        
        // Move the top of max heap to min heap to maintain order
        int temp = leftMaxHeap.top();
        leftMaxHeap.pop();
        rightMinHeap.push(temp);
      
        // Balance heaps if min heap has more elements
        if (rightMinHeap.size() > leftMaxHeap.size()) {
            temp = rightMinHeap.top();
            rightMinHeap.pop();
            leftMaxHeap.push(temp);
        }
        
        // Compute median based on heap sizes
        double median;
        
        if (leftMaxHeap.size() != rightMinHeap.size())
            median = leftMaxHeap.top();
        else
            median = (double)(leftMaxHeap.top() + rightMinHeap.top()) / 2;
        
        res.push_back(median);
    }
    
    return res;
}


int main() {
    vector<int> arr = {5, 15, 1, 3, 2, 8};
    vector<double> res = getMedian(arr);
    cout << fixed << setprecision(2);
    
    for (double median: res) 
        cout << median << " ";
    return 0;
}
Java
import java.util.PriorityQueue;
import java.util.ArrayList;

class GfG {
    static ArrayList<Double> getMedian(int[] arr) {
        
        // Max heap to store the smaller half of numbers
        PriorityQueue<Integer> leftMaxHeap = new PriorityQueue<>((a, b) -> b - a);
        
        // Min heap to store the greater half of numbers
        PriorityQueue<Integer> rightMinHeap = new PriorityQueue<>();
        
        ArrayList<Double> res = new ArrayList<>();
      
        for (int i = 0; i < arr.length; i++) {
            
            // Insert new element into max heap
            leftMaxHeap.add(arr[i]);
            
            // Move the top of max heap to min heap to maintain order
            int temp = leftMaxHeap.poll();
            rightMinHeap.add(temp);
          
            // Balance heaps if min heap has more elements
            if (rightMinHeap.size() > leftMaxHeap.size()) {
                temp = rightMinHeap.poll();
                leftMaxHeap.add(temp);
            }
            
            // Compute median based on heap sizes
            double median;
            if (leftMaxHeap.size() != rightMinHeap.size())
                median = leftMaxHeap.peek();
            else
                median = (leftMaxHeap.peek() + rightMinHeap.peek()) / 2.0;
            
            res.add(median);
        }
        
        return res;
    }

    public static void main(String[] args) {
        int[] arr = {5, 15, 1, 3, 2, 8};
        ArrayList<Double> res = getMedian(arr);
        System.out.printf("%.2f", res.get(0));
        
        for (int i = 1; i < res.size(); i++) {
            System.out.printf(" %.2f", res.get(i));
        }
    }
}
Python
import heapq

def getMedian(arr):
    
    # Max heap to store the smaller half of numbers
    leftMaxHeap = []
    
    # Min heap to store the greater half of numbers
    rightMinHeap = []
    
    res = []
  
    for num in arr:
        # Insert new element into 
        #max heap 
        heapq.heappush(leftMaxHeap, -num)
        
        # Move the top of max heap to min heap to maintain order
        temp = -heapq.heappop(leftMaxHeap)
        heapq.heappush(rightMinHeap, temp)
      
        # Balance heaps if min heap has more elements
        if len(rightMinHeap) > len(leftMaxHeap):
            temp = heapq.heappop(rightMinHeap)
            heapq.heappush(leftMaxHeap, -temp)
        
        # Compute median based on heap sizes
        if len(leftMaxHeap) != len(rightMinHeap):
            median = -leftMaxHeap[0]
        else:
            median = (-leftMaxHeap[0] + rightMinHeap[0]) / 2.0
        
        res.append(median)
    
    return res


if __name__ == "__main__":
    arr = [5, 15, 1, 3, 2, 8]
    res = getMedian(arr)
    
    print(" ".join(f"{median:.2f}" for median in res))
C#
using System;
using System.Collections.Generic;
using System.Linq;

class GfG {
    static void insert(SortedDictionary<int, int> heap, int num, ref int size) {
        if (heap.ContainsKey(num))
            heap[num]++;
        else
            heap[num] = 1;
        size++;
    }

    static void remove(SortedDictionary<int, int> heap, int num, ref int size) {
        if (heap[num] == 1)
            heap.Remove(num);
        else
            heap[num]--;
        size--;
    }

    static int getMax(SortedDictionary<int, int> heap) => heap.First().Key;
    static int getMin(SortedDictionary<int, int> heap) => heap.First().Key;
    
    static List<double> getMedian(int[] arr) {
        
        // Max heap for the smaller half 
        SortedDictionary<int, int> leftMaxHeap = new SortedDictionary
            <int, int>(Comparer<int>.Create((a, b) => b.CompareTo(a)));
        int leftSize = 0;

        // Min heap for the greater half 
        SortedDictionary<int, int> rightMinHeap = new SortedDictionary
                            <int, int>();
        int rightSize = 0;

        List<double> res = new List<double>();

        foreach (int num in arr) {
            
            // Insert into max heap
            insert(leftMaxHeap, num, ref leftSize);

            // Move the top of max heap to min heap to maintain order
            int temp = getMax(leftMaxHeap);
            remove(leftMaxHeap, temp, ref leftSize);
            insert(rightMinHeap, temp, ref rightSize);

            // Balance heaps if min heap has more elements
            if (rightSize > leftSize) {
                temp = getMin(rightMinHeap);
                remove(rightMinHeap, temp, ref rightSize);
                insert(leftMaxHeap, temp, ref leftSize);
            }

            //Compute median based on heap sizes
            double median;
            if (leftSize != rightSize)
                median = getMax(leftMaxHeap);
            else
                median = (getMax(leftMaxHeap) + getMin(rightMinHeap)) / 2.0;

            res.Add(median);
        }

        return res;
    }

    static void Main() {
        int[] arr = {5, 15, 1, 3, 2, 8};
        List<double> res = getMedian(arr);
        
        foreach (double median in res)
            Console.Write(median.ToString("F2") + " ");
    }
}
JavaScript
//Driver Code Starts
class Heap {
    constructor(compare) {
        this.data = [];
        this.compare = compare;
    }

    push(val) {
        this.data.push(val);
        this._heapifyUp();
    }

    pop() {
        if (this.data.length === 0) return null;
        if (this.data.length === 1) return this.data.pop();

        const top = this.data[0];
        this.data[0] = this.data.pop();
        this._heapifyDown();
        return top;
    }

    peek() {
        return this.data[0] || null;
    }

    size() {
        return this.data.length;
    }

    _heapifyUp() {
        let index = this.data.length - 1;
        while (index > 0) {
            let parentIndex = Math.floor((index - 1) / 2);
            if (this.compare(this.data[parentIndex], this.data[index])) break;
            
            [this.data[parentIndex], this.data[index]] = [this.data[index], this.data[parentIndex]];
            index = parentIndex;
        }
    }

    _heapifyDown() {
        let index = 0;
        const length = this.data.length;

        while (true) {
            let leftChildIdx = 2 * index + 1;
            let rightChildIdx = 2 * index + 2;
            let swapIdx = index;

            if (leftChildIdx < length && !this.compare(this.data[swapIdx], this.data[leftChildIdx])) {
                swapIdx = leftChildIdx;
            }
            if (rightChildIdx < length && !this.compare(this.data[swapIdx], this.data[rightChildIdx])) {
                swapIdx = rightChildIdx;
            }
            if (swapIdx === index) break;

            [this.data[index], this.data[swapIdx]] = [this.data[swapIdx], this.data[index]];
            index = swapIdx;
        }
    }
}

// MaxHeap (Stores smaller half of numbers)
class MaxHeap extends Heap {
    constructor() {
        super((a, b) => a > b); 
    }
}

// MinHeap (Stores greater half of numbers)
class MinHeap extends Heap {
    constructor() {
        super((a, b) => a < b); 
    }
}

// Function to find the median of a stream of data
function getMedian(arr) {
//Driver Code Ends
    
    // Max heap for left side
    let leftMaxHeap = new MaxHeap();
    // Min heap for right side
    let rightMinHeap = new MinHeap(); 
    
    let res = [];

    for (let num of arr) {
        
        // Insert into max heap
        leftMaxHeap.push(num);

        // Balance heaps by moving element to min heap
        rightMinHeap.push(leftMaxHeap.pop());

        // Ensure left heap has more or equal elements
        if (rightMinHeap.size() > leftMaxHeap.size()) {
            leftMaxHeap.push(rightMinHeap.pop());
        }

        // Compute median based on heap sizes
        let median;
        if (leftMaxHeap.size() !== rightMinHeap.size())
            median = leftMaxHeap.peek();
        else
            median = (leftMaxHeap.peek() + rightMinHeap.peek()) / 2.0;
        
        res.push(median);
    }

    return res;
}

// Driver Code
let arr = [5, 15, 1, 3, 2, 8];
let res = getMedian(arr);

console.log(res.map(median => median.toFixed(2)).join(" "));

Output
5.00 10.00 5.00 4.00 3.00 4.00 

Time Complexity: O(n * log n), All the operations within the loop (push, pop) take O(log n) time in the worst case for a heap of size n.
Auxiliary Space: O(n)


Explore