找中位数
题目描述
请设计一个算法,不排序,快速计算出一个无序数列的中位数。 时间复杂度要求为O(n)。
如果有奇数个元素,中位数则是数组排序后最中间的那个数字。
如果是偶数个元素,中位数则是数组排序后最中间两个元素的平均值。
输入
有多组输入,每组输入的第一行为n(1<=n<=1e5),表示该数列的元素个数。
第二行为n个整数组成的无序数列
输出
每组样例输出一行,表示该无序数列的中位数。
若为偶数,请保留三位小数
若为奇数,直接输出
样例输入
5
5 3 2 1 4
样例输出
3
Code
类似于快排,但是不用排序,只要找出大小在中间的就可以了,以第一个为基元,比它小或者大就交换。
package Week8;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.Scanner;
public class QuestionF {
//将数组长度和数组定义为全局变量
static int n;
static int[] arr;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
n = sc.nextInt();
arr = new int[n];
//输入数据
for(int i=0;i<n;i++){
arr[i] = sc.nextInt();
}
System.out.println(select(0,n-1));
}
}
public static Serializable select(int begin, int end){
if(n==1){
return arr[0];
}
int i = begin;
//将后面的依次和第一位进行比较,比它小的就交换并交换起点
for(int j =i+1;j<=end;j++){
if(arr[j]<arr[begin]){
++i;
swap(arr,i,j);
}
}
//循环结束后改变起点的位置。
swap(arr,begin,i);
//判断第i位是否已经位数组中间位(跟快排的思想差不多)
if(i<n/2){
return select(i+1,end);
}else if(i>n/2){
return select(begin,i-1);
}else{
//否则判断奇数还是偶数
if(n%2==1){
return Integer.parseInt(String.valueOf(arr[i]));
}else {
int m=arr[0];
//将第一位与前i位数相比较,若比其大,则交换
for(int j=1;j<i;j++){
if(arr[j]>m){
m = arr[j];
}
}
DecimalFormat df = new DecimalFormat("#0.000");
//df.format()
return df.format((double) (arr[i]+m)/2);
}
}
}
//先写一个交换函数
public static void swap(int[] a, int i, int j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}