二分法一直在查找已排序数据中占有很重要的位置,我们经常使用的二分法是在数组中使用。如下
/* binsearch: find x in v[0] <= v[1] <= ... <= v[n−1] */
int binsearch(int x, int v[], int n)
{
int low, high, mid;
low = 0;
high = n − 1;
while (low <= high) {
mid = (low+high)/2;
if (x < v[mid])
high = mid + 1;
else if (x > v[mid])
low = mid + 1;
else /* found match */
return mid;
}
return −1; /* no match */
}
但是有时候我们会使用指针操作数组中的元素,而不是使用数组下表,虽然两者具有千丝万缕的联系,这时候如果照搬上面程序是不能通过的,两个指针相加是违法的,这时候如果使用
mid = (low+high)/2; /*Wrong*/
编译器将会报错。然而两个指针相减则合法,表示两个指针之间的元素个数,注意是元素个数,而不是字节数。
因此我们可以这样运算
mid = low + (high-low)/2; /*right*/
下面是使用指针操作实现二分法运算。
/* binsearch: find word in v[0]...v[n−1] */
int *binsearch(int x, int *v, int n)
{
int* low = &v[0];
int* high = &v[n];
int* mid = NULL;
while (low < high) {
mid = low + (high−low) / 2;
if (x < *mid))
high = mid;
else if (x > *mid)
low = mid + 1;
else
return mid;
}
return NULL;
}
此处得到两端代码,我们可以研究一下两段代码的区别,首先就是关于high的初始化。第一段代码将high初始化为最后一个元素,第二段代码将high初始化为最后一个元素后面的一个元素。由于初始化的不同会对后面mid的赋值产生影响。我们可以发现代码中对边界真正的影响为图中红色部分,于是我们尝试修改代码时二者一致。于是下面的代码出现
/* binsearch: find word in v[0]...v[n−1] */
int *binsearch(int x, int *v, int n)
{
int* low = &v[0];
int* high = &v[n-1];
int* mid = NULL;
while low <= high) {
mid = low +(high - low)/ 2;
if (x < *mid)
high = mid-1;
else if (x > *mid)
low = mid + 1;
else
return mid;
}
return NULL;
}