具体思路:
用一个最大堆存放比中位数小(或等于)的元素,用一个最小堆存放比中位数大(或等于)的元素。这里关键的方法是insert(),每当要插入一个元素时,根据判断条件将它插入最大堆或是最小堆,并更新最大堆和最小堆,使得最大堆和最小堆中元素的个数之差不超过1,这样中位数就是最大堆或最小堆的堆顶元素。当最大堆和最小堆中元素个数不同(个数相差为1)时,元素个数多的那个堆的堆顶元素即为中位数;如果两者元素个数相同,那么中位数可以是最大堆和最小堆的堆顶元素的值取平均。下面的程序代码中,当两者元素个数相同时,将最大堆的堆顶元素看做中位数。
插入(insert) (1)如果最大堆为空,将元素插入最大堆;(2)如果最小堆为空,将元素插入最小堆;(3)如果元素比最大堆的堆顶元素小且最大堆中元素个数不大于最小堆中元素个数,将元素插入最大堆;如果如果元素比最大堆的堆顶元素小但最大堆中元素个数大于最小堆中元素个数,那么先把最大堆的堆顶元素插入最小堆,然后删除最大堆的堆顶元素,最后把元素插入最大堆;(4)如果元素比最小堆的堆顶元素大且最小堆中元素个数不大于最大堆中元素个数,将元素插入最小堆;如果如果元素比最小堆的堆顶元素大但最小堆中元素个数大于最大堆中元素个数,那么先把最小堆的堆顶元素插入最大堆,然后删除最小堆的堆顶元素,最后把元素插入最小堆;(5)如果最大堆中元素个数小于最小堆中元素个数,将元素插入最大堆;否则将元素插入最大堆。
package com.ldl.algorithms.Exercise;
import com.ldl.algorithms.StdIn;
import com.ldl.algorithms.StdOut;
public class Midian<Key> {
private MaxPQ max; //store items less than midian
private MinPQ min; //store items larger than midian
/**
* Initialize max and min
*/
public Midian(){
max = new MaxPQ();
min = new MinPQ();
}
/**
* Is both max and min are empty?
*/
public boolean isEmpty(){
return max.isEmpty() && min.isEmpty();
}
/**
* Add a new key to either max or min.
*/
public void insert(Key k){
if(max.isEmpty()) {
max.insert(k);
return;
}
if(min.isEmpty()){
min.insert(k);
return;
}
if(less(k, (Key)max.max())) {
if(max.size() <= min.size()) max.insert(k);
else {
min.insert(max.delMax());
max.insert(k);
}
}
else if(less((Key)min.min(), k)){
if(min.size() <= max.size()) min.insert(k);
else{
max.insert(min.delMin());
min.insert(k);
}
}
else{
if(max.size() < min.size()) max.insert(k);
else min.insert(k);
}
}
/**
* Return the midian key on max or min.
* Throw an exception if both max and min empty.
*/
public Key midian(){
if (isEmpty()) throw new RuntimeException("Both max and min are underflow");
if(max.size() < min.size()) return (Key)min.min();
return (Key)max.max();
}
private boolean less(Key k1, Key k2){
return ((Comparable)k1).compareTo(k2) < 0;
}
/**
* A test client.
*/
public static void main(String[] args){
Midian midian = new Midian();
while(!StdIn.isEmpty()){
String item = StdIn.readString();
if(!item.equals("-")) midian.insert(item);
else if(!midian.isEmpty()) StdOut.print(midian.midian());
}
}
}