在我的C二进制搜索代码中我做错了什么?(迭代和递归)
我做错了什么? 原型是不可变的。 我需要写这两个函数,这就是我写的。 他们90%的时间都在工作。当我试图搜索中间元素时,迭代方法遇到了一个问题 递归方法有一些问题,但我真的不知道是怎么回事。有时它会找到元素,有时则不会 还有一件事我不能改变,那就是我必须避免检查函数内部是否在我的C二进制搜索代码中我做错了什么?(迭代和递归),c,algorithm,recursion,search,binary-search,C,Algorithm,Recursion,Search,Binary Search,我做错了什么? 原型是不可变的。 我需要写这两个函数,这就是我写的。 他们90%的时间都在工作。当我试图搜索中间元素时,迭代方法遇到了一个问题 递归方法有一些问题,但我真的不知道是怎么回事。有时它会找到元素,有时则不会 还有一件事我不能改变,那就是我必须避免检查函数内部是否array[middle]==key。老师希望我们只在我退出循环时做这个检查,他希望循环只检查我应该向右还是向左 int *BinarySearchIter(const int SortedArray[], int key,
array[middle]==key
。老师希望我们只在我退出循环时做这个检查,他希望循环只检查我应该向右还是向左
int *BinarySearchIter(const int SortedArray[], int key, size_t length)
{
/* variables that will set the boundries of the searched area */
int left_index = 0, right_index = 0, middle = 0;
int *result = NULL;
assert(SortedArray);
assert(length);
left_index = 0; /* first elemenet in the array */
right_index = length - 1; /* last elemenet in the array */
/* while only one elemenet is left in the searched area */
while (left_index <= right_index)
{
/* split it to half */
middle = (left_index + right_index) / 2;
/* if key greater, ignore left half, search only in right half */
if (SortedArray[middle] < key)
{
left_index = middle + 1;
}
/* if key smaller, ignore right half, search only in left half */
else
{
right_index = middle - 1;
}
}
/* if we reach here, then element is the key or was not found */
result = (int *)SortedArray + middle;
return (key == *result ? result : NULL);
}
/******************************************************************************/
int *BinarySearchRec(const int SortedArray[], int key, size_t length)
{
int left_index = 0; /* first elemenet of the array */
int right_index = length - 1; /* last elemenet in the array */
int middle = 0, isBigger = 0;
if (1 == length)
{
return (key == *SortedArray ? (int *)SortedArray : NULL);
}
middle = (left_index + right_index) / 2;
isBigger = (key > SortedArray[middle]);
return (BinarySearchRec(SortedArray+(middle + 1)*isBigger, key, isBigger * (length - length /2 ) + !isBigger*(length/2)));
}
/******************************************************************************/
用于迭代函数
让我们想想你的代码在做什么。您有一个由5个元素组成的数组,假设您正在搜索8
2 4 8 10 12
^
在第一次迭代中,值如下所示:
left_index = 0, right_index = 4, middle_index = 2
const int *BinarySearchIter(const int SortedArray[], int key, size_t length) {
int left_index = 0, right_index = length - 1;
while (left_index < right_index) {
int middle = (left_index + right_index) / 2;
if (SortedArray[middle] < key) {
left_index = middle + 1;
} else {
right_index = middle;
}
}
return SortedArray[right_index] == key ? SortedArray + right_index : NULL;
}
在if语句中,程序检查(SortedArray[middle_index]else {
right_index = middle;
}
while (left_index < right_index)
让我们继续第二次迭代:
2 4 8
^
left_index = 0, right_index = 2, middle_index = 1
在第二次迭代之后,第三次迭代只包含1个元素
8
left_index = 2, right_index = 2, middle_index = 2
此时,程序将进入无限循环,因为它总是执行else语句。左右索引始终保持不变
因此,您需要做的第二个更改是将while条件更改为:
else {
right_index = middle;
}
while (left_index < right_index)
其原因与迭代函数相同。您需要包含中间元素。对于阵列的下部,阵列长度需要等于ceil(长度/2),对于阵列的上部,阵列长度需要等于floor(长度/2)
2 4 8 10 12
^
您也可以这样做:
const int *BinarySearchRec(const int SortedArray[], int key, size_t length) {
if (1 == length) return (key == *SortedArray ? SortedArray : NULL);
int middle = (length + 1) / 2;
if (key >= SortedArray[middle]) return BinarySearchRec(SortedArray + middle, key, length / 2);
else return BinarySearchRec(SortedArray, key, middle);
}
在
BinarySearchRec
中,假设length
为5。然后,右索引
为5,中间
为(0+4)/2
=2。然后,如果isbiger
为0,则传递给递归调用的长度为length/2
,即2。因此递归调用将搜索两个元素,即索引为0和1的元素。如果更大
为1,则它通过SortedArray+(中间+1)*1
,因此SortedArray+3
,它通过长度长度-长度/2
,即5−2 = 3. 因此,递归调用被要求搜索索引为3、4和5的元素,这是错误的。在迭代代码中,如果您没有测试中间值是否相等,那么您就不能在下一次迭代中删除它。@斯塔克问题是,他不希望我们在退出循环之前测试中间值是否相等。如果middle==key,只需添加就很容易了。。返回while循环开始时的
。但他不想让我们这么做。他希望我们找到一种方法,仅当您退出循环并需要返回找到的索引时才检查它。这就是为什么我要在return
行中检查它。@NoobCoder:Stark的评论告诉你问题出在哪里。它并没有说要检验中间人是否平等。它说,因为您无法测试中间值是否相等,所以在准备下一次迭代时不要删除它。分配<代码>右索引=中间-1是错误的,因为它排除了中间部分。因为没有测试中间值是否相等,所以不能排除它。赋值应该是right\u index=middle
@EricPostpischil嘿,谢谢你的回答。如果我们假设length
为5,则意味着right\u索引
为4
,因为right index=length-1
<在这种情况下,code>middle实际上是2
。然后,如果更大
为0
,这意味着键
小于中间
,我们需要扫描数组的左侧。它传递到递归调用:SortedArray[]的原始开始作为开始、键,2作为长度,..
好,说实话,我迷路了。你能指出我到底应该修什么吗?也许除了length/2
我应该发送length/2+1吗?
Wow!多么完美的答案,你帮助我理解了我的错误,并从中吸取教训,还提供了一个固定的代码。谢谢,我很感激!在编辑答案之前,您在myreccursive
函数中编写了三件要修复的事情。为什么要删除其中的两个?我想问你为什么要在中间索引=(左索引+右索引+1)/2中添加+1
;
?我可以只写middle=length/2吗?
我意识到有一个修改较小的补丁,所以我修改了递归函数的补丁。我添加了1,因为当我试图解决这个问题时,我没有使用first_索引和last_索引,而是直接使用长度,所以它导致了有限循环。然后我用ceil找到了一个解决方案,然后将该解决方案实现到您的代码中。我认为如果不加1,它将导致无限循环。然后我意识到您使用的是第一个和最后一个索引,不需要做其他更改。我想这是一个更好的方法。谢谢。如果你有任何其他的提示和建议,我很乐意听到,因为你的评论帮助我深刻理解我在实现中的错误。