二进制搜索,用于查找排序数组中比给定值最小和最大的元素
Binary search for finding the lowest and largest element in a sorted array than a given value?
所以,我试图实现二进制搜索算法(尽可能通用,可以适应不同的情况)。我在网上搜索了这个,有些用法,while (low != high)
和有些用法,while (low <= high)
和其他一些不同的条件,这很令人困惑。
因此,我开始编写代码来查找第一个大于给定元素的元素。我想知道是否还有比这更优雅的解决方案?
主要代码:
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <utility>
#include <algorithm>
#include <stack>
#include <queue>
#include <climits>
#include <set>
#include <cstring>
using namespace std;
int arr1[2000];
int n;
int main (void)
{
int val1,val2;
cin>>n;
for (int i = 0; i < n; i++)
cin>>arr1[i];
sort(arr1,arr1+n);
cout<<"Enter the value for which next greater element than this value is to be found";
cin>>val1;
cout<<"Enter the value for which the first element smaller than this value is to be found";
cin>>val2;
int ans1 = binarysearch1(val1);
int ans2 = binarysearch2(val2);
cout<<ans1<<"n"<<ans2<<"n";
return 0;
}
int binarysearch1(int val)
{
while (start <= end)
{
int mid = start + (end-start)/2;
if (arr[mid] <= val && arr[mid+1] > val)
return mid+1;
else if (arr[mid] > val)
end = mid-1;
else
start = mid+1;
}
}
类似地,为了找到比给定元素小的第一个元素,
int binarysearch2(int val)
{
while (start <= end)
{
int mid = start + (end-start)/2;
if (arr[mid] >= val && arr[mid] < val)
return mid+1;
else if (arr[mid] > val)
end = mid-1;
else
start = mid+1;
}
}
当我不得不为这种抽象修改二进制搜索时,我经常感到非常困惑。请告诉我是否有更简单的方法?谢谢
正如您所说,有不同的方式来表示二进制搜索的结束条件,这完全取决于您的两个极限的含义。让我来解释一下我的,我认为这很容易理解,它可以让你在不想太多的情况下为其他情况修改它。
让我把这两个极限称为第一个和最后。我们想要找到大于某个x的第一个元素。以下不变量将一直保持:
超过last的每个元素都大于x,并且之前的每个元素第一个小于或等于(相反的情况)。
注意,不变量没有说明区间[first,last]。在没有进一步了解向量的情况下,极限的唯一有效初始化是向量的第一个=0和最后一个=最后一个位置。这满足条件,因为在最后之后什么都没有,在first之前什么都没有。所以一切都是对的。
由于区间[第一个,最后一个]未知,我们将不得不继续进行,直到它为空,从而更新限制。
int get_first_greater(const std::vector<int>& v, int x)
{
int first = 0, last = int(v.size()) - 1;
while (first <= last)
{
int mid = (first + last) / 2;
if (v[mid] > x)
last = mid - 1;
else
first = mid + 1;
}
return last + 1 == v.size() ? -1 : last + 1;
}
正如您所看到的,我们只需要两个案例,所以代码非常简单。在每次检查时,我们都会更新极限,使其始终保持不变。
当循环结束时,使用不变量,我们知道last+1大于x(如果存在),所以我们只需要检查我们是否仍在向量内。
考虑到这一点,您可以根据需要修改二进制搜索。让我们更改它以查找最后一个小于x的值。我们更改不变量:
第一个之前的每个元素都小于x,并且每个元素在之后最后大于或等于x。
这样,修改代码就非常容易:
int get_last_smaller(const std::vector<int>& v, int x)
{
int first = 0, last = int(v.size()) - 1;
while (first <= last)
{
int mid = (first + last) / 2;
if (v[mid] >= x)
last = mid - 1;
else
first = mid + 1;
}
return first - 1 < 0 ? -1 : first - 1;
}
检查我们是否只更改了运算符(>=而不是>)和返回,使用了与以前相同的参数。
很难写出正确的程序。一旦一个程序被验证是正确的,它就应该很少被修改,更多地被重用。在这一行中,考虑到您使用的是C++而不是C,我建议您尽可能充分地使用std C++库。您正在寻找的两个功能都是在算法中提供给您的。
http://en.cppreference.com/w/cpp/algorithm/lower_boundhttp://en.cppreference.com/w/cpp/algorithm/upper_bound这对你来说很神奇,而且考虑到模板的强大功能,你应该能够通过添加其他实现排序的方法来使用这些方法。
HTH。
要部分回答这个问题,可以考虑实际比较(使用回调函数或类似函数),这取决于要搜索的是比元素大的第一个元素还是更小的第一个元件。然而,在第一个代码块中,您使用
arr[mid] <= val && arr[mid+1] > val
而在第二块中,在第二条件中的索引移位
if (arr[mid] >= val && arr[mid] < val)
省略了,这似乎不一致。
您的搜索例程有一些错误[其中一个完全坏了]。我已经清理了一些,但我是从你的代码开始的。注意:不能保证——现在已经晚了,但这应该给你一个起点。请注意,"lo/hi"是标准命名法(例如,lo是你的开始,hi是你的结束)。此外,请注意,hi/lo设置为mid,而不是mid+1或mid-1
有一些边缘案例需要处理。while循环必须为"<"或"mid+1",它将运行到数组的末尾。
int
binarysearch_larger(const int *arr,int cnt,int val)
// arr -- array to search
// cnt -- number of elements in array
// val -- desired value to be searched for
{
int mid;
int lo;
int hi;
int match;
lo = 0;
hi = cnt - 1;
match = -1;
while (lo < hi) {
mid = (hi + lo) / 2;
if (arr[mid] <= val) && (arr[mid+1] > val)) {
if ((mid + 1) < cnt)
match = mid + 1;
break;
}
if (arr[mid] > val)
hi = mid;
else
lo = mid;
}
return match;
}
int
binarysearch_smaller(const int *arr,int cnt,int val)
// arr -- array to search
// cnt -- number of elements in array
// val -- desired value to be searched for
{
int mid;
int lo;
int hi;
int match;
lo = 0;
hi = cnt - 1;
match = -1;
while (lo < hi) {
mid = (hi + lo) / 2;
if (arr[mid] <= val) && (arr[mid+1] > val)) {
match = mid;
break;
}
if (arr[mid] > val)
hi = mid;
else
lo = mid;
}
// the condition here could be "<=" or "<" as you prefer
if ((match < 0) && (arr[cnt - 1] <= val))
match = cnt - 1;
return match;
}
下面是一个通用算法,它给出了一个排序的元素范围和一个值,它返回一对迭代器,其中第一个迭代器的值是排序范围中第一个比输入值小的元素,第二个迭代机的值是该范围中比输入值大的第一个元素。
若返回的迭代器对指向范围的末尾,则表示输入的范围为空。
我已经尽可能地使它通用,它还处理边缘案例和重复案例。
template<typename BidirectionalIterator>
std::pair<BidirectionalIterator, BidirectionalIterator>
lowhigh(BidirectionalIterator first, BidirectionalIterator last,
typename std::iterator_traits<BidirectionalIterator>::value_type const &val) {
if(first != last) {
auto low = std::lower_bound(first, last, val);
if(low == last) {
--last;
return std::make_pair(last, last);
} else if(low == first) {
if(first != last - 1) {
return std::make_pair(first, std::upper_bound(low, last - 1, val) + 1);
} else {
return std::make_pair(first, first);
}
} else {
auto up = std::upper_bound(low, last, val);
return (up == last)? std::make_pair(low - 1, up - 1) : std::make_pair(low - 1, up);
}
}
return std::make_pair(last, last);
}
现场演示
- Lower_bound不适用于具有 3 个元素的向量的最后一个元素
- 动态分配列表 - 创建一个函数,用于删除所有包含偶数值的元素
- 用于查找数组中最大元素的出现次数的代码,给出分段错误
- 是否有用于元素部分移位的 simd 指令/内在/内置指令?
- C++ 函数,用于查找数组中四个最小最大元素的总和不起作用
- C++用于循环跳过向量的元素?
- Getter 和 Setter 用于类 C++ 中的数组元素
- 为什么 std::swap 不适用于<bool> Clang/Win(英语:Clang/Win)下的矢量元素?
- std::p artition 的问题,用于分离小于枢轴的元素
- Getter 函数,用于在 2d 数组是类的数据成员时检索 2d 数组元素
- 用于查找元素的数据结构
- 继承函数是否适用于 C++ 中的基类元素或派生类元素?
- 如何编写用于查找数组中一系列元素的函数?
- const 数组,用于在数组长度定义中使用其元素或为模板参数提供值
- 用于编织链接列表元素的Runner Technique
- 为什么用于阈值矩阵元素的 Matlab 逻辑索引操作在性能上优于 mex 实现?
- 试图使模板用于C 中结构的元素工作
- 在一个类中向向量添加元素不适用于其他类
- 我用于汇总数组元素的 c++ 代码无法正常工作
- 用于显示矩阵元素的C 函数显示垃圾值