以下是对已排序数组中的元素进行二进制搜索的代码:
#include<stdio.h>
int binarySearch(int *arr, int l, int r, int data)
{
if(l > r)
return -1;
int mid = l+(r-l)/2; //find the middle index
if(data < arr[mid]) {
return(binarySearch(arr, l, mid-1, data));
}
else if(data > arr[mid]) {
return(binarySearch(arr, mid+1, r, data));
}
else {
return mid;
}
}
int main()
{
int arr [] = {0 , 11, 22, 33, 44, 55, 66 };
int n = sizeof(arr)/sizeof(arr[0]);
int data = 22;
int index = binarySearch(arr, 0, n-1, data);
if( index != -1)
{
printf("%d" , index);
}
return 0;
}
如何使搜索稳定?当重复数组的元素时,我的搜索应该返回数组中数据的第一次出现的索引。
我希望修改后的代码能够生成输出:
input array is {1, 22, 22, 22}
output = 1,
input array is {1, 12, 15, 22, 22, 22, 22, 22, 22, 22, 55 ,66}
output = 3
我看不出怎么做。
答案 0 :(得分:3)
您可以将匹配的条件从arr[mid] == data
更改为更复杂的arr[mid] == data && (mid == 0 || arr[mid-1] != data)
。变化:
else {
return mid;
}
为:
else if (mid == 0 || arr[mid-1] != data) {
// note that arr[mid] == data is implied at this point
return mid;
}
else {
return(binarySearch(arr, l, mid, data));
}
如果在阵列中存在大量搜索值,这仍然可以提供O(log(n))性能(与其他一些更简单的解决方案相比,在这种情况下会降低到O(n)性能)。您还可以保留原始搜索中的O(1)最佳情况:也就是说,可能在没有任何递归的情况下找到结果。
请注意,它确实假设可以访问低于(l
)绑定的数组,如果绑定不是0,则原始代码不会做出这样的假设。在您发布的示例中,这不是问题。如果这是一个问题,您可以传递原始边界(例如,ol
,然后mid == 0
在上面成为mid == ol
),或者改为使用:
else if (mid == l) {
return mid;
}
else {
return(binarySearch(arr, l, mid - 1, data));
}
然而,后者失去了O(1)最佳案例。
答案 1 :(得分:1)
根据您期望的平等元素数量,这里有两种方法:
只需从找到的元素开始在列表中向后移动,直到到达第一个相等的元素(取 O(n) n =相等元素的数量)
再次搜索从索引0开始并以找到的元素的索引结束的子数组。这样做直到新的声音元素具有与之前找到的索引相同的索引。
这里是版本2的插图(让每个角色成为一个元素)并寻找 B
AAAABBBBBBBBBBBBBBBBBBBBBBCDDDDEEEFFFZ
^ ^ search range
AAAABBBBBBBBBBBBBBBBBBBBBBCDDDDEEEFFFZ
^ ! ^ found at position !
AAAABBBBBBBBBBBBBBBBBBBBBBCDDDDEEEFFFZ
^ ^ new search range
AAAABBBBBBBBBBBBBBBBBBBBBBCDDDDEEEFFFZ
^ ! ^ found at position !
(different from previous finding position)
AAAABBBBBBBBBBBBBBBBBBBBBBCDDDDEEEFFFZ
^ ^ new search range
AAAABBBBBBBBBBBBBBBBBBBBBBCDDDDEEEFFFZ
^ ! ^ found at position !
(different from previous finding position)
AAAABBBBBBBBBBBBBBBBBBBBBBCDDDDEEEFFFZ
^ ^ new search range
AAAABBBBBBBBBBBBBBBBBBBBBBCDDDDEEEFFFZ
^ !^ found at position !
(different from previous finding position)
AAAABBBBBBBBBBBBBBBBBBBBBBCDDDDEEEFFFZ
^ ^ new search range
AAAABBBBBBBBBBBBBBBBBBBBBBCDDDDEEEFFFZ
^ ! found at same position as before => lirst one
答案 2 :(得分:0)
请考虑使用以下内容替换return mid;
内的int binarySearch(int *arr, int l, int r, int data)
:
for(; (mid > 0) && (data == arr[mid]); mid--);
return (data == arr[mid]) ? mid : mid + 1;
答案 3 :(得分:0)
我已经更改了您的代码,因此它会检查找到左边的每个元素是否也等于搜索元素。
if(data < arr[mid]) {
return(binarySearch(arr, l, mid-1, data));
}
else if(data > arr[mid]) {
return(binarySearch(arr, mid+1, r, data));
}
else {
while(mid && data == arr[--mid]);
return mid + 1;
}
但是,如果您的整个数组包含相同的元素,那么它可能会很慢。其他解决方案是继续搜索,但您需要记住,找到的元素是有效的并且可能是唯一有效的元素,因此您不应该在下一次递归调用时丢失它(使用mid
而不是{{1} }或mid - 1
)。
这是代码(抱歉更改格式)。
mid + 1
答案 4 :(得分:0)
使用<algorithm>
,您可以
int binarySearch(const int *arr, int l, int r, int data)
{
// inclusive `r` for binarySearch
auto it = std::lower_bound(arr + l, arr + r + 1, data);
if (it == arr + r + 1 || *it != data) {
return -1;
}
return std::distance(arr + l, it);
}