lower_bound和upper_bounder使用的一些细节

lower_bound和upper_bounder使用的一些细节

一、std::lower_bound和std::upper_bound的介绍

这两个函数是标准算法库的调用二分查找的两个相关的查找算法。之所以提到这两个算法函数,是因为在c++98和c++11中这两个函数的使用有了一些细节的不同,需要提醒一下。先看一下二者的原型:

//std::upper_bound
template< class ForwardIt, class T >
ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value );
	(until C++20)
template< class ForwardIt, class T >
constexpr ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value );
	(since C++20)
	(2) 	
template< class ForwardIt, class T, class Compare >
ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp );
	(until C++20)
template< class ForwardIt, class T, class Compare >
constexpr ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp );

template<class _FwdIt,
	class _Ty,
	class _Pr>
	_NODISCARD inline _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last,
		const _Ty& _Val, _Pr _Pred)
	{	// find first element that _Val is before, using _Pred
	_DEBUG_RANGE(_First, _Last);
	auto _UFirst = _Unchecked(_First);
	_Iter_diff_t<_FwdIt> _Count = _STD distance(_UFirst, _Unchecked(_Last));

	while (0 < _Count)
		{	// divide and conquer, find half that contains answer
		_Iter_diff_t<_FwdIt> _Count2 = _Count >> 1; // TRANSITION, VSO#433486
		const auto _UMid = _STD next(_UFirst, _Count2);
		if (_Pred(_Val, *_UMid))
			{
			_Count = _Count2;
			}
		else
			{	// try top half
			_UFirst = _Next_iter(_UMid);
			_Count -= _Count2 + 1;
			}
		}
	return (_Rechecked(_First, _UFirst));
	}

//std::lower_bound
template< class ForwardIt, class T >
ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value );
	(until C++20)
template< class ForwardIt, class T >
constexpr ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value );
	(since C++20)
	(2) 	
template< class ForwardIt, class T, class Compare >
ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp );
	(until C++20)
template< class ForwardIt, class T, class Compare >
constexpr ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp );
	(since C++20)

  template<class _FwdIt,
  	class _Ty,
  	class _Pr>
  	_NODISCARD inline _FwdIt lower_bound(_FwdIt _First, const _FwdIt _Last,
  		const _Ty& _Val, _Pr _Pred)
  	{	// find first element not before _Val, using _Pred
  	_DEBUG_RANGE(_First, _Last);
  	auto _UFirst = _Unchecked(_First);
  	_Iter_diff_t<_FwdIt> _Count = _STD distance(_UFirst, _Unchecked(_Last));

  	while (0 < _Count)
  		{	// divide and conquer, find half that contains answer
  		_Iter_diff_t<_FwdIt> _Count2 = _Count >> 1; // TRANSITION, VSO#433486
  		const auto _UMid = _STD next(_UFirst, _Count2);
  		if (_Pred(*_UMid, _Val))
  			{	// try top half
  			_UFirst = _Next_iter(_UMid);
  			_Count -= _Count2 + 1;
  			}
  		else
  			{
  			_Count = _Count2;
  			}
  		}

  	return (_Rechecked(_First, _UFirst));
  	}

首先需要注意的是看不同的定义的模板函数最后面的声明,有的是到c++20,有的是从c++20才开始支持,不要弄错,特别是在使用时,一定要把握好编译器对c++标准库的支持的程度和范围。

这两个函数有什么作用呢?它们都是在前闭后开的区间内查找一个元素,返回一个查找结果(迭代器指针)。不同之处在于,std::lower_bound返回是一个大于等于查找值的位置而std::upper_bound是返回一个大于查找值的位置。如果所有元素都于小查找元素,则返回指向最后的迭代器(注意,此时其已越界)。

看两个算法函数的实现,用了一种比较技巧的方法实现了二分查找,细节就不解释了,如果觉得不明白,可以把模板函数改写成非模板函数,就看清楚了。

二、例程

为了加深印象,来一个例程看看:

#include <vector>
#include <iostream>
#include <algorithm>

