patternjavaMinor
Generic Median Heap using PriorityQueues
Viewed 0 times
priorityqueuesgenericheapusingmedian
Problem
I've implemented a generic data structure to keep track of the median in a streaming list of numbers. I was hoping to gather the community's feedback on code style and taste.
```
package ad.collections;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import java.util.*;
/**
* Created by adhulipa on 10/28/16.
*/
public class MedianHeap implements Queue {
private enum QueueSize { BIGGER, SMALLER };
private PriorityQueue lowers;
private PriorityQueue uppers;
public MedianHeap() {
super();
lowers = new PriorityQueue(Collections.reverseOrder());
uppers = new PriorityQueue();
}
@Override
public boolean offer(Number number) {
boolean offered;
if ( !lowers.isEmpty() && isLessThan(number, lowers.peek())) {
// Cast number to actual type E
offered = lowers.offer( (E) number);
} else if ( !uppers.isEmpty() && isGreaterThan(number, uppers.peek())) {
offered = uppers.offer( (E) number);
} else {
// Otherwise, add new number to smaller of the two queues
Queue smallerQueue = selectQueue(QueueSize.SMALLER);
offered = smallerQueue.offer(number);
}
rebalance();
return offered;
}
@Override
public Double peek() {
return this.median(false);
}
@Override
public int size() {
return lowers.size() + uppers.size();
}
@Override
public boolean isEmpty() {
return lowers.isEmpty() && uppers.isEmpty();
}
@Override
public Double poll() {
Double median = this.median(true);
rebalance();
return median;
}
private void rebalance() {
while ( Math.abs(lowers.size() - uppers.size()) > 1 ) {
Queue bigger = selectQueue(QueueSize.BIGGER);
Queue smaller = selectQueue(QueueSize.SMALLER);
smaller.offer(bigger.poll());
}
}
private Doubl
```
package ad.collections;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import java.util.*;
/**
* Created by adhulipa on 10/28/16.
*/
public class MedianHeap implements Queue {
private enum QueueSize { BIGGER, SMALLER };
private PriorityQueue lowers;
private PriorityQueue uppers;
public MedianHeap() {
super();
lowers = new PriorityQueue(Collections.reverseOrder());
uppers = new PriorityQueue();
}
@Override
public boolean offer(Number number) {
boolean offered;
if ( !lowers.isEmpty() && isLessThan(number, lowers.peek())) {
// Cast number to actual type E
offered = lowers.offer( (E) number);
} else if ( !uppers.isEmpty() && isGreaterThan(number, uppers.peek())) {
offered = uppers.offer( (E) number);
} else {
// Otherwise, add new number to smaller of the two queues
Queue smallerQueue = selectQueue(QueueSize.SMALLER);
offered = smallerQueue.offer(number);
}
rebalance();
return offered;
}
@Override
public Double peek() {
return this.median(false);
}
@Override
public int size() {
return lowers.size() + uppers.size();
}
@Override
public boolean isEmpty() {
return lowers.isEmpty() && uppers.isEmpty();
}
@Override
public Double poll() {
Double median = this.median(true);
rebalance();
return median;
}
private void rebalance() {
while ( Math.abs(lowers.size() - uppers.size()) > 1 ) {
Queue bigger = selectQueue(QueueSize.BIGGER);
Queue smaller = selectQueue(QueueSize.SMALLER);
smaller.offer(bigger.poll());
}
}
private Doubl
Solution
A few of my personal pet hates:
- You should avoid boxed
Doubles as much as possible. If you are looking for a double that you can set tonull, you should consider using theOptionalDoubleinstead.
- You are violating the contract of the
Queueinterface. Notably thepollmethod, which is really only supposed to remove one number from the queue (yours can remove two in some circumstances), and can return an item that was never put in the queue in the first place.
- The number of
NotImplementedExceptionsyou are throwing around tells me that theQueueinterface is not the right one to implement for this purpose. (Frankly, that type of exception should not exist, as it only encourages bad practice.)
Context
StackExchange Code Review Q#145578, answer score: 2
Revisions (0)
No revisions yet.