无序数组找中位数

如果数组长度是奇数,中位数是排序后的第(n+1)/2个元素;若是偶数,中位数是排序后第n/2个元素。

思路1:

1.1 将前(n+1)/2个元素调整为一个最小堆;
1.2 对后续每一个元素和堆顶比较,如果小于等于堆顶,丢弃之,去下一个元素。如果大于堆顶,用该元素取代堆顶,调整堆,去下一个元素重复1.2步
1.3 当遍历完所有元素之后,堆顶为中位数

思路2:

可以扩展为从无序数组中查找第k大的元素。

利用快速排序的partition函数,任意挑一个元素,以该元素key,划分数组为两部分,key左边元素小于等于key,右边元素大于等于key。在第一次partition后,如果左侧元素个数k - 1,则递归地在左侧序列中继续查找。代码如下:


public class Main {
	public static void swap(int[] a, int i, int j){
		int temp = a[i];
		a[i] =  a[j];
		a[j] = temp;
	}
	
	public static int partition(int[] arr, int low, int high){
		int pivot = arr[low];
		int i= low, j = high;
		while(i<=j){
			while(i<=j && arr[i]<=pivot)i++;
			while(i<=j && arr[j]>=pivot)j--;
			swap(arr,i,j);
		}
		swap(arr,low,j);
		return j;
	}
	//第k大的数,如果数组长度奇数,则k=(1+n)/2, 否则k=n/2
	public static int findMedian(int[] arr, int k, int low, int high){
		if(k >high -low +1) return -1;
		int pos = partition(arr,low, high);
		if(pos - low < k -1){
			return findMedian(arr, k-pos-1, pos+1, high);
		}else if(pos - low == k-1){
			return arr[pos];
		}else {
			return findMedian(arr, k, low, pos-1);
		}
	}
	
	
	public static void main(String[] args) {
		int[] arr= {3,5,2,3,5,9,1,2,11,12,13};
		int res = 0;
		if(arr.length%2 ==1){
			res = findMedian(arr, (arr.length+1)/2, 0, arr.length-1);
		}else{
			res = findMedian(arr, arr.length/2, 0, arr.length-1);
		}
		System.out.println(res);
	}

}


你可能感兴趣的:(数据结构与算法)