欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

分治法找第K小的数PTA

程序员文章站 2022-05-12 10:58:02
...

分治法————找第K小的数

基本思路:用一个基准数a(本题选用数组的第一个元素作为基准数)将S分割为两部分,分别为小于等于a的S1和大于a的S2.记|S1|表示S1中元素的个数,|S2|表示S2中元素的个数。这样当|S1|>k时,那么第k小的数在S1中并且时S1中第k小的数;相反的,当|S1|<k时,那么第k小的数在S2中并且时S2中第k-S1小的数;而当S1=k时,那么这个第k小的数就是基准数本身。

#include <stdio.h>
 #define MAXN 10000
 
 void swap(int *x,int *y)
 {
  int temp;
  temp = *x;
  *x = *y;
  *y = temp;
 }
int partition(int a[],int left,int right)
{
 int e = a[left];
 int L=left,R=right;
 int temp=0;
 
 while(1){
  while(left<=right && e>=a[left]){/*从左向右遍历直到找到比基准数大的数停止*/ 
   left ++; 
  }
  while(left<right && e<a[right]){/*从右向左遍历直到找到比基准数小的数停止*/ 
   right --;
  }
  if(left < right){
   swap(&a[left],&a[right]);/*将左边比基准数大的数与右边比基准数小的数互换,使得左边全是比基准数小的数,右边全是比基准数大的数*/ 
     }
  else
   break;/*当left=right时,此时来到了边界,跳出循环*/ 
 }
 swap(&a[L],&a[left-1]);/*因为a[left-1]比基准数小所以应该将他换到基准数左边,二基准数时S1中最大数*/ 
 
 return left;/*此处的left等价于|S1|*/
 
}
int find(int a[],int left,int right,int k)
{
 int pos =partition(a,left,right);
 if(pos > k)/*当|S1|>k时则第k小的数在S1中*/
  find(a,left,pos-1,k);/*在S1中找第k小的数*/ 
 else if(pos < k)/*当|S1|<k时则第k小的数在S2中*/ 
  find(a,pos,right,k);/*在S2中找第k小的数*/ 
 else/*当|s1|=k时则基准数就是第k小的数*/ 
  return a[pos-1];
  
}
 int main(void){
  int n,k;
  scanf("%d %d",&n,&k);
  
  int a[MAXN];
  int i;
  for(i=0; i<n; i++)
   scanf("%d",&a[i]);
  
  int num;
  num = find(a,0,n-1,k);
  
  printf("%d",num);
  
   
  return 0;
 }