实践题目名称:找第k小的数

问题描述:

设计一个平均时间为O(n)的算法,在n(1<=n<=1000)个无序的整数中找出第k小的数。

提示:函数int partition(int a[],int left,int right)的功能是根据a[left]~a[right]中的某个元素x(如a[left])对a[left]~a[right]进行划分,划分后的x所在位置的左段全小于等于x,右段全大于等于x,同时利用x所在的位置还可以计算出x是这批数据按升非降序排列的第几个数。因此可以编制int find(int a[],int left,int right,int k)函数,通过调用partition函数获得划分点,判断划分点是否第k小,若不是,递归调用find函数继续在左段或右段查找。

输入格式:

输入有两行:

第一行是n和k,0<k<=n<=10000

第二行是n个整数

输出格式:

输出第k小的数

输入样例:

在这里给出一组输入。例如:

10 4

2 8 9 0 1 3 6 7 8 2

输出样例:

在这里给出相应的输出。例如:

2

算法描述:

   题设提示使用快速排序,在总共有x个数的时候,每层递归时所选取的参照数在该层递归排序完后,其必定位于次数列第y个空间,前面y-1个数都比它小,后面x-y个数都大于它,即为它即是该数列中第y小的数。因此只需在快速排序的过程中找到在排序后位于第k个空间的参照数,这个数即为我们所要求的第k小的数。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int partition(int a[],int left,int right){
 5     int l=left,r=right+1;
 6     int x=a[left],s;
 7     while(l<r){
 8         while(a[++l]<x&&l<r);
 9         while(a[--r]>x);
10         if(l>=r)break;
11         swap(a[l],a[r]);
12     }
13     a[left]=a[r];
14     a[r]=x;
15     return r;
16 }
17 
18 int find(int a[],int left,int right,int k){
19     if(left<=right){
20         int m=partition(a,left,right);
21         if(m==k)return a[m];
22         if(m>k){
23             find(a,left,m-1,k);
24         }
25         else find(a,m+1,right,k);
26     }
27 }
28 
29 int main(){
30     int n,k,a[10002];
31     cin >> n >> k;
32     for(int i=1;i<=n;i++){
33         cin >> a[i];
34     }
35     int result = find(a,1,n,k);
36     cout << result;
37     return 0;
38 }

算法时间及空间复杂度分析(要有分析过程):

最优时间复杂度为T(1),即为当k=(int)n/2的情况,最差时间复杂度为T(nlogn),即为在快速排序完全完成时才找到的情况。

心得体会(对本次实践收获及疑惑进行总结)

    这道题主要看对快速排序算法的熟悉程度,思考的重点是区分递归中的层次和找到判定第k小的数的插入位置,对理解递归和快速排序比较有帮助。