算法第二章上机实验报告
一、实践名称
maximum number in a unimodal array
一维数组中的最大数字
二、问题描述
存在一个由n个不同元素组成的一维数组,元素从小递增至最大数据后递减,即求出峰值数据,该算法的时间复杂度已被规定为O(log n)
三、算法描述
1)在主函数如题目所示定义出n用于存放输入数据的数量,和a[1000]用于存放数组数值,并依次输入
2)定义一个int 类型函数 bio(int a[],int left,int right,int n)用于进行二分查找,其中a存放输入数组,left为查找范围的最左侧下边,n-1为查找范围的最右边下标,n为main函数中用于存放输入数据的总数量
3)在bio函数中定义一个int类型的数据m,用于存放(left+right)/2也就是查找范围中间数据的下标
当left<=right时进行以下判断:
- 在bio函数中首先用if(m == 0)来判断该范围中数据是否只有一个,若只有一个则峰值为该数据,break,返回a[m]
- 再用if(a[m - 1] < a[m] && a[m + 1] < a[m])来判断m下标所指向的数据是否为峰值,若满足条件返回,break,a[m]
- 若以上条件接不满足,则进行以下判断,若a[m - 1] > a[m],说明峰值出现在了本次搜查范围的左边,则需要return bio(a,left,m-1,n)进行递归操作在left至m-1的范围内再次查找;若a[m +1] > a[m],说明峰值出现在了本次搜查范围的右边,则需要return bio(a,m+1,right,n)进行递归操作在m+1至right的范围内再次查找
4)在main函数中输出bio(a,0,n-1,n),并return 0结束运算
四、算法时间复杂度以及空间复杂度的分析(分析过程)
时间复杂度:
1)在bio函数中运用的查找方法为用递归调用实现二分搜索,则时间复杂度为O(log2n)
2)在if(m == 0)、if(a[m - 1] < a[m] && a[m + 1] < a[m])、a[m - 1] > a[m]、a[m +1] > a[m]这四个判断条件中,时间复杂度都为O(1)
综上所述时间复杂度为O(log2n)
空间复杂度:
在bio函数中,每次递归都会产生一个m进行储存(left+right)/2,则空间复杂度为O(log2n)
五、心得体会
- 第一次打出来的代码会出现运行超时的情况,后来发现了自己的低级错误,我只是对if(a[m - 1] < a[m] && a[m + 1] < a[m])这个条件进行了判断后break,但是忘记return了,所以出现了运行超时(真的很低级,下次需要注意)
- 在改正了1中的错误后,代码出现了部分错误的判断,我就意识到了出现边界溢出的情况,在这条代码中if(a[m - 1] < a[m] && a[m + 1] < a[m]),如果m=0的话则m-1会出现溢出不合法,所以我后来加上了if(m == 0)来判断该范围中数据是否只有一个后,代码就可以完全通过了!
六、分治法的个人体会和思考
- 分治法需要特别严谨的研究,例如left和right要不要改变,变成mid还是mid+1或者mid-1,一般用例题中简单的例子就可以推算出来,所以分治法的在打代码之前话较长一段时间进行分析我认为是非常有必要的。
- 通过这次实验的两道题和平时作业的题目我发现了,一般数组用二分查找还是较为简单的,但需要注意的是不同题目的数组输入排列顺序不同,所以有时候用纸画图后会更明确判断条件。
- 类似于切蛋糕问题和本次实验中找函数的解的问题,特别需要注意其精度和输出格式,如小数点后需保留几位的问题,这两个方面在日常打代码的过程中都栽过跟头,所以需要特别注意
- 在二分法的问题中,需要特别注意的就是边界问题,除了边界的数值之外,还需要特别注意一些例如应该是< 还是<=的问题,如果边界没有正确判断的话,递归容易进入一个死循环