//升序排列,查找等于和不等于的值
void first_type()
{
	int v = 11;//6
	std::vector<int> vec;
	vec.push_back(1);
	vec.push_back(6);
	vec.push_back(9);
	vec.push_back(12);
	vec.push_back(16);
	vec.push_back(19);
	vec.push_back(26);
	vec.push_back(36);

	std::cout<<"find value is :"<<v<<std::endl;

	int low = lower_bound(vec.begin(),vec.end(),v)-vec.begin();
	int upp = upper_bound(vec.begin(),vec.end(),v)-vec.begin();

	std::cout<<"lower_bound is:"<<low<<"  index is:"<<std::endl;
	std::cout<<"upper_bound is:"<<upp<<" index is:"<<std::endl;


	std::cout<<"lower and upper value is:"<<vec[low]<<"-"<<vec[upp]<<std::endl;
}
//升序查找,查找集合中有相同元素,结果相同
void second_type()
{

	int v = 26;
	std::vector<int> vec;
	vec.push_back(116);
	vec.push_back(26);
	vec.push_back(19);
	vec.push_back(102);
	vec.push_back(116);
	vec.push_back(19);
	vec.push_back(26);
	vec.push_back(36);
	vec.push_back(116);
	vec.push_back(19);
	vec.push_back(36);

	for (auto v:vec)
	{
		std::cout<<v<<",";
	}

	std::cout<<""<<std::endl;

	std::sort(vec.begin(),vec.end());

	for (auto v :vec)
	{
		std::cout<<v<<",";
	}
	std::cout<<""<<std::endl;

	std::cout<<"find value is :"<<v<<std::endl;

	int low = lower_bound(vec.begin(),vec.end(),v)-vec.begin();
	int upp = upper_bound(vec.begin(),vec.end(),v)-vec.begin();

	std::cout<<"lower_bound is:"<<low<<"  index is:"<<std::endl;
	std::cout<<"upper_bound is:"<<upp<<" index is:"<<std::endl;

	std::cout<<"lower and upper value is:"<<vec[low]<<"-"<<vec[upp]<<std::endl;
}
//不排序,结果异常
void third_type()
{
	int v = 26;
	std::vector<int> vec;
	vec.push_back(116);
	vec.push_back(26);
	vec.push_back(19);
	vec.push_back(102);
	vec.push_back(116);
	vec.push_back(19);
	vec.push_back(26);
	vec.push_back(36);
	vec.push_back(116);
	vec.push_back(19);
	vec.push_back(36);

	for (auto v:vec)
	{
		std::cout<<v<<",";
	}

	std::cout<<""<<std::endl;
//注释相关排序
//	std::sort(vec.begin(),vec.end());
//
//	for (auto v :vec)
//	{
//		std::cout<<v<<",";
//	}
//	std::cout<<""<<std::endl;

	std::cout<<"find value is :"<<v<<std::endl;

	int low = lower_bound(vec.begin(),vec.end(),v)-vec.begin();
	int upp = upper_bound(vec.begin(),vec.end(),v)-vec.begin();

	std::cout<<"lower_bound is:"<<low<<"  index is:"<<std::endl;
	std::cout<<"upper_bound is:"<<upp<<" index is:"<<std::endl;

	std::cout<<"lower and upper value is:"<<vec[low]<<"-"<<vec[upp]<<std::endl;
}
//降序查找,得到第一值,错误
void four_type()
{
	int v = 26;
	std::vector<int> vec;
	vec.push_back(116);
	vec.push_back(26);
	vec.push_back(19);
	vec.push_back(102);
	vec.push_back(116);
	vec.push_back(19);
	vec.push_back(26);
	vec.push_back(36);
	vec.push_back(116);
	vec.push_back(19);
	vec.push_back(36);

	for (auto v:vec)
	{
		std::cout<<v<<",";
	}

	std::cout<<""<<std::endl;

	std::sort(vec.begin(),vec.end(),std::greater<int>());
	//std::reverse(vec.begin(),vec.end());

	for (auto v :vec)
	{
		std::cout<<v<<",";
	}
	std::cout<<""<<std::endl;

	std::cout<<"find value is :"<<v<<std::endl;

	int low = lower_bound(vec.begin(),vec.end(),v)-vec.begin();
	int upp = upper_bound(vec.begin(),vec.end(),v)-vec.begin();

	std::cout<<"lower_bound is:"<<low<<"  index is:"<<std::endl;
	std::cout<<"upper_bound is:"<<upp<<" index is:"<<std::endl;

	std::cout<<"lower and upper value is:"<<vec[low]<<"-"<<vec[upp]<<std::endl;
}
//验证集合元素均小于的情况
void five_type()
{
	int v = 160;
	std::vector<int> vec;
	vec.push_back(116);
	vec.push_back(26);
	vec.push_back(19);
	vec.push_back(102);
	vec.push_back(116);
	vec.push_back(19);
	vec.push_back(26);
	vec.push_back(36);
	vec.push_back(116);
	vec.push_back(19);
	vec.push_back(36);

	for (auto v:vec)
	{
		std::cout<<v<<",";
	}

	std::cout<<""<<std::endl;

	std::sort(vec.begin(),vec.end());

	for (auto v :vec)
	{
		std::cout<<v<<",";
	}
	std::cout<<""<<std::endl;

	std::cout<<"find value is :"<<v<<std::endl;

	int low = lower_bound(vec.begin(),vec.end(),v)-vec.begin();
	int upp = upper_bound(vec.begin(),vec.end(),v)-vec.begin();

	std::cout<<"lower_bound is:"<<low<<"  size is:"<<vec.size()<<std::endl;
	std::cout<<"upper_bound is:"<<upp<<"  size is:"<<vec.size()<<std::endl;


	std::cout<<"lower and upper value is:"<<vec[low]<<"-"<<vec[upp]<<std::endl;
}
int main()
{
	std::cout<<"first test------------------------------------!"<<std::endl;

	first_type();

	std::cout<<"second test++++++++++++++++++++++++++++++++++++!"<<std::endl;
	second_type();

	std::cout<<"third test====================================!"<<std::endl;
	third_type();

	std::cout<<"four test------------------------------------!"<<std::endl;
	four_type();

	std::cout<<"five test%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!"<<std::endl;
	five_type();

	return 0;
}

