中位数
public class median {
private boolean bOdd;//是否奇偶数
private int kv;//k值
private double medium;
int partition(double a[], int low, int high) {
double tmp = a[low];
int i = low, j = high;
while (i < j) {
while (i < j && a[j] >= tmp){
j--;
}
while (i < j && a[i] <= tmp){
i++;
}
swap(a, i, j);
}
a[low] = a[i];
a[i] = tmp;
return i;
}
void swap(double a[], int i, int j) {
if(i == j){
return;
}
double tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
void findMedium(double a[]){
bOdd = a.length % 2 == 0;
kv = a.length / 2 + 1;
medium = 0;
findK(a, 0, a.length - 1, kv, -1);
}
/**
* 需求第K小
* @param a
* @param low
* @param high
* @param k
* @param prePart 上回分裂中将该中位数分到右边的分裂点
*/
void findK(double a[], int low, int high, int k, int prePart){
if(low > high){
return;
}
int pos = partition(a, low, high);
int left = pos - low + 1;//左边个数
if(k > left){//中位数在分裂点右边,将该分裂点作为下次迭代的prePart
findK(a, pos + 1, high, k - left, pos);
}
else if(k < left){//中位数在分裂点左边,本次的prePart作为下次迭代的prePart
findK(a, low, pos - 1, k, prePart);
}
else{
if(bOdd){//偶数时的中位数处理,取两个中位数的均值
double v1 = a[pos];
double v2 = 0;
if(low >= pos){
v2 = a[prePart]; //左边无值时取prePart
}else{
v2 = findMax(a, low, pos - 1);//左边有值时取左边最大值
}
medium = (v1 + v2) / 2;
System.out.println(medium);
}else{
medium = a[pos];
System.out.println(medium);
}
}
}
double findMax(double a[], int low, int high){
double max = a[low];
for(int i = low + 1; i <= high; i ++){
if(a[i] > max){
max = a[i];
}
}
return max;
}
double getMedium(){
return medium;
}
public static void main(String[] args) {
median m = new median();
double a[] = {6,1,2,3,7,8,5,4,9};
m.findMedium(a);
m.findK(a,0,a.length - 1, 9, -1);
}
}
// 求前K个数
public class medianK {
private int kv;//k值
private double medium;
int partition(double a[], int low, int high) {
double tmp = a[low];
int i = low, j = high;
while (i < j) {
while (i < j && a[j] >= tmp){
j--;
}
while (i < j && a[i] <= tmp){
i++;
}
swap(a, i, j);
}
a[low] = a[i];
a[i] = tmp;
return i;
}
void swap(double a[], int i, int j) {
if(i == j){
return;
}
double tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
/**
* 需求第K小
* @param a
* @param low
* @param high
* @param k
* @param prePart 上回分裂中将该中位数分到右边的分裂点
*/
void findK(double a[], int low, int high, int k, int prePart){
if(low > high){
return;
}
int pos = partition(a, low, high);
int left = pos - low + 1;//左边个数
if(k > left){//中位数在分裂点右边,将该分裂点作为下次迭代的prePart
findK(a, pos + 1, high, k - left, pos);
}
else if(k < left){//中位数在分裂点左边,本次的prePart作为下次迭代的prePart
findK(a, low, pos - 1, k, prePart);
}else {
for (int i=0;i<k;i++){
System.out.println(a[i]);
}
}
}
double findMax(double a[], int low, int high){
double max = a[low];
for(int i = low + 1; i <= high; i ++){
if(a[i] > max){
max = a[i];
}
}
return max;
}
double getMedium(){
return medium;
}
public static void main(String[] args) {
medianK m = new medianK();
double a[] = {6,1,2,3,7,8,5,4,9};
// m.findMedium(a);
m.findK(a,0,a.length - 1, 5, -1);
}
}