算法第二章上机实践报告

Posted on 2020-10-03 22:32  Youthenen  阅读(180)  评论(0编辑  收藏  举报

要求:

实践报告任选一题进行分析。内容包括:

  1. 实践题目名称
  2. 问题描述
  3. 算法描述
  4. 算法时间及空间复杂度分析(要有分析过程)
  5. 心得体会(对本次实践收获及疑惑进行总结)

实践题目:2-1 找第k小的数 (25分)

问题描述:

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

算法描述

(快速排序)

函数int partition(int a[],int left,int right):用第一个数作为基准点,将比它小的数放在左侧,比它大的数放在右侧。i从左往右扫,j从右往左扫,在不交叉的情况下(i<j)若是有大数在左边,则与右边的小数交换位置,直到最后交叉,则交换基准点与a[j]的位置。最后返回划分点的位置j

函数find(int a[],int left,int right,int k):调用partition函数获得基准点,将返回的划分点j与k比较。(在此划分点的左边为小数,右边为大数,所以比较即可知道第k小的数的范围。)

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

时间复杂度

partition算法的时间复杂度O(n),最坏情况下,会将n个元素分为n-1与1的组合,此时T(n)=O(n^2);

最好情况下,每次都产生n/2的区域,则此时T(n)=O(nlogn)

空间复杂度

O(n),存放无序数的数组

心得体会

①一开始并没有想到是快速排序的思想,由于是要找第k小,而快速排序刚好满足这一特点,数本身可能无序,但是总有前面数小,后面数大的情况。这正好满足第k小的特点,若元素位置与k-1相等,则说明为要找的数。

②一开始没有考虑到数组下标从0开始,而最小k为1.

代码

#include <iostream>
using namespace std;
 
int partition(int a[],int left,int right)
{
	int x = a[left];
	int i = left+1;
	int j = right;
	int temp;
	while(i<j)
	{
		while(a[i] < x && i<j)   
          //若是一直比x小,则有越界的可能,所以要加i<j的判断 { i++; } while(a[j] > x) { j--; }
          //若是已经交叉了,则要break,停止交换,否则大数会跑到小数的位置 if(i>=j) break; temp = a[i]; a[i] = a[j]; a[j] = temp; }
    //基准点与a[j]的交换 a[left] = a[j]; a[j] = x; return j; } int find(int a[],int left,int right,int k) { int x = partition(a,left,right); if(x+1 == k) { return a[k-1]; } if(x+1 < k) { find(a,x+1,right,k); } else find(a,left,x-1,k); } int main() { int n,k; cin >> n >> k; int a[10002]; for(int i=0; i<n; i++) { cin >> a[i]; } cout << find(a,0,n-1,k); }

  

 

Copyright © 2024 Youthenen
Powered by .NET 8.0 on Kubernetes