算法导论-选择数组中第K小的数(选择问题)

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);
  }
 }
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值