upper_bound自定义函数可能涉及的错误

由于不会写二分查找俺就找到了一个C++的函数:
upper_bound函数,emm,这个函数完美的解决了我对于二分查找的恐惧,是的我还是不会写二分查找,(主要是对查找失败的处理
但是今天读到了一篇博客,总结的很好:
关于upper_bound和lower_bound的总结
其中有这样的两条结论:
(1).upper_bound返回的就是[begin, end)区间中第一个满足cmp(value, element)为true的数。
(2).lower_bound返回的是[begin, end)区间中第一个使cmp(element, value)为false的数。
嗯…我确信他说的是真的,于是我就浅浅的试验了一下发现还挺对的,于是我发现了一个必胜法门,每次把我想要的查找结果放到cmp函数不就行了嘛!
于是我兴高采烈的点开洛谷:
二分查找确信
本蒟蒻就飞速的 写了个代码
WA无疑,甚至没交(甚至没过样例
好吧,答案都是-1,没找到被,我就开始了我的调试之路,但是发现和我没啥关系,我直接用的是upper_bound函数。如下:
现有数组:

1 3 3 3 5 7 9 11 13 15 15

我要找的那个数是3,然后我就这样用了upper_bound函数:

vector<int>::iterator it = upper_bound(yh.begin(), yh.end(), 5, [](int value, int element)->bool {
		return element==value ; 
	});

按照结论,找到的一定是第一个3呀!
结果:
在这里插入图片描述乐,我当时懵了一下,后来一想也对,二分查找里面也没有用那个等号的呀!,于是我把这个lambda函数改了一下:

vector<int>::iterator it = upper_bound(yh.begin(), yh.end(), 5, [](int value, int element)->bool {
		return element<=value ; 
	});

那他返回的一定是第一个小于等于5的值呀!,要注意这里面参数value就是5
结果:
在这里插入图片描述
我又乐了,找不到?这upper_bound函数多少是有点大病了;
然而应该注意在调用别人的二分函数,要从二分的本质出发去学习利用,没有绝对的窍门hh
好吧,我又开始上网搜,于是找到了这个博客,突然明白了什么(确信
另一篇博客
里面引用了一段代码:

/**
 *  以下程序来自:bits/stl_algobase.h
 */

template<typename _ForwardIterator, typename _Tp, typename _Compare>
_ForwardIterator
__upper_bound(_ForwardIterator __first, _ForwardIterator __last,
              const _Tp &__val, _Compare __comp) {
    typedef typename iterator_traits<_ForwardIterator>::difference_type
            _DistanceType;

    _DistanceType __len = std::distance(__first, __last);

    /**
     * 下面使用二分查找算法来实现
     * __len 右指针
     * __first 左指针
     * __middle 中间值
     */
    while (__len > 0) {
        
        _DistanceType __half = __len >> 1; // __len / 2 操作,位移操作更快
        _ForwardIterator __middle = __first;
        std::advance(__middle, __half);
        if (__comp(__val, __middle))
            __len = __half;
        else {
            __first = __middle;
            ++__first;
            __len = __len - __half - 1;
        }
    }
    return __first;
}

让我们重点来看下面这一段:

 while (__len > 0) {
        
        _DistanceType __half = __len >> 1; // __len / 2 操作,位移操作更快
        _ForwardIterator __middle = __first;
        std::advance(__middle, __half);
        if (__comp(__val, __middle))
            __len = __half;
        else {
            __first = __middle;
            ++__first;
            __len = __len - __half - 1;
        }
    }
    return __first;
}

的这两行:

 if (__comp(__val, __middle))
            __len = __half;

这个comp就是我们的自定义函数,如果满足这个条件应该让last指针向前移,否则的话应该让first指针向后移动,我们再来看我们前面写的两个沙雕lambda函数

	return element<=value ; 
	return element==value ; 

我们注意到:

1 3 3 3 5 7 9 11 13 15 15

数组的中间位置元素是7对于上述的两个函数comp值都是false,first指针向后移动再也不可能找到5;emm有没有一种豁然开朗的感觉hh
综上所述,我们把这个lambda表达式改成element>=value,7>=5last指针肯定向前移动啊!
在这里插入图片描述
嗯额,成功辽!
后记:改错的过程中包括但不限于把形参名给改了,还需要注意的是upper_bound里面第一个值是value,lower_bound里面第二个值是value
最后的总结:
如果comp就向前找
意思就是对于升序数组,如果找到的数比key大就向前找,所以写element>=value
如果是降序数组,找到的数比key小就向前找
最后:
在这里插入图片描述

// ConsoleApplication11.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include<bits/stdc++.h>
using namespace std;
const int length = 1e6 + 5;
vector<int>nums;
//upper_bound是返回第一个满足
//lower_bound是返回第一个不满足
int main()
{
	int n,m;
	scanf_s("%d%d", &n, &m);
	for (int i = 0; i < n; i++)
	{
		int a;
		scanf_s("%d", &a);
		nums.push_back(a);
	}

	for (int i = 0; i < m; i++)
	{
		int a;
		scanf_s("%d", &a);
		vector<int>::iterator it = upper_bound(nums.begin(), nums.end(), a, [](int value, int m)->bool {return m >= value; });
		if (it == nums.end()||*it!=a)
			printf("-1 ");
		else
			printf("%d ", it - nums.begin() + 1);
	}
//	scanf_s("%d", &n);

}



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值