简体   繁体   English

如何在二进制搜索中找到数组的最后一个元素

[英]How to find the last element of array in binary search

In binary Search algorithm, the upper-bound element is array.length-1 , then how can I find the last element of an array? 在二进制搜索算法中,上限元素是array.length-1 ,那么如何找到数组的最后一个元素?

If the lower-bound and upper-bound for element of an array of length 8 is 6 and 7 respectively, then my mid element coming out as: 如果长度为8的数组的下界和上限分别为6和7,那么我的中间元素的结果为:

mid=(6+7)/2 ie 6 in java mid =(6 + 7)/ 2即Java中的6

It really comes down to using the right compares with the correctly chosen midpoint. 真正归结为使用正确的比较与正确选择的中点。 For instance (without variable type declarations), 例如(没有变量类型声明),

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);
}

will give you the index of the leftmost element that matches val (even if it is the rightmost element in the array). 将为您提供与val匹配的最左边元素的索引(即使它是数组中最右边的元素)。 You don't need to explicitly check the last two or round up rather than using the built in integer truncation. 您无需显式检查最后两个或四舍五入,而无需使用内置的整数截断。

However, if you want the index of the rightmost element that is equal to val then you need to change the < operator to > and mid should be given by 但是,如果要使最右边的元素的索引等于val,则需要将<运算符更改为>,并且mid应该由

mid = (left+right+1)/2;

It's as simple as that. 就这么简单。

Edit: One more thing, I looked at my code that I use for this and realized that you have to to also change the the calls to binsearch to end up on the rightmost element. 编辑:还有一件事,我查看了我用于此的代码,并意识到您还必须将对binsearch的调用更改为最右边的元素。 I'll just post the full code for this (which I should have done in the first place). 我将为此发布完整的代码(首先应该完成)。 Here's a binary search to find the rightmost element equal to the val. 这是一个二进制搜索,以查找最右边等于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);
}

The simplest approach is to use half-open ranges. 最简单的方法是使用半开范围。 This way, your upper bound points one step after the last valid item in the array, though your lower bound points directly to the first item. 这样,您的上限就指向数组中最后一个有效项之后的一步,尽管您的下限直接指向了第一个项。 However, during the search, you treat your range as inclusive - the out-of-range upper bound is a valid "no match found" result. 但是,在搜索过程中,您将范围视为包含范围-超出范围上限是有效的“未找到匹配项”结果。

At the start of each iteration you have... 在每次迭代开始时,您都有...

lower <= target <= upper

"target" means the index that will be found and returned. “目标”是指将找到并返回的索引。

You calculate mid as "(upper + lower) / 2". 您将中值计算为“(上+下)/ 2”。 Since this truncates, mid can never be the same as upper, which is important. 由于这会被截断,因此mid永远不能与upper相同,这很重要。 Since "upper" may be out-of-bounds, we can never legally evaluate "array [upper]". 由于“上限”可能超出范围,因此我们永远无法合法地评估“数组[上限]”。

To find the first item greater-than-or-equal-to the key... 要找到大于或等于钥匙的第一项...

if array[mid] >= k :  lower <= target <= mid
if array[mid] <  k :  mid+1 <= target <= upper

To find the first item greater-than the key... 要找到比键大的第一项...

if array[mid] >  k :  lower <= target <= mid
if array[mid] <= k :  mid+1 <= target <= upper

These subranges are inclusive, and must precisely meet but not overlap. 这些子范围是包含性的,并且必须精确地满足但不能重叠。 A single item overlap at mid (an easy mistake) results in infinite loops, which is part of why we use mid+1 for one subrange. 单个项目在中间重叠(一个容易犯的错误)会导致无限循环,这就是为什么我们将mid + 1用于一个子范围的一部分。

Note that all that changes between the two searches is the comparison operator. 请注意,两次搜索之间的所有更改都是比较运算符。

To find last-less-or-equal, find first-greater and subtract one from the result. 要查找后等于或不等于,请查找第一个大于等于的值,然后从结果中减去一个。 You can get -1 if all items in the array are greater than the key. 如果数组中的所有项目都大于键,则可以得到-1。