上面分成了五种情况进行验证,结果如下:

[fanjinfeng@bc01v test]$ g++ -std=c++11  -o vec test_lowerbound.cpp
[fanjinfeng@bc01v test]$ ./vec
first test------------------------------------!
find value is :11
lower_bound is:3  index is:
upper_bound is:3 index is:
lower and upper value is:12-12
second test++++++++++++++++++++++++++++++++++++!
116,26,19,102,116,19,26,36,116,19,36,
19,19,19,26,26,36,36,102,116,116,116,
find value is :26
lower_bound is:3  index is:
upper_bound is:5 index is:
lower and upper value is:26-36
third test====================================!
116,26,19,102,116,19,26,36,116,19,36,
find value is :26
lower_bound is:6  index is:
upper_bound is:7 index is:
lower and upper value is:26-36
four test------------------------------------!
116,26,19,102,116,19,26,36,116,19,36,
116,116,116,102,36,36,26,26,19,19,19,
find value is :26
lower_bound is:0  index is:
upper_bound is:0 index is:
lower and upper value is:116-116
five test%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
116,26,19,102,116,19,26,36,116,19,36,
19,19,19,26,26,36,36,102,116,116,116,
find value is :160
lower_bound is:11  size is:11
upper_bound is:11  size is:11
lower and upper value is:0-0

为了验证方便,这里的代码没有进行优化,这样更易于观察和修改。

三、总结

通过上面的例程可以看出,在按要求的升序测试中是OK的,可是这里为了突出为什么需要升序也举出了没有排序和降序的例子。不排序肯定是不行,二分搞不定,降序其实是可以自己修改代码来实现的,如果按默认的实现也会出现异常。

其实最需要注意的是当查找的元素的集合中存在着大量的相同的元素时,这两个函数的得到的结果就有比较大的不同了。有一些注意的细节,在c++的帮助文档上有说明,这里提醒一定注意。

同时,在c++11之后,algorithm库和一些容器库的相关的操作也有一些变化,比如在map的插入时,其插入的位置与之前恰好相反,所以在新的插入时,需要将插入数据进行一下反向的处理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值