第一步:从伪代码到具体的C语言代码
一般版本:
int binarysearch(int arr[], int n, int key)
{
int low = 0, high = n;
while(low < high)
{
int mid = low + (high - low) / 2;
if(arr[mid] == key)
{
cout<<"fad";
return mid;
}
else if(arr[mid] > key)
high = mid;
else
low = mid + 1;
}
return -1;
}
递归版本:
int binarysearch(int arr[], int low, int high, int key)
{
if(low >= high)
return -1;
int mid = low + (high - low) / 2;
cout<<"low :"<<low<<" high :"<<high<<" mid :"<<mid<<endl;
count++;
if(arr[mid] == key)
return mid;
else if(arr[mid] > key)
binarysearch(arr, low, mid, key);
else
binarysearch(arr, mid + 1, high, key);
}
第二步:测试装备
先通过一些自定义的小数据来测试该程序,对于大数据,就可以使用数据生成器生成测试文件,然后再测试。
小范围的脚手架程序:
scanf("%d %d", &n, &key);
for(int i = 0; i < n; ++i)
scanf("%d", &arr[i]);
cout<<binarysearch(arr, n, key)<<endl;
当然,如果程序出现一些bug,我们可以在binarysearch中进行debug,比如这个程序问题多半处在循环内部中(上下界处理不当造成了死循环),我们就可以尝试在循环输出上下界,如果有问题就分析,没有就测试循环外部分。
*******在程序中恰当使用printf输出语句具有良好的疗效*******
第三步:断言的艺术
对一些边界情况使用断言也许会很快找到问题的所在。当我们在脚手架中测试函数,以及从组件测试移到系统系统测试中时,断言说很有帮助的。
第四步:自动化测试
使用一些辅助程序来让系统帮我们测试我们编写程序的正确性。典型代表就是:数据生成器+文件重定向函数+对拍程序(fc或diff)
第五步:计时(分析时间复杂度)
通过不同的数据量对该程序的性能进行统计分析(本质就是测试时间复杂度与实际效率的比较)
第六步:完整的程序
通过上述五个步骤的开发,这时的程序就可以在需要的地方使用了。当然,如果在使用的过程中需求有了变化,则再进行同样的步骤进行修改就可以了。
以此为基础,分别写出lower_bound和upper_bound。(左闭右开)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
int lowbound(int arr[], int n, int key)
{
int low = 0, high = n;
while(low < high)
{
int mid = (low + high) / 2;
if(arr[mid] >= key)
high = mid;
else
low = mid + 1;
}
return low;
}
int upperbound(int arr[], int n, int key)
{
int low = 0, high = n;
while(low < high)
{
int mid = (low + high) / 2;
if(arr[mid] <= key)
low = mid + 1;
else
high = mid;
}
return high;
}
int main()
{
int arr[10];
for(int i = 0; i < 10; ++i)
cin>>arr[i];
int p = lowbound(arr, 10, 4);
int q = upperbound(arr, 10, 4);
cout<<p<<" "<<q<<endl;
return 0;
}