Note - you only test key against mid in each iteration (you know that the lower and upper bounds are correct already) and you only do one conditional test. 注意-您只能在每次迭代中针对中点测试键(您知道上下限已经正确了),并且您仅执行一个条件测试。

Do the out-of-bounds check and equality check (if that's what you need) outside of the loop. 在循环进行越界检查和相等检查(如果您需要的话)。

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;
}

NOTE 注意

Edited to correct some mistakes that left this just as infinite-loopy as what it was meant to fix. 进行了修改,以纠正一些错误,这些错误使它像应解决的那样陷入无限循环。

The trick is to ensure that the bisected subranges are exactly as needed after each key test, and always at least one smaller than the original full range - and through overconfidence and bad memory, that's exactly what I managed to get wrong. 诀窍是确保在每次按键测试后,二等分的子范围完全符合需要,并且始终比原始的整个范围小至少一个-并通过过度自信和不良记忆,这正是我设法弄错的。 The above is based on real working code in a heavily-used library (searches within a node in a multiway-tree library), so if it's wrong I've got big problems ;-) 以上是根据实际工作的代码在一个频繁使用的库(在多路树库中的节点内搜索),所以如果这是错的我有很大的问题;-)

NOTE 注意

Edited again to improve wording and simplify the subrange bounds descriptions (noting that although the ranges are half-open, they are treated as inclusive). 再次进行编辑以改善措辞并简化子范围的边界描述(请注意,尽管范围是半开的,但它们被视为包含范围)。

You could round up each time. 您可以每次四舍五入。

(6+7)/2.0 == 6.5 (6 + 7)/2.0 == 6.5

Round it up and you'll come up with 7. 将其四舍五入,您将得出7。

Or you could simply add one to your midpoint. 或者,您可以将一个简单地添加到您的中点。

mid = (6+7)/2 + 1 中=(6 + 7)/ 2 + 1

Another way is changing your start or end point to +1 or -1 for the following recursion. 另一种方法是将您的起点或终点更改为+1或-1,以进行以下递归。 This is what the wikipedia article on the subject shows in some implementations. 这是有关此主题的Wikipedia文章在某些实现中显示的内容。

min = mid+1 分钟=中+1

or 要么

max = mid-1 最大值=中-1

当您的下限和上限位于彼此的一个范围内时,请同时选中两者。

Binary search is notoriously tricky to get exactly right. 众所周知,二进制搜索很难正确完成。 There is a very thorough analysis on the various problems and edge cases, along with a correct implementation, in Programming Pearls , a book that every programmer should probably have read at least once. Programming Pearls 》一书中对各种问题和极端情况进行了非常详尽的分析,并给出了正确的实现,每位程序员都应该至少阅读一本书。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何通过二进制搜索获取数组中的最后一个字符 - How to get the last char in an array with a binary search 如何使用二进制搜索来查找具有一定权重的数组中的第一个元素(另一个数组中的另一个元素)? - How to use binary search in order to find the first element in an array that has certain weight (another element in a different array)? 如何对数组中的一个特定元素进行二进制搜索? - how to binary search one specific element in an array? Java:递归二进制搜索以查找数组的元素-逻辑错误 - Java:Recursion Binary search to find element of an array-Logical error 如何在容量不足的数组中找到最后一个元素? - How to find the last element in an under capacity array? 如何通过特定键在数组中查找最后一个元素 - How to find last element in an array by specific key 如何使用二进制搜索在排序数组中查找重复项? - How to use Binary Search to find duplicates in sorted array? 如何在二叉搜索树数组实现中找到最大值的索引? - How to find the index of the maximum value in a Binary Search Tree array implementation? 二分查找找到不重复java的元素 - binary search find the element that does not repeat java 如何使用二进制搜索算法找到给定二进制密钥值的最接近元素? - How to find the closest element to a given binary key value using binary search algorithm?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM