Median of a Stream (original) (raw)

Last Updated : 11 May, 2026

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.

**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

Try It Yourselfredirect icon

Table of Content

[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:

**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 #include #include using namespace std;

vector getMedian(vector &arr) { vector 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 arr = {5, 15, 1, 3, 2, 8}; vector 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

**Step 2: Balance the heaps

**Step 3: Find the median

#include #include #include using namespace std;

vector getMedian(vector &arr) {

// Max heap to store the smaller half of numbers
priority_queue<int> s;

// Min heap to store the greater half of numbers
priority_queue<int, vector<int>, greater<int>> g;

vector<double> res;

for (int i = 0; i < arr.size(); i++)
{

    // Insert new element into max heap
    s.push(arr[i]);

    // Move the top of max heap to min heap to maintain order
    int temp = s.top();
    s.pop();
    g.push(temp);

    // Balance heaps if min heap has more elements
    if (g.size() > s.size())
    {
        temp = g.top();
        g.pop();
        s.push(temp);
    }

    // Compute median based on heap sizes
    double median;

    if (s.size() != g.size())
        median = s.top();
    else
        median = (double)(s.top() + g.top()) / 2;

    res.push_back(median);
}

return res;

}

int main() { vector arr = {5, 15, 1, 3, 2, 8}; vector 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 getMedian(int[] arr) {

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

# Min heap to store the greater half of numbers
g = []

res = []

for num in arr:
    # Insert new element into 
    #max heap 
    heapq.heappush(s, -num)
    
    # Move the top of max heap to min heap to maintain order
    temp = -heapq.heappop(s)
    heapq.heappush(g, temp)
  
    # Balance heaps if min heap has more elements
    if len(g) > len(s):
        temp = heapq.heappop(g)
        heapq.heappush(s, -temp)
    
    # Compute median based on heap sizes
    if len(s) != len(g):
        median = -s[0]
    else:
        median = (-s[0] + g[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> s = new SortedDictionary
        <int, int>(Comparer<int>.Create((a, b) => b.CompareTo(a)));
    int leftSize = 0;

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

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

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

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

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

        //Compute median based on heap sizes
        double median;
        if (leftSize != rightSize)
            median = getMax(s);
        else
            median = (getMax(s) + getMin(g)) / 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 { //Driver Code Ends

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) {

// Max heap for left side
let s = new MaxHeap();
// Min heap for right side
let g = new MinHeap();

let res = [];

for (let num of arr) {

    // Insert into max heap
    s.push(num);

    // Balance heaps by moving element to min heap
    g.push(s.pop());

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

    // Compute median based on heap sizes
    let median;
    if (s.size() !== g.size())
        median = s.peek();
    else
        median = (s.peek() + g.peek()) / 2.0;

    res.push(median);
}

//Driver Code Starts 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(" ")); //Driver Code Ends

`

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)