第二章上机实践报告

问题描述:

设计一个平均时间为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

 

算法描述:

利用数组的第一个元素将数组划分为两部分,前面都比第一个元素小,后面都比第一个元素大,与快速排序划分完全相同

 

解决方法:

①利用函数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函数继续在左段或右段查找。

 

//完整代码如下

int partition(int a[], int left, int right, int k){

 

 int x = a[left];

 

 int i = left+1, j = right;

 

 while(i < j){

 

  while(a[i] < x && i < right)

 

   i++;//往左移

 

  while(a[j] > x )

 

   j--;//往右移

 

  if(i >= j) break; //交叉的情况 ,则退出循环

 

    swap(a[i], a[j]);//没有交叉,交换元素

 

}

 

 

//在下标从leftright的数组元素中输出第K小的数

 

int find(int num[], int left, int right, int k) {

 

    int p = partition(num, left, right); //返回划分元素的下标

 

    int n = p - left + 1; // 划分元素为第n

 

    int t;

 

    if ( n == k)

 

        t = num[p];

 

    else if (n < k) //找右半部分的第k-n

 

        t = find(num, p + 1, right, k - n);

 

    else //找左半部分的第k

 

        t = find(num, left, p - 1, k);

 

 

 

    return t;

 

}

 

 

int main() {

 

    int n, k;

 

    cin >> n >> k;

 

    int num[n];

 

    for (int i = 0; i < n; i++)

 

        cin >> num[i];

 

    cout << find(num, 0, n - 1, k) << endl;

 

    return 0;

 

}

 

心得体会:

最开始听老师讲快速排序的时候觉得掌握得不错,一上机打代码就开始出各种bug,后来成功debugpta提交成功,但是代码的规范却没有做好,函数的功能分得不够明确,后续还有待提高。

posted @ 2020-10-06 01:27  L_XIAOTIAN  阅读(92)  评论(0编辑  收藏  举报