用最大堆和最小堆实现中位数查找

具体思路:

用一个最大堆存放比中位数小(或等于)的元素,用一个最小堆存放比中位数大(或等于)的元素。这里关键的方法是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());
    	}
    }
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值