Skip to content

Instantly share code, notes, and snippets.

@jeryini
Forked from Vedrana/MedianOfIntegerStream.java
Last active September 23, 2016 03:08
Show Gist options
  • Select an option

  • Save jeryini/a26276d2289878bd7744 to your computer and use it in GitHub Desktop.

Select an option

Save jeryini/a26276d2289878bd7744 to your computer and use it in GitHub Desktop.
package com.jernejerin.traffic.helper;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
// Given a stream of unsorted integers, find the median element in sorted order at any given time.
// http://www.ardendertat.com/2011/11/03/programming-interview-questions-13-median-of-integer-stream/
public class MedianOfIntegerStream {
public Queue<Integer> minHeap;
public Queue<Integer> maxHeap;
public int numOfElements;
public MedianOfIntegerStream() {
minHeap = new PriorityQueue<Integer>();
maxHeap = new PriorityQueue<Integer>(10, new MaxHeapComparator());
numOfElements = 0;
}
public void addNumberToStream(Integer num) {
maxHeap.add(num);
if (numOfElements%2 == 0) {
if (minHeap.isEmpty()) {
numOfElements++;
return;
}
else if (maxHeap.peek() > minHeap.peek()) {
Integer maxHeapRoot = maxHeap.poll();
Integer minHeapRoot = minHeap.poll();
maxHeap.add(minHeapRoot);
minHeap.add(maxHeapRoot);
}
} else {
minHeap.add(maxHeap.poll());
}
numOfElements++;
}
public Double getMedian() {
if (numOfElements%2 != 0)
return new Double(maxHeap.peek());
else
return (maxHeap.peek() + minHeap.peek()) / 2.0;
}
public void removeNumberFromStream(Integer num) {
// if it is greater then maximum on left, then
// the number must be on right side (minimum heap)
if (num > maxHeap.peek()) {
if (minHeap.remove(num)) {
numOfElements--;
// if the number of elements is not odd
// after delete, then we need to move
// element from max heap to min
if (numOfElements % 2 == 0) {
minHeap.add(maxHeap.poll());
}
}
}
else {
if (maxHeap.remove(num)) {
numOfElements--;
// if the number of elements is not even
// after delete, then we need to move
// element from min heap to max
if (numOfElements % 2 != 0) {
maxHeap.add(minHeap.poll());
}
}
}
}
private class MaxHeapComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
}
public static void main(String[] args) {
MedianOfIntegerStream streamMedian = new MedianOfIntegerStream();
streamMedian.addNumberToStream(1);
System.out.println(streamMedian.getMedian()); // should be 1
streamMedian.addNumberToStream(5);
streamMedian.addNumberToStream(10);
streamMedian.addNumberToStream(12);
streamMedian.addNumberToStream(2);
System.out.println(streamMedian.getMedian()); // should be 5
streamMedian.addNumberToStream(3);
streamMedian.addNumberToStream(8);
streamMedian.addNumberToStream(9);
System.out.println(streamMedian.getMedian()); // should be 6.5
streamMedian.removeNumberFromStream(9);
System.out.println(streamMedian.getMedian()); // should be 5
streamMedian.removeNumberFromStream(8);
streamMedian.removeNumberFromStream(3);
System.out.println(streamMedian.getMedian()); // should be 5
}
}
@Holden-Garfield
Copy link

Could you please briefly explain how your removal works?

@Holden-Garfield
Copy link

I have written this one, but i cannot complete those two lines; also I am not sure about the time complexity. Do you think it is O(logn) for removal?

        public void removal(int num){       
        if(num == maxHeap.peek()){
            maxHeap.remove();
            numberOfElements--;
            return;
        }       
        if(num == minHeap.peek()){
            minHeap.remove();
            numberOfElements--;
            return;
        }       
        if(numberOfElements % 2 == 0){
            int median = (maxHeap.peek() + minHeap.peek())/2;
            if(num < median){
                // should be removed from maxheap, but how????
                // ?????

                // before: maxHeap: N & minheap: N - Now: maxHeap: N-1 & minheap: N
                // So, one element from minheap should add to maxheap
                maxHeap.add(minHeap.remove());
                // Now: maxHeap: N & minheap: N-1, so it's fine
            }else{ 
                // should be removed from minheap, but how????
                // ?????

                // before: maxHeap: N+1 & minheap: N - Now: maxHeap: N+1 & minheap: N-1
                // So, one element from maxheap should add to minheap
                maxHeap.add(minHeap.remove());
                // Now: maxHeap: N & minheap: N, so we are fine
            }
        }else{
            int median = maxHeap.peek();
            if(num < median){
                // should be removed from max heap
            }else{ 
                // should be removed from min heap
            }
        }
        numberOfElements--;
    }

@Holden-Garfield
Copy link

Here discussed same question, but not 'delete', it is 'delete median', which is possible in O(logn). what do you think?
http://www.cs.cmu.edu/afs/cs/academic/class/15750-s11/www/hw/hw1-sol.pdf

@jeryini
Copy link
Author

jeryini commented Aug 20, 2015

The logic goes like that. First we need to check if the number that we want to remove is greater than the root element of the max heap. If it is, than we need to try to remove it from the min heap, otherwise we remove from max heap. Keep in mind that min and max heap are implemented as PriorityQueue, which means that removal of specified object is done in linear time. If the removal is successful we need to check for the number of elements in heap and fix it.

@jeryini
Copy link
Author

jeryini commented Aug 20, 2015

Also watch out what the paper you linked states. It says the following:

deleteMedian(D): Delete the median of D in time O(log n).

They only want to delete the median of structure D, where in my case the user can remove arbitrary number from stream. I see you are trying to implement the removal of only median element, as it is stated in the paper. Just follow the solution specified in the paper. Will take a look at your code later, as I am currently busy.

@Holden-Garfield
Copy link

Thanks for explanation 👍

@942u3895hjf
Copy link

Hi - is it possible to public this under an ASF 2.0 license?

@tezcane
Copy link

tezcane commented Sep 23, 2016

Here is a little cleaner and little more optimized version of addNumberToStream():

    public void addNumberToStream(Integer num) {
        if (numOfElements % 2 == 0) {
            maxHeap.add(num); //no more need for minHeap.isEmpty() check
        } else {
            minHeap.add(num); //no more need for maxHeap.poll()
            if (maxHeap.peek() > minHeap.peek()) {
                Integer maxHeapRoot = maxHeap.poll();  //only one variable is needed for swap
                maxHeap.add(minHeap.poll());
                minHeap.add(maxHeapRoot);
            }
        }
        numOfElements++; //only need one  numOfElements++
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment