算法第二章上机实践报告
一、实践题目名称
找第k小的数
二、问题描述
在n(1<=n<=1000)个无序整数中寻找第k小的数,平均时间复杂度需为O(n)
输入格式:
输入有两行:
第一行是n和k,0<k<=n<=10000
第二行是n个整数
输出格式:
输出第k小的数
输入样例:
10 4
2 8 9 0 1 3 6 7 8 2
输出样例:
2
三、算法描述
1、算法思路:
Partition函数:
选择第一个作为标准数(中轴),将数组中比x小的元素放在x左边,比x大的放在右边,最终稿返回中轴元素的位置。
Find函数:
通过调用partition函数获得划分点,判断划分点是否第k小(因为首元素下标为0,注意是k-1来判断),若是,输出该划分点;若不是则递归查找,直到找出第k小的数。
2、具体代码:
#include <iostream> using namespace std; int partition(int a[], int left, int right) {//将数组a的第left到right个元素进行划分 if(left==right) return left; int i=left,j=right+1; int x=a[left];//标准数 while(1) { while(a[++i]<x && i<right);//左侧 while(a[--j]>x);//右侧 if(i>=j) break; swap(a[i],a[j]); } a[left]=a[j]; a[j]=x; return j;// } int find(int a[], int left, int right, int k) {//在数组a的第left到right中寻找第k小的数 int mid = partition(a, left, right); if (k - 1 == mid) cout << a[mid]; else if (k - 1 < mid)//判断下一次划分在哪一区间进行 find(a, left, mid - 1, k); else if (k - 1 > mid) find(a, mid + 1, right, k);
return 0; } int main() { int n, k; cin >> n >> k; int a[1000]; for (int i = 0; i < n; i++) cin >> a[i]; find(a, 0, n - 1, k); return 0; }
四、算法时间及空间复杂度分析
1、时间复杂度
在partition函数中对整个数组进行了遍历,而find函数运用了二分思想,所以T(n) = O(n) + T(n/2) = O(n)
2、空间复杂度:
在find函数中使用到了递归调用,需要开辟辅助空间,递归过程空间复杂度为O(logn),所以总的S(n) = O(logn)
五、心得体会
1、本次的实践让我对分治法更加熟悉的运用
2、在寻找第k小数的过程中一直没注意初始下标为0的问题,导致一直在寻找第k+1个数
3、许多方法的思想都在上学期学习过,需要另外复习上学期数据结构的内容