在二进制搜索算法中,上限元素是array.length-1
,那我怎样才能找到数组的最后一个元素?
如果长度为8的数组的元素的下限和上限分别为6和7,那么我的mid元素将显示为:
mid =(6 + 7)/ 2,即java中的6
答案 0 :(得分:5)
真正归结为使用正确选择正确选择的中点。例如(没有变量类型声明),
binsearch(a,val,left,right){
if(left==right) return left;
mid = (left+right)/2;
if(a[mid] < val)
return binsearch(a,val,mid+1,right);
else
return binsearch(a,val,left,mid);
}
将为您提供与val匹配的最左边元素的索引(即使它是数组中最右边的元素)。您不需要显式检查最后两个或向上舍入而不是使用内置整数截断。
但是,如果您希望最右边元素的索引等于val,则需要更改&lt;运营商&gt;
应该给出中期mid = (left+right+1)/2;
就这么简单。
编辑:还有一件事,我查看了我用于此的代码,并意识到你还必须将对binsearch的调用更改为最右边的元素。我将发布完整的代码(我应该首先完成)。这是一个二进制搜索,找到最右边的元素等于val。
binsearch(a,val,left,right){
if(left==right) return left;
mid = (left+right+1)/2;
if(a[mid] > val)
return binsearch(a,val,left,mid-1);
else
return binsearch(a,val,mid,right);
}
答案 1 :(得分:2)
最简单的方法是使用半开范围。这样,您的上限指向数组中最后一个有效项之后的一步,尽管您的下限直接指向第一个项。但是,在搜索过程中,您将范围视为包含范围 - 超出范围的上限是有效的“找不到匹配”结果。
在每次迭代开始时你都有......
lower <= target <= upper
“target”表示将找到并返回的索引。
您将mid计算为“(上+下)/ 2”。由于这个截断,mid可能永远不会与upper相同,这很重要。由于“上限”可能超出范围,我们永远无法合法地评估“数组[上部]”。
找到大于或等于密钥的第一个项目......
if array[mid] >= k : lower <= target <= mid
if array[mid] < k : mid+1 <= target <= upper
要找到比键更大的第一项......
if array[mid] > k : lower <= target <= mid
if array[mid] <= k : mid+1 <= target <= upper
这些子范围是包容性的,必须精确地满足但不重叠。单个项目在中间重叠(一个容易出错的错误)导致无限循环,这是我们为一个子范围使用mid + 1的原因的一部分。
请注意,两次搜索之间发生的所有变化都是比较运算符。
要找到last-less-equal,找到first-greater并从结果中减去1。如果数组中的所有项都大于键,则可以获得-1。
注意 - 你只在每次迭代中对着mid测试键(你知道下限和上限已经正确),你只做一次条件测试。
进行越界检查和相等检查(如果这就是你需要的)在之外的循环。
int find_first_ge (int key)
{
int lower = 0;
int upper = array.length;
while (upper > lower)
{
int mid = (lower + upper) / 2;
if (array [mid] >= key) // for find_first_gt, use ">" here
{
upper = mid;
}
else
{
lower = mid + 1;
}
}
return lower;
}
注意强>
编辑纠正了一些错误,这些错误使得这个错误与它的修复方式一样无限循环。
诀窍是确保在每次关键测试后,二分的子范围完全符合要求,并且始终至少比原始的整个范围小一个 - 并且通过过度自信和坏内存,这正是我设法弄错了。以上是基于大量使用的库中的实际工作代码(在多路树库中的节点内搜索),所以如果它错了我有大问题; - )
注意强>
再次编辑以改进措辞并简化子范围界限描述(注意尽管范围是半开放的,但它们被视为包容性的。)
答案 2 :(得分:0)
你可以每次都围捕。
(6 + 7)/2.0 == 6.5
将它围起来,你会得到7。
或者您只需在中点添加一个。
mid =(6 + 7)/ 2 + 1
另一种方法是将开始或结束点更改为+1或-1以进行以下递归。这是关于该主题的维基百科文章在某些实现中所显示的内容。
min = mid + 1
或
max = mid-1
答案 3 :(得分:0)
当你的下限和你的上限在一个之内时,检查两者。
答案 4 :(得分:0)
完全正确地进行二进制搜索是非常棘手的。在Programming Pearls中,对每个程序员应该至少读过一次的书,对各种问题和边缘情况以及正确的实现进行了非常全面的分析。