import java.util.Random;
/**
* 在一个数组中,选择第K小元素的值
* @author qihouliang
*
*/
public class SelectProblem {
//第一种方法是,利用选择最小值、最大值的思想,依次选择最小值,第二小...直到第K小。
//这种方法的时间复杂度为O(kN),当k比较小时,这种方法的时间复杂度较好。
public static int kNselect(int arr[],int k){
int j=0;
int q=0;
int minKValue=0;
while(j<k){ //从最小的元素开始找,依次找出K个最小元素
int i=q;
int minValue=arr[i];
int minIndex=i;
while(i<arr.length){
if(minValue>arr[i]){
minIndex=i;
minValue=arr[i];
}
i++;
}
//交换minIndex与此时最左边的元素交换
int temp=arr[q];
arr[q]=arr[minIndex];
arr[minIndex]=temp;
q++;
j++;
minKValue=minValue;
}
return minKValue;
}
//第二种方法是利用快速排序的思想
public static int partitionSelect(int arr[], int left,int right,int k){
int flag=partition(arr,left,right);//首先选定分区标志位
if(left==right){//如果left==right,则直接返回
return arr[left];
}
int rank=flag-left+1;//否则,计算当前标志位是第几小元素。这里是第rank小元素
if(rank==k){
return arr[flag];//如果rank==k,则找到第k小元素,则返回;
//注意返回时候,应该返回数组下标为flag,我们都是判断当前flag是第几小元素,如果判断正确,则返回。
}else if(rank<k)
return partitionSelect(arr, flag+1,right,k-rank);//这意味着在rank<k,即flag左边没有第K小,所以在flag右侧找,但此时找的是k-rank小的
else
return partitionSelect(arr, left,flag-1,k);//这意味着rank>k,即在flag左侧就有第K小元素,接着找。
}
public static void main(String args[]){
Random random=new Random();
int arr[]=new int[10];
for(int i=0;i<arr.length;i++){
arr[i]=random.nextInt(100);
}
// int minNkValue=kNselect(arr, 3);
// System.out.println("the nkmin value is:"+minNkValue);
int minPValue=partitionSelect(arr, 0, arr.length-1,5);//找第5小元素
System.out.println("the pmin value is:"+minPValue);
/*************这段代码是为了验证正确性的********************/
quickSort(arr,0,arr.length-1);
for(int i=0 ;i<arr.length;i++){
System.out.print(arr[i]+"\t");
}
System.out.println();
/*************这段代码是为了验证正确性的********************/
}
//返回切分的下标
public static int partition (int a[],int left,int right){
int flag=a[left];//以最左边即a[left]为标记数,这个可以随便选取
while(left<right){
while(left<right&&a[right]>=flag)
right--;//右边比flag元素大的元素不动,把比flag小的元素移动到左边
a[left]=a[right];//这里说明 右边的元素比flag小,所以把这个元素移动到左边,此时右边的right这个位置空出
while(left<right&&a[left]<flag)
left++;
a[right]=a[left];//此时刚好把上面空出的right位置填补
}
a[left]=flag;//到最后还空出一个left位置,这里刚好用flag填补。
return left;
}
public static void quickSort(int a [],int left,int right){
int flag=0;
if(left<right){
flag=partition(a, left, right);
quickSort(a, left, flag-1);
quickSort(a, flag+1, right);
}
}
}