算法第二章上机实践报告
一.实践题目
题目来源:《计算机算法设计与分析》,王晓东
设a[0:n-1]是已排好序的数组,请改写二分搜索算法,使得当x不在数组中时,返回小于x的最大元素位置i和大于x的最小元素位置j。当搜索元素在数组中时,i和j相同,均为x在数组中的位置。
输入格式:
输入有两行:
第一行是n值和x值; 第二行是n个不相同的整数组成的非降序序列,每个整数之间以空格分隔。
输出格式:
输出小于x的最大元素的最大下标i和大于x的最小元素的最小下标j。当搜索元素在数组中时,i和j相同。 提示:若x小于全部数值,则输出:-1 0 若x大于全部数值,则输出:n-1的值 n的值
输入样例:
在这里给出一组输入。例如:
6 5
2 4 6 8 10 12
输出样例:
在这里给出相应的输出。例如:
1 2
二.问题描述
题目要求我们改写二分搜索方法,主要是对在数组中查询不到目标值时做一定的反馈,同时成功检索到目标值时也需做特殊反馈,分为四种情况,目标值大于数组全部值,目标值小于数组全部值,目标值在数组中,目标值不在数组中但目标值大小介于数组中元素大小。
三.算法描述
#include<iostream> #include<algorithm> using namespace std; //非递归实现的二分搜索 int bSearch(int a[],int x, int left, int right,int k){ int i=0; int j=0; while(left <= right){ int mid = (left + right) / 2; if(x == a[mid]) { i = j = mid; cout<< i <<" "<< j ; return mid; } else if(x > a[mid]) left = mid + 1 ; else right = mid - 1; } //当二分搜索在数组中查找不到x时 i = right ; j = left; if(k == 0) cout<< i <<" "<< j ; return -1; } int main(){ int n,x; cin >> n >> x; int *a = new int[n]; for(int i = 0;i < n ;i++){ cin >> a[i]; } //判断是否为降序序列 int *b = new int[n]; for(int i = 0;i < n ;i++){ b[i] = a[i]; } sort(b,b+n); int j = 0; for(int i = 0;i < n ; i++){ if(a[i] != b[i]) j++; } if(j) return 0; int left = 0,right = n; int k = 0; if(x < a[0]) { cout << "-1" << " "<<"0"; k++; } if(x > a[n-1]){ cout << n - 1 << " " << n; k++; } bSearch(a,x,left,right,k); return 0; }
因为题目要求输入的数组为非降序的,所有设置了另一个数组b,并将b用sort()方法排序后再与a数组比较,如果同样下标下两个数组元素仍相同,则说明a本来就是升序排列的。在进行二分搜索前先判断是否为目标值小于全部元素和大于全部元素的两种情况,之后便可进行二分搜索。二分搜索成功则直接输出目标值在数组中的下标。在搜索时会有折半的左右值,这便是最终的输出值,但应注意是左右值与我们习惯上的反向了,因为检索不到目标值是,最后一次检索,left跨越的right或是right跨越了right,即left大于right,因此先输出的i=right,j=left。
四.算法时间及空间复杂度分析
如果只讨论二分搜索算法函数的时间及空间复杂度,则函数中基本操作所执行的次数为n/2+log2n+n/2,关注最高级别的增长趋势,则二分搜索的时间复杂度为O(logn),在长度为n的数组中查找,第一次循环在n/2中查找,第二次在n/4中查找,第X次找到就是n/(2的X次方),解得x=log2n ,故该算法时间复杂度为log2N。该二分算法在循环迭代时只用了left,right,mid来存储变化的数组,没有申请其他辅助空间,所以需要的辅助空间是常数级别的,空间复杂读为O(1)。
五.心得体会
本次实践操作让我感到自身的实践能力还有待提升,简单的算法思路执行起来却耗费了很长时间,中间还更改过几次方案,效率十分低。有一些小细节小方法没有通过实践是很难注意到的,例如本次实验过程中就一直在思考如何通过一个函数得到两个返回值,得到的大概思路有几个:定义两个全局变量,设置一个长整数,返回长整数后再通过运算将其分开,或是往函数里传数组,酒后采用了传数组的方式。可是到了最后才发现不如直接在调用函数时直接在函数里写输出语句,因为本来需要的返回值便是输出结果。