算法第二章上机实践报告

一、实践题目名称:

找第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

三、算法描述

  这道题其实就是利用快速排序的思想,利用分治法,首先将这个问题进行分解,再递归求解,又因为是寻找第k小的数,所以不用进行合并。根据提示其实不需要完全排好序,而是边排边找。首先在find里面调用partition将a[left:right]进行划分,并返回基准元素x的位置。再将x跟k比较,如果x比k小,说明第k小的数在右边,就继续递归调用find在右边进行查找;反之,说明第k小的数在左边,就调用find在左边进行查找。

四、算法时间及空间复杂度分析

  算法时间其实跟快速排序是差不多的,在最好情况下 T(n) = 2T(n/2) + O(n) = O(nlogn),在最坏情况下 T(n) = T(n-1) + O(n) = O(n^2)。空间复杂度是O(n)。

五、代码:

 1 #include<iostream>
 2 
 3 using namespace std;
 4 
 5 int partition(int a[], int left, int right)
 6 {
 7     int x = a[left];
 8     int i = left + 1, j = right;
 9     while(true)
10     {
11         while(a[i]<x && i<j)
12             i++;
13         while(a[j]>x)
14             j--;
15         if(i >= j)
16             break;
17         int t = a[i];
18         a[i] = a[j];
19         a[j] = t;
20     }
21     a[left] = a[j];
22     a[j] = x;
23     return j;
24 }
25 
26 int find(int a[], int left, int right, int k)
27 {
28     int x = partition(a, left, right);
29     if(x == k-1)
30         return a[x];
31     else if(x < k-1)
32         return find(a, x+1, right, k);
33     else
34         return find(a, left, x-1, k);
35 }
36 
37 int main()
38 {
39     int n, k, a[10001];
40     
41     cin >> n >> k;
42     for(int i=0; i<n ;i++) 
43     {
44         cin >> a[i];
45     } 
46     
47     cout << find(a, 0, n-1, k);
48     
49     return 0;
50 } 

六、心得体会

  这道题就是利用快速排序的算法,一开始就错在了x和k的比较上,因为数组是从0开始,所以要跟k-1比较。

posted on 2020-10-03 22:43  minsiL  阅读(160)  评论(0编辑  收藏  举报