C++ STL 已序区间的搜索算法binary_search() 附一编程练习题 牛客网编程面试注意事项

牛客网编程面试注意事项:

  1. 视频面试用chrome或者firefox,,如果装了adblock   adguard等记得关闭。不然可能会影响视频和语音!(采坑)
  2. 这里有注意事项和面试题分享一下:https://download.csdn.net/download/xiao__jia__jia/10558921
  3. C/C++编程输入输出尽量用scanf()和printf()。。(据说cin cout 比sancf()和printf()慢20倍!!)(采坑)

文末那题运行时间超时的题的改进:用low_bound()代替循环写的顺序查找(已序表的查找)用scanf()和printf()代替cin cout!

参考资料:[1]http://www.cplusplus.com/reference/algorithm/binary_search/

二分查找

binary_search()

函数功能:

Test if value exists in sorted sequence

Returns true if any element in the range [first,last) is equivalent to val, and false otherwise.

形式1:

template <class ForwardIterator, class T>
  bool binary_search (ForwardIterator first, ForwardIterator last,
                      const T& val);

形式2:

扫描二维码关注公众号,回复: 2776578 查看本文章
template <class ForwardIterator, class T, class Compare>
  bool binary_search (ForwardIterator first, ForwardIterator last,
                      const T& val, Compare comp);

The elements are compared using operator< for the first version, and comp for the second. Two elements, a and b are considered equivalent if (!(a<b) && !(b<a)) or if (!comp(a,b) && !comp(b,a)).

The elements in the range shall already be sorted according to this same criterion (operator< or comp), or at least partitioned with respect to val.

效率
The function optimizes the number of comparisons performed by comparing non-consecutive elements of the sorted range, which is specially efficient for random-access iterators.

The behavior of this function template is equivalent to:

template <class ForwardIterator, class T>
  bool binary_search (ForwardIterator first, ForwardIterator last, const T& val)
{
  first = std::lower_bound(first,last,val);
  return (first!=last && !(val<*first));
}

VS2013在头文件<algoritm>中:的模板函数

// TEMPLATE FUNCTION binary_search WITH PRED
template<class _FwdIt,
	class _Ty,
	class _Pr> inline
	bool binary_search(_FwdIt _First, _FwdIt _Last,
		const _Ty& _Val, _Pr _Pred)
	{	// test if _Val equivalent to some element, using _Pred
	_First = _STD lower_bound(_First, _Last, _Val, _Pred);
	return (_First != _Last && !_Pred(_Val, *_First));
	}

		// TEMPLATE FUNCTION binary_search
template<class _FwdIt,
	class _Ty> inline
	bool binary_search(_FwdIt _First, _FwdIt _Last, const _Ty& _Val)
	{	// test if _Val equivalent to some element, using operator<
	return (_STD binary_search(_First, _Last, _Val, less<>()));
	}

如果要找到待搜索元素在序列中的具体位置,应该使用:

lower_bound()、up_bound()、equal_range()

参考资料[2]http://www.cplusplus.com/reference/algorithm/lower_bound/

2.lower_bound

function template

<algorithm>

std::lower_bound

形式1:

template <class ForwardIterator, class T>
  ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,
                               const T& val);

形式2:

template <class ForwardIterator, class T, class Compare>
  ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,
                               const T& val, Compare comp);

函数功能:

Return iterator to lower bound

Returns an iterator pointing to the first element in the range [first,last) which does not compare less than val.

返回指向范围[first,last)中的满足条件(element>=val)的第一个元素的迭代器,该元素element的值不比val小!。

即返回指向区间中第一个大于等于val的元素的迭代器!

The elements are compared using operator< for the first version, and comp for the second. The elements in the range shall already be sorted according to this same criterion (operator< or comp), or at least partitioned with respect to val.

关注下效率问题:(比顺序查询要快,毕竟序列已有序)
The function optimizes the number of comparisons performed by comparing non-consecutive elements of the sorted range, which is specially efficient for random-access iterators.

Unlike upper_bound, the value pointed by the iterator returned by this function may also be equivalent to val, and not only greater.


The behavior of this function template is equivalent to:

template <class ForwardIterator, class T>
  ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val)
{
  ForwardIterator it;
  iterator_traits<ForwardIterator>::difference_type count, step;
  count = distance(first,last);
  while (count>0)
  {
    it = first; step=count/2; advance (it,step);
    if (*it<val) {                 // or: if (comp(*it,val)), for version (2)
      first=++it;
      count-=step+1;
    }
    else count=step;
  }
  return first;
}

function template

<algorithm>

std::upper_bound

参考资料[3]http://www.cplusplus.com/reference/algorithm/upper_bound/

形式1:

template <class ForwardIterator, class T>
  ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last,
                               const T& val);

形式2:

template <class ForwardIterator, class T, class Compare>
  ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last,
                               const T& val, Compare comp);

Return iterator to upper bound

Returns an iterator pointing to the first element in the range [first,last) which compares greater than val.

返回第一个大于val的元素的下标。

The elements are compared using operator< for the first version, and comp for the second. The elements in the range shall already be sorted according to this same criterion (operator< or comp), or at least partitioned with respect to val.

The function optimizes the number of comparisons performed by comparing non-consecutive elements of the sorted range, which is specially efficient for random-access iterators.

Unlike lower_bound, the value pointed by the iterator returned by this function cannot be equivalent to val, only greater.

The behavior of this function template is equivalent to:

template <class ForwardIterator, class T>
  ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val)
{
  ForwardIterator it;
  iterator_traits<ForwardIterator>::difference_type count, step;
  count = std::distance(first,last);
  while (count>0)
  {
    it = first; step=count/2; std::advance (it,step);
    if (!(val<*it))                 // or: if (!comp(val,*it)), for version (2)
      { first=++it; count-=step+1;  }
    else count=step;
  }
  return first;
}

编程小习题:

有n堆苹果,每堆ai个,从左到右边给每一个苹果编号,且排好序。

输入第m个苹果,问该苹果是属于第几堆?

思路:

测试用例:

设有5堆

每堆苹果个数为{2 7 3 4 9}

那么再创建一个部分个数组:{2,9,12,16,25}

val值为第几个苹果,即苹果的编号,从1到n,如第3个苹果一个在第2堆里,第10个苹果在第3堆!

即在部分和数组里查找第一个element>=val的元素的下标。然后+1转换成第及堆(堆号从1计算起)

最简单的办法就是顺序查找,单在网站上只通过了30%的测试用例,原因是运行时间超时!

顺序查找效率太低!

使用STL中的low_bound()函数,返回指向区间中第一个大于等于val值的迭代器,在转换成下标序号->+1得到堆序号!

vs中要加头文件:#include"stdafx.h"

/*了解下"stdafx.h"到底是什么!
stdafx的英文全称为:Standard Application Framework Extensions(标准应用程序框架的扩展)
所谓头文件预编译,就是把一个工程(Project)中使用的一些MFC标准头文件(如Windows.H、Afxwin.H)预先编译,
以后该工程编译时,不再编译这部分头文件,仅仅使用预编译的结果。这样可以加快编译速度,节省时间。*/

#include "stdafx.h"/*在网站上提交代码的时候去掉这行!*/


#include<iostream>
#include<vector>
#include<algorithm>
#include<numeric>
#include<algorithm>
using namespace std;

int main()
{
	int n;

	/*据说cin、cout 比 scanf()和printf()慢20倍!!
	吓得我赶快把输入输出换成scanf()和printf()!*/

	//cin >> n;
	scanf("%d", &n);/*注意一下scanf()是要取地址&的!*/

	/*用这些C的函数在vs下会报错:
	错误	1	error C4996: 'scanf': This function or variable may be unsafe. 
	Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. 
	See online help for details.	
	
	打开项目属性->配置属性->C/C++->预处理器定义里加入_CRT_SECURE_NO_WARNINGS
	*/

	vector<int> apples(n,0);
	vector<int> applesSum(n,0);

	//for (int i = 0; i < n; i++)
	//{
	//	cin >> apples[i];
	//}
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &apples[i]);
	}

	applesSum[0] = apples[0];
	for (int i = 1; i < n; i++)
	{
		applesSum[i] = apples[i] + applesSum[i - 1];
	}

	int m;
	//cin >> m;
	scanf("%d", &m);
	vector<int> querys(m, 0);
	int queryNth;
	//for (int i = 0; i < m; i++)
	//{
	//	cin >> querys[i];
	//}
	for (int i = 0; i < m; i++)
	{
		scanf("%d", &querys[i]);
	}

	////int qi;
	//for (int i = 0; i < m; i++)
	//{
	//	//qi = querys[i];
	//	int ofTh=0;
	//	for (int j = 0; j < n; j++)
	//	{
	//		if (querys[i] <= applesSum[j])
	//		{
	//			ofTh = j+1;
	//			break;
	//		}
	//	}
	//	cout << ofTh<<endl;
	//}



	/*这应该算是条件查找,在升序向量中找到第一个key<=该关键字的数,并返回其下标!!*/
	/*使用:low_bound()和up_bound()
	low_bound()返回第一个大于等于value的元素的位置。

	template<class _FwdIt,
	class _Ty> inline
	_FwdIt lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val)
	{	// find first element not before _Val, using operator<
	return (_STD lower_bound(_First, _Last, _Val, less<>()));
	}

	*/
	vector<int>::iterator iter;
	for (int i = 0; i < m; i++)
	{
		/*lower_bound()是模板函数!*/
		iter = lower_bound<vector<int>::iterator,int>(applesSum.begin(), applesSum.end(), querys[i]);
		cout << iter - applesSum.begin()+1 << endl;
	}

	/*不要用顺序查找!既然是部分和是递增的有序序列!,用二分查找??*/
	/*find_if 底层是怎么实现了?时间复杂度低于0(n)吗?*/
	//for (int i = 0; i < m; i++)
	//{
	//	find_if(applesSum.begin(), applesSum.end(), lessEqual(,querys[i]));
	//}


	system("pause");/*在网站上提交代码的时候去掉这行!*/
	return 0;
}


/*
5
2 7 3 4 9
3
3 11 18
2
3
5
请按任意键继续. . .
即第三个苹果在第2堆,第11个苹果在第3堆,第18个苹果在第5堆

*/

注释:对于已经有序的序列,查找用二分查找!

所以使用low_bound()的效率肯定要比顺序查找高!这样才能满足运行时间的要求!

C++ STL 搜索算法 二分查找 low_bound() up_bound() 编程小练习

对有序序列的二分查找:


/*有序表vector的二分查找!,前提是vector的元素有序!*/
int Search_Binary(vector<int> vec, int key)
{
	int low = 0;
	int high = vec.size() - 1;
	int mid;
	while (low <= high)
	{
		mid = (low + high) / 2;
		if (vec[mid] == key)
		{
			return mid;
		}
		else if (vec[mid] < key)
		{
			high = mid - 1;
		}
		else
		{
			low = mid + 1;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_37357063/article/details/81590665
今日推荐