取中位数的算法

找出一个组元素中的中位数(中间值,它不大于一半的元素也不小于另一半的元素),是一个和排序有关但又不需要完全排序的重要应用。查找中位数在统计和许多数据处理中很常见。
可以把查找中位数看成是一种特殊的选择:在数组中查找第k个小或大的元素。我们可以回想前面《快速排序及改进》中的partition(Comparable[] a,int lo,int hi)方法,它会将数组的a[lo]到a[hi]重新排列(局部排序)并返回一个整数j,使得:

a[lo ... j - 1] <= a[j] <= a[j + 1 ... hi]

那么,要获取第K小的值,当k = j时,a[j]就是要求解的数值了。

/**
*查找一个数组中的第k小的元素
*/
public static Comparable select(Comparable[] a,int k){
//对数组a洗牌
shuffle(a);
int lo = 0;
int hi = a.length - 1;
int j = 0;
while(hi > lo){
j = partition(a,lo,hi - 1);
if(j == k){
return a[k];
}else if(j > k){
hi = j - 1;
}else{
lo = j + 1;
}
}
return a[k];
}

对于查找中位数,就是k = N/2时的a[j],a[j]就是要求的中位数。整个代码如下:

/**
* 取中位数
*/
public class MedianFinder extends SortBase{


/**
* 局部排序,查找数组a的中位数
* @param a
* @return
*/
public static Comparable find(Comparable[] a){
int len = a.length;
int mid = 0;
if((isOdd(len)){//奇数
mid = (len + 1)/2;
}else{
mid = len/2;
}
return select(a,mid - 1);
}

/**
* 判断整数i是否是奇数
* @param i
* @return true:奇数,false:偶数
*/
private static isOdd(int i){
return (k & 1) != 0;
}

/**
* 查找数组a中第k小的元素
* @param a
* @param k
* @return
*/
public static Comparable select(Comparable[] a,int k){
shuffle(a);
Comparable val = null;
int lo = 0;
int hi = a.length - 1;
int j = 0;
while(hi > lo){
j = partition(a,lo,hi);
if(j == k){
val = a[k];
break;
}else if(j > k){
hi = j - 1;
}else{
lo = j + 1;
}
}
return val;
}

/**
* 在数组a的下标lo和hi范围内获取快速切分的基数的小标,使该基数的左边的
* 元素都不大于该数,而右边的元素都不小于该数
* @param a
* @param lo
* @param hi
* @return 快速切分基数的下标
*/
public static int partition(Comparable[] a,int lo,int hi){
//将数组切分为a[lo...i - 1],a[i],a[j + 1,hi]
int i = lo,j = hi + 1; //设置左右扫描指针
Comparable v = a[lo]; //切分元素
while(true){
while(less(a[++i],v)){
if(i == hi) break;
}
while(less(v,a[--j])){
if(j == lo) break;
}
if(i >= j){
break;
}
exch(a,i,j);
}
exch(a,lo,j); //将v = a[i]放入正确的位置
//a[lo...j - 1] <= a[j] <= a[j + 1 ... hi]
return j;
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值