如何使存储数组的二进制搜索稳定
How to make binary search of a stored array to be stable
这是在排序数组中对元素进行二进制搜索的代码:
#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
我看不出该怎么做。
您可以将匹配的条件从 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)最佳情况。
根据您在这里期望的相等元素数量,有两种方法:
-
只需从找到的元素开始在列表中向后倒退,直到到达第一个相等元素(取 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
请考虑将int binarySearch(int *arr, int l, int r, int data)
内部的return mid;
替换为以下内容:
for(; (mid > 0) && (data == arr[mid]); mid--);
return (data == arr[mid]) ? mid : mid + 1;
我更改了您的代码,以便它检查找到的每个元素是否也等于搜索的元素。
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
而不是 mid - 1
或 mid + 1
)。这是代码(抱歉更改格式)。
if (data == arr[mid]) {
if (r - l == 0) {
return mid;
}
return binarySearch(arr, l, mid, data);
}
if(data < arr[mid])
return binarySearch(arr, l, mid-1, data);
return binarySearch(arr, mid+1, r, data);
有了<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);
}
演示
- 有根的二进制搜索树.保留与其父级的链接
- cpp二进制搜索问题,计算给定数组中输入元素的出现次数
- 二进制搜索树叶数问题
- 为什么二进制搜索在我的测试中不起作用
- 正在尝试重载二进制搜索树分配运算符
- 我的二进制搜索程序只是关闭了
- 二进制搜索的终止点
- 递归二进制搜索与字符串数组
- 测试树是否为二进制搜索树
- 如何二进制搜索结构向量并在适当的索引处插入
- 如果你有一个固定大小的数组,你需要遍历它!n次,使用二进制搜索如何改变时间复杂性
- 字符串的递归二进制搜索-C++
- 使用二进制搜索树中的迭代器对象访问左侧节点
- 二进制搜索树没有匹配的函数调用
- 二进制搜索不适用于特定输出
- 如何在向量上进行二进制搜索以找到具有特定id的元素
- 如何将Z3_ast导出为二进制以及如何搜索函数名称?
- 二进制搜索树不变的标头文件
- 在C++中搜索二进制文件分隔符时出现不正确的偏移量
- 可视化 在 c++ 中读取和搜索二进制文件