Find Median from Running Data Stream
Last Updated :
15 Oct, 2025
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(" "));
Output5.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(" "));
Output5.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
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem
My Profile