算法第二章上机实验报告

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

2. 问题描述
设计一个平均时间为O(n)的算法,在n(1<=n<=1000)个无序的整数中找出第k小的数。 
输入有两行:第一行是n和k,0<k<=n<=10000,第二行是n个整数
输出结果为第k小的数
输入样例:
在这里给出一组输入。例如:
10 4
2 8 9 0 1 3 6 7 8 2输出样例:
在这里给出相应的输出。例如:
2

3. 算法描述
int partition(int a[], int left, int right)
{//将数组a的第left到right个元素进行划分
int x = a[left];
while (left < right) 
{//采用快排策略
while (left < right && a[right] >= x)
right--;
a[left] = a[right];

while (left < right && a[left] <= x)
left++;
a[right] = a[left];
}
a[left] = x;
return left;
}
函数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 l,int r,int k){
if(l ==r) return a[l];
int i = partition(a,l,r);
int j = i-l+1;//数组l到i的元素个数
if(k<=j) return find(a,l,i,k);
else return find(a,i+1,r,k-j);
}
int find(int a[],int left,int right,int k)函数,通过调用partition函数获得划分点,判断划分点是否第k小,若不是,递归调用find函数继续在左段或右段查找。
即如果k<=j,则第k小的数在前半部分a[l,i]中;如果k>j,则要找的第k小元素在子数组a[i+1,r]中,由于此时子数列a[l,i]中的元素均小于要找的第k小元素,因此要找的第k小元素是子数列a[i+1,r]的第k-j小元素。

4. 算法时间及空间复杂度分析(要有分析过程)
由于随机划分函数partition()随机产生l和r之间的一个随机整数,因此partition()函数产生的划分基准是随机的,在这个条件下,算法find()可以在O(n)平均时间内找出n个输入元素中的第k小元素
由于没有利用到额外的辅助数组空间,因此空间复杂度为O(0).

5. 心得体会(对本次实践收获及疑惑进行总结)
本次实践通过利用快速排列和分治法,进一步加深了其对分治法的理解,能够简单快速的解决问题。
对于一些小细节,如下标的取值以及条件的大于小于以及等于应该考虑清楚。

posted @ 2020-10-03 16:30  唐嘉欣  阅读(137)  评论(0编辑  收藏  举报