int recurbinarysearch(int * oringalary, int low, int high, int target) {
if (low > high) {
return -1;
} else {
int mid = (low + high) / 2;
if (target == * (oringalary + mid)) return mid;
if (target > * (oringalary + mid)) return recurbinarysearch(oringalary, mid + 1, high, target);
if (target < * (oringalary + mid)) return recurbinarysearch(oringalary, low, mid - 1, target);
}
}
有人在我的递归二进制搜索算法中看到错误吗?有时候它会返回一个不正确的索引(通常是一个关闭的索引),但偶尔会离开它。但通常是正确的。我没有看到这个问题,不胜感激。
答案 0 :(得分:1)
编辑这是可以接受的,所以我想我应该尝试将其变成正确答案。
我最初假设(请参阅下面的“注意”)问题是使用了半开边界。它实际上(正确地)使用包含边界。在首次通话中,low=0
和high=n-1
。
使用包容性边界通常被认为是一件坏事 - 请参阅Dijkstra的经典(PDF)。在C系列语言中,半开边界是常见的约定,甚至是for (i = 0; i < n; i++)
优于for (i = 0; i <= n-1; i++)
的偏好。但是,考虑到使用包含边界,问题中的代码似乎是正确的。
正如WhozCraig在评论中发现的那样,调用代码并不尊重该约定,并且传递了错误的界限 - 包括搜索范围内的越界垃圾项。因为该额外项目是垃圾,所以范围中的项目被排序的假设也可能无效。大多数搜索都不会找到垃圾项(因为你不太可能搜索它所拥有的任何垃圾值),但它会误导搜索。
注意这可能不是答案,但评论时间过长。
您的界限是包容性的,排他的还是半开放的?
我将在low
处假设半开放式,high
独占。如果是这样,这条线看起来错了......
if (target < * (oringalary + mid))
return recurbinarysearch(oringalary, low, mid - 1, target);
原因是您已在mid
检查了该项目,但您使用mid - 1
作为新的独占上限。这意味着mid - 1
处尚未检查的项目已被意外排除在搜索范围之外。这条线应该是......
if (target < * (oringalary + mid))
return recurbinarysearch(oringalary, low, mid, target);
这会使项目保持在mid - 1
范围内以进行搜索。 mid
处的项目将不会再次被搜索,因为上限是独占的。
在二进制搜索中弄乱边界是一个常见问题,它会导致更多的错误。
然而,这本身并不能解释你的症状 - 它有时候很难找到项目(可能大约有50%的搜索次数),但它不应该报告错误的搜索位置成功了。
二进制搜索中错误边界的常见症状是无限循环(重复检查相同的项目,因为它没有从边界中排除)或搜索未能找到存在的项目(因为项目被排除在搜索范围之外)没有检查过。)
说实话,我看不出你的症状是如何发生的。函数退出的每种可能方式都应该给出正确的成功结果,否则-1
失败结果。我能想到的唯一可能的例外是在这段代码之外 - 误解了结果,例如:未能检查-1
结果。
编辑我想我发现了界限的另一个问题 - 仍然假设半开,这条线错了......
if (low > high) {
应该是......
if (low >= high) {
原因是对于半开边界,如果边界相等,则检查之间没有项目 - 即使是低边界项也无效,因为高边界等于它并且是独占的。这允许你仍然测试
答案 1 :(得分:1)
有关二元搜索的详尽讨论,请研究Jon Bentley的Programming Pearls。
这是代码的测试工具,非常受Programming Pearls的启发,以及代码的检测版本。我做的唯一改变是在二进制搜索中添加(现已注释掉)调试打印。测试代码的输出几乎是完美的(线束说一切都通过了,但它不太正确):
N = 0:
search for 0 in 0 entries - returned 0 found 0 PASS
N = 1: [0] = 1;
search for 0 in 1 entries - returned -1 PASS
search for 1 in 1 entries - returned 0 found 1 PASS
search for 2 in 1 entries - returned -1 PASS
N = 2: [0] = 1;[1] = 3;
search for 0 in 2 entries - returned -1 PASS
search for 1 in 2 entries - returned 0 found 1 PASS
search for 2 in 2 entries - returned -1 PASS
search for 3 in 2 entries - returned 1 found 3 PASS
search for 4 in 2 entries - returned -1 PASS
N = 3: [0] = 1;[1] = 3;[2] = 5;
search for 0 in 3 entries - returned -1 PASS
search for 1 in 3 entries - returned 0 found 1 PASS
search for 2 in 3 entries - returned -1 PASS
search for 3 in 3 entries - returned 1 found 3 PASS
search for 4 in 3 entries - returned -1 PASS
search for 5 in 3 entries - returned 2 found 5 PASS
search for 6 in 3 entries - returned -1 PASS
N = 4: [0] = 1;[1] = 3;[2] = 5;[3] = 7;
search for 0 in 4 entries - returned -1 PASS
search for 1 in 4 entries - returned 0 found 1 PASS
search for 2 in 4 entries - returned -1 PASS
search for 3 in 4 entries - returned 1 found 3 PASS
search for 4 in 4 entries - returned -1 PASS
search for 5 in 4 entries - returned 2 found 5 PASS
search for 6 in 4 entries - returned -1 PASS
search for 7 in 4 entries - returned 3 found 7 PASS
search for 8 in 4 entries - returned -1 PASS
N = 5: [0] = 1;[1] = 3;[2] = 5;[3] = 7;[4] = 9;
search for 0 in 5 entries - returned -1 PASS
search for 1 in 5 entries - returned 0 found 1 PASS
search for 2 in 5 entries - returned -1 PASS
search for 3 in 5 entries - returned 1 found 3 PASS
search for 4 in 5 entries - returned -1 PASS
search for 5 in 5 entries - returned 2 found 5 PASS
search for 6 in 5 entries - returned -1 PASS
search for 7 in 5 entries - returned 3 found 7 PASS
search for 8 in 5 entries - returned -1 PASS
search for 9 in 5 entries - returned 4 found 9 PASS
search for 10 in 5 entries - returned -1 PASS
N = 6: [0] = 1;[1] = 3;[2] = 5;[3] = 7;[4] = 9;[5] = 11;
search for 0 in 6 entries - returned -1 PASS
search for 1 in 6 entries - returned 0 found 1 PASS
search for 2 in 6 entries - returned -1 PASS
search for 3 in 6 entries - returned 1 found 3 PASS
search for 4 in 6 entries - returned -1 PASS
search for 5 in 6 entries - returned 2 found 5 PASS
search for 6 in 6 entries - returned -1 PASS
search for 7 in 6 entries - returned 3 found 7 PASS
search for 8 in 6 entries - returned -1 PASS
search for 9 in 6 entries - returned 4 found 9 PASS
search for 10 in 6 entries - returned -1 PASS
search for 11 in 6 entries - returned 5 found 11 PASS
search for 12 in 6 entries - returned -1 PASS
N = 7: [0] = 1;[1] = 3;[2] = 5;[3] = 7;[4] = 9;[5] = 11;[6] = 13;
search for 0 in 7 entries - returned -1 PASS
search for 1 in 7 entries - returned 0 found 1 PASS
search for 2 in 7 entries - returned -1 PASS
search for 3 in 7 entries - returned 1 found 3 PASS
search for 4 in 7 entries - returned -1 PASS
search for 5 in 7 entries - returned 2 found 5 PASS
search for 6 in 7 entries - returned -1 PASS
search for 7 in 7 entries - returned 3 found 7 PASS
search for 8 in 7 entries - returned -1 PASS
search for 9 in 7 entries - returned 4 found 9 PASS
search for 10 in 7 entries - returned -1 PASS
search for 11 in 7 entries - returned 5 found 11 PASS
search for 12 in 7 entries - returned -1 PASS
search for 13 in 7 entries - returned 6 found 13 PASS
search for 14 in 7 entries - returned -1 PASS
N = 8: [0] = 1;[1] = 3;[2] = 5;[3] = 7;[4] = 9;[5] = 11;[6] = 13;[7] = 15;
search for 0 in 8 entries - returned -1 PASS
search for 1 in 8 entries - returned 0 found 1 PASS
search for 2 in 8 entries - returned -1 PASS
search for 3 in 8 entries - returned 1 found 3 PASS
search for 4 in 8 entries - returned -1 PASS
search for 5 in 8 entries - returned 2 found 5 PASS
search for 6 in 8 entries - returned -1 PASS
search for 7 in 8 entries - returned 3 found 7 PASS
search for 8 in 8 entries - returned -1 PASS
search for 9 in 8 entries - returned 4 found 9 PASS
search for 10 in 8 entries - returned -1 PASS
search for 11 in 8 entries - returned 5 found 11 PASS
search for 12 in 8 entries - returned -1 PASS
search for 13 in 8 entries - returned 6 found 13 PASS
search for 14 in 8 entries - returned -1 PASS
search for 15 in 8 entries - returned 7 found 15 PASS
search for 16 in 8 entries - returned -1 PASS
N = 9: [0] = 1;[1] = 3;[2] = 5;[3] = 7;[4] = 9;[5] = 11;[6] = 13;[7] = 15;[8] = 17;
search for 0 in 9 entries - returned -1 PASS
search for 1 in 9 entries - returned 0 found 1 PASS
search for 2 in 9 entries - returned -1 PASS
search for 3 in 9 entries - returned 1 found 3 PASS
search for 4 in 9 entries - returned -1 PASS
search for 5 in 9 entries - returned 2 found 5 PASS
search for 6 in 9 entries - returned -1 PASS
search for 7 in 9 entries - returned 3 found 7 PASS
search for 8 in 9 entries - returned -1 PASS
search for 9 in 9 entries - returned 4 found 9 PASS
search for 10 in 9 entries - returned -1 PASS
search for 11 in 9 entries - returned 5 found 11 PASS
search for 12 in 9 entries - returned -1 PASS
search for 13 in 9 entries - returned 6 found 13 PASS
search for 14 in 9 entries - returned -1 PASS
search for 15 in 9 entries - returned 7 found 15 PASS
search for 16 in 9 entries - returned -1 PASS
search for 17 in 9 entries - returned 8 found 17 PASS
search for 18 in 9 entries - returned -1 PASS
几乎所有这些都很好;唯一的问题是第一次搜索,这应该会失败,因为在空数组中找不到任何值。
测试代码是:
#include <stdio.h>
int recurbinarysearch(int *oringalary, int low, int high, int target)
{
//printf("-->> %d..%d: ", low, high);
if (low > high)
{
//printf("<<-- %d ", -1);
return -1;
}
else
{
int mid = (low + high) / 2;
if (target == * (oringalary + mid))
{
//printf("<<-- %d ", mid);
return mid;
}
if (target > * (oringalary + mid))
{
int r = recurbinarysearch(oringalary, mid + 1, high, target);
//printf("<<-- %d ", r);
return r;
}
if (target < * (oringalary + mid))
{
int r = recurbinarysearch(oringalary, low, mid - 1, target);
//printf("<<-- %d ", r);
return r;
}
}
}
int main(void)
{
for (int i = 0; i < 10; i++)
{
int a[i+1]; // No zero-size arrays in C
printf("N = %2d: ", i);
for (int j = 0; j < i; j++)
{
a[j] = 2 * j + 1;
printf("[%d] = %d;",j, a[j]);
}
putchar('\n');
for (int j = 0; j < 2*i+1; j++)
{
int f = recurbinarysearch(a, 0, i, j);
//putchar('\n'); // debug
printf("search for %2d in %2d entries - returned %2d",
j, i, f);
if (f >= 0 && f <= i)
{
printf(" found %2d", a[f]);
printf(" %s", (a[f] == j) ? "PASS" : "FAIL");
}
else
printf(" %8s %s", "", (j % 2 == 0) ? "PASS" : "FAIL");
putchar('\n');
}
}
return(0);
}
我将离开你去研究如何处理空数组的情况。