一. 实践题目
7-2 改写二分搜索算法
设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
二. 问题理解
这个问题是二分搜索算法的改进,我的想法是在二分搜索算法的基础上,搜索元素在数组中时,输出改为下标输出两次。搜索元素不在数组中时按照题目要求输出相应的值,而这一情况可以放到搜索元素在数组中这一情况之前进行判断。
三. 算法描述
按照我对这个问题的理解,第一步就是输入数组长度,要搜索的数以及数组元素。第二步是设置三个指针,分别为i,j,指向数组头尾,还有一个mid,应(i+j)/2。因为数组是有序的,可以直接进行判断,第一种情况,当搜索元素小于数组的第一个元素时,直接输出-1 0,第二种情况,当搜索元素大于最后一个元素时,直接输出n-1 n,第三种情况,搜索元素大小在数组第一个和最后一个元素之间时,这个时候的思想是第一题里面的二分搜索,将x与a[mid]进行比较,然后指针移动,当找到元素时直接输出下标两次,若找不到元素则输出左右元素的下标。
四. 代码实现
#include <iostream>
using namespace std;
int main(){
int n,x;
cin >> n >> x;
if(1<=n<=100){
int a[n];
for(int i=0;i<n;i++){
cin >> a[i];
}
int i = 0;
int j = n-1;
int mid;
if(x<a[0]){
cout << "-1 " << "0" <<endl;
return 0;
}
else if(x>a[n-1]) {
cout << n-1 <<" "<<n<<endl;
return 0;
}
else {
while(i<=j){
mid = (i+j)/2;
if(x==a[mid]){
cout << mid << " " << mid << endl;
return 0;
}
else if(x < a[mid]){
j = mid - 1;
}
else if(x > a[mid]){
i = mid+1;
}
}
cout << j <<" "<< i <<endl;
}
}
return 0;
}
五. 时间复杂度和空间复杂度分析
1. 时间复杂度:
O(log n)相比于7-1进行了改进,但还是利用二分搜索算法时间复杂度并未改变。
2. 空间复杂度:
非递归算法,O(1)
六. 心得体会
首先当时写这段代码的时候输出的数组指针写反了,运行结果是反过来的这才注意到这个问题。然后其中搜索元素在数组中的查找算法是将7-1所写的算法进行了简单的修改。第三,在拼题中提交的时候出现了部分错误的情况,但是找了好几遍之后才发现之前写的代码,搜索元素在数组中的这一情况,我将输出写成了cout << mid <<endl; 而题目要求的是输出i和j,这才发现应该改成cout << mid <<" " << mid <<endl;以后会多注意题目的要求,细心审题。