【C++】剖析lower_bound upper_bound

【C++】剖析lower_bound & upper_bound

接口

先看看接口

std::lower_bound

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

std::upper_bound

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

实现

类似的底层实现

参考:https://cplusplus.com/reference/algorithm/lower_bound/,https://cplusplus.com/reference/algorithm/upper_bound/

std::lower_bound

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;
}

std::upper_bound

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;
}

使用

这两个结果对于升序还是降序、传入查找的参数类型是否和数组类型一致都会影响具体的使用

升序数组

根据下面的源码,对于升序数组,内置类型或者重载了operator<自定义数据类型的不用多数了,直接用default 1即可。因为底层也是使用operator<

// lower_bound-------------------------------------
_EXPORT_STD template <class _FwdIt, class _Ty, class _Pr>
_NODISCARD _CONSTEXPR20 _FwdIt lower_bound(_FwdIt _First, const _FwdIt _Last, const _Ty& _Val, _Pr _Pred) {
    // find first element not before _Val
    _STD _Adl_verify_range(_First, _Last);
    auto _UFirst                = _STD _Get_unwrapped(_First);
    _Iter_diff_t<_FwdIt> _Count = _STD distance(_UFirst, _STD _Get_unwrapped(_Last));

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

    _STD _Seek_wrapped(_First, _UFirst);
    return _First;
}

_EXPORT_STD template <class _FwdIt, class _Ty>
_NODISCARD _CONSTEXPR20 _FwdIt lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) {
    // find first element not before _Val
    return _STD lower_bound(_First, _Last, _Val, less<>{});// ⭐
}

// upper_bound---------------------------------------

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

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

    _STD _Seek_wrapped(_First, _UFirst);
    return _First;
}

_EXPORT_STD template <class _FwdIt, class _Ty>
_NODISCARD _CONSTEXPR20 _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) {
    // find first element that _Val is before
    return _STD upper_bound(_First, _Last, _Val, less<>{});// ⭐
}

降序数组

但如果是降序数组就需要传入比较参数了。例如

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

struct Person {
    std::string name;
    int age;
};

// 自定义比较函数:根据 age 降序排列
bool compareByAgeDesc(const Person& p1, const Person& p2) {
    return p1.age > p2.age;  // 按年龄降序排列
}

int main() {
    // 创建一个 Person 类型的 vector,并按年龄降序排序
    std::vector<Person> people = {
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35},
        {"David", 40}
    };

    // 按年龄降序排列
    std::sort(people.begin(), people.end(), compareByAgeDesc);

    // 查找年龄大于或等于 30 的第一个 Person
    Person p = {"", 30};  // 目标年龄是 30
    auto it_lower = std::lower_bound(people.begin(), people.end(), p, [](const Person& p1, const Person& p2) {
        return p1.age > p2.age;  // 按降序比较
    });

    if (it_lower != people.end()) {
        std::cout << "Lower bound (first person >= 30): " << it_lower->name << ", Age: " << it_lower->age << std::endl;
    }

    // 查找年龄大于 30 的第一个 Person
    p.age = 30;  // 查找大于 30 的
    auto it_upper = std::upper_bound(people.begin(), people.end(), p, [](const Person& p1, const Person& p2) {
        return p1.age > p2.age;  // 按降序比较
    });

    if (it_upper != people.end()) {
        std::cout << "Upper bound (first person > 30): " << it_upper->name << ", Age: " << it_upper->age << std::endl;
    }
    return 0;
}

非同类型元素查找

上面都是传入查找的参数类型和数组元素类型一致,但如果不一致呢,如下,注意两者lamda的形参顺序和比较方式。这种不一致其实都是为了符合底层实现。

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

struct Person {
    std::string name;
    int age;
};

// 自定义比较函数:根据 age 降序排列
bool compareByAgeDesc(const Person& p1, const Person& p2) {
    return p1.age > p2.age;  // 按年龄降序排列
}

int main() {
    // 创建一个 Person 类型的 vector,并按年龄降序排序
    std::vector<Person> people = {
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35},
        {"David", 40}
    };

    // 按年龄降序排列
    std::sort(people.begin(), people.end(), compareByAgeDesc);

    // 查找年龄大于或等于 30 的第一个 Person
    int age = 30;  // 目标年龄是 30
    auto it_lower = std::lower_bound(people.begin(), people.end(), age, [](const Person& p, int age) {
        return p.age > age;  // ⭐按降序比较,查找第一个 age >= 30 的 Person
    });

    if (it_lower != people.end()) {
        std::cout << "Lower bound (first person >= 30): " << it_lower->name << ", Age: " << it_lower->age << std::endl;
    }

    // 查找年龄大于 30 的第一个 Person
    auto it_upper = std::upper_bound(people.begin(), people.end(), age, [](int age, const Person& p) {
        return age > p.age;  // ⭐按降序比较,查找第一个 age > 30 的 Person
    });

    if (it_upper != people.end()) {
        std::cout << "Upper bound (first person > 30): " << it_upper->name << ", Age: " << it_upper->age << std::endl;
    }

    return 0;
}

一个是const Person& p, int age; return p.age > age;,对应if (comp(*it,val)),一个是int age, const Person& p; return age > p.age;对应if (!comp(val,*it)),

所以一切使用上的细节都来源于底层实现!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/943859.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【开源】一款基于SpringBoot的智慧小区物业管理系统

一、下载项目文件 项目文件源码链接&#xff1a;https://pan.quark.cn/s/3998d958e182如出现网盘空间不够存的情况&#xff01;&#xff01;&#xff01;解决办法是先用夸克手机app注册&#xff0c;然后保存上方链接&#xff0c;就可以得到1TB空间了&#xff01;&#xff01;&…

Linux编程(清华大学出版社2019年1月第1版)第7章-进程间通信-课后作业

7.1 输出: 4:ABCD 4:EFGH7.2 输出: numbers3 10 20 30 7.3 #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <limits.h> #include <fcntl.h> #include <sys/types.h> #include <stdint.h> #includ…

线性代数行列式

目录 二阶与三阶行列式 二元线性方程组与二阶行列式 三阶行列式 全排列和对换 排列及其逆序数 对换 n阶行列式的定义 行列式的性质 二阶与三阶行列式 二元线性方程组与二阶行列式 若是采用消元法解x1、x2的话则得到以下式子 有二阶行列式的规律可得&#xff1a;分…

canvas之进度条

canvas之进度条 效果&#xff1a; 封装的组件 <template><div class"circle" :style"{ width: props.radius px, height: props.radius px }"><div class"circle-bg" :style"{ width: props.radius - 5 px, height: pr…

再生核希尔伯特空间(RKHS)上的分位回归

1. 基本定义和理论基础 1.1 再生核希尔伯特空间(RKHS) 给定一个非空集合 X \mathcal{X} X&#xff0c;一个希尔伯特空间 H \mathcal{H} H 称为再生核希尔伯特空间&#xff0c;如果存在一个函数 K : X X → R K: \mathcal{X} \times \mathcal{X} \rightarrow \mathbb{R} K…

Nature+Science=ONNs(光学神经网络)

2024深度学习发论文&模型涨点之——光学神经网络 光学神经网络&#xff08;Optical Neural Networks, ONNs&#xff09;是一种利用光学器件&#xff08;如激光、光学调制器、滤波器、探测器等&#xff09;来模拟和实现神经网络推理功能的计算模型。这种网络通过利用光信号的…

武泳樽携手AI AD Manager荣获红点奖,智能广告管理系统备受瞩目

近日,由著名设计师武泳樽主导设计的AI AD Manager在2024年红点奖评选中荣获大奖,这一殊荣不仅彰显了他在创新设计领域的卓越实力,更巩固了AI AD Manager作为智能广告技术标杆的地位。凭借独特的用户体验设计、尖端的AI驱动功能和出色的技术融合,AI AD Manager在激烈的国际竞争中…

OCR实践-问卷表格统计

前言 书接上文 OCR实践—PaddleOCROCR实践-Table-Transformer 本项目代码已开源 放在 Github上&#xff0c;欢迎参考使用&#xff0c;Star https://github.com/caibucai22/TableAnalysisTool 主要功能说明&#xff1a;对手动拍照的问卷图片进行统计分数&#xff08;对应分数…

flask后端开发(2):URL与视图

目录 URL定义request获取请求参数 gitcode地址&#xff1a; https://gitcode.com/qq_43920838/flask_project.git URL定义 from flask import FlaskappFlask(__name__)app.route(/) def hello_world():return Hello World!app.route(/profile) def profile():return 我是个人…

基于Sentinel的服务保护方案的三种方式(请求限流、线程隔离、服务熔断)超详细讲解

目录 1、三种方式介绍 1.1请求限流 1.2 线程隔离方案 1.3 服务熔断 2、基于sentinel实现 2.1 启动sentinel 2.2 基于springboot整合sentinel 2.2.1请求限流 2.2.2请求隔离 2.2.2.1 OpenFeign整合Sentinel 2.2.3 服务熔断 2.2.3.1 编写降级代码 2.2.3.2 服务熔断 1、…

小程序基础 —— 02 微信小程序账号注册

微信小程序账号注册 小程序开发与网页开发不一样&#xff0c;在开始微信小程序开发之前&#xff0c;需要访问微信公众平台&#xff0c;注册一个微信小程序账号。 有了小程序的账号以后&#xff0c;才可以开发和管理小程序&#xff0c;后续需要通过该账号进行开发信息的设置、…

箭头函数与普通函数的区别

箭头函数&#xff08;Arrow Functions&#xff09;是ES6&#xff08;ECMAScript 2015&#xff09;引入的一种新的函数定义方式&#xff0c;它提供了更简洁的语法和一些与传统函数表达式不同的行为。 以下是箭头函数与普通函数的主要区别&#xff1a; 语法上的简化&#xff1a; …

uniapp实现APP、小程序与webview页面间通讯

需求&#xff1a; 1、需要在Uniapp开发的APP或小程序页面嵌入一个H5网页&#xff0c;需要拿到H5给APP传递的数据。 2、并且这个H5是使用vuevant开发的。&#xff08;其实跟使用uniapp开发H5一样&#xff09; 实现步骤&#xff1a; 1、首先需要兼容多端和App端&#xff0c;因…

iPhone 17 :史诗级大改,120Hz 全面普及

资深果粉应该都听过一个说法&#xff1a;“iPhone 买单不买双”。这个“规律”似乎在iPhone 16上也得到了印证。 近段时间&#xff0c;各方消息都在指明一点&#xff1a;iPhone 16 只是大餐前的小菜&#xff0c;iPhone 17才是真正带来革命性提升的一代神机。下一代 iPhone 17&…

逆袭之路(11)——python网络爬虫:原理、应用、风险与应对策略

困厄铸剑心&#xff0c;逆袭展锋芒。 寒苦凝壮志&#xff0c;腾跃绘华章。 我要逆袭。 目录 一、引言 二、网络爬虫的基本原理 &#xff08;一&#xff09;网络请求与响应 &#xff08;二&#xff09;网页解析 &#xff08;三&#xff09;爬行策略 三、网络爬虫的应用领…

关系数据库

一些关系数据模型的常见概念->数据库概论-CSDN博客 目录 1、关系数据结构 1.1 笛卡尔积 1.2 关系的定义 1.3 关系的性质 2、关系代数 2.1 传统的集合运算 1. 并(union) 2. 交(intersection) 3. 差(difference) 4. 广义笛卡尔积(extended cartesian product) 2.2…

Unity中实现人物残影效果

今天火柴人联盟3公测了&#xff0c;看到一个残影的效果&#xff0c;很有意思&#xff0c;上网查询了一下实现方式&#xff0c; 实现思路&#xff1a; 将角色的网格复制出来&#xff0c;然后放置到新建的物体的MeshFilter组件上&#xff0c;每隔几十毫秒在玩家的位置生成一个&a…

计算机网络习题(第1章 概论 第2章 数据通信基础)

第1章 概论 1、计算机网络 2、互联网 3、计算机网络体系结构 分层模型 OSI/RM 7层模型 TCP/IP 5层模型 协议、PDU、SDU、SAP等术语 数据封装&#xff08;计算&#xff09; 第2章 数据通信基础 1、数据通信系统组成 2、主要性能指标 数据传输速率 码元速率 时延 3…

【连续学习之随机初始化算法 】2024Nature期刊论文Loss of plasticity in deep continual learning

1 介绍 年份&#xff1a;2024 期刊&#xff1a;Nature Dohare S, Hernandez-Garcia J F, Lan Q, et al. Loss of plasticity in deep continual learning[J]. Nature, 2024, 632(8026): 768-774. 本文提出的算法是“持续反向传播”&#xff08;continual backpropagation&a…

Android Studio | 连接手机设备后,启动App时出现:Waiting For DebuggerApplication (App名)...

在这种情况下&#xff0c;打开目录文件&#xff0c;出现 Is:/storage/emulated/: Permission denied 问题分析&#xff1a; 以上两种情况表明应用程序试图访问Android设备的存储空间中的/storage/emulated/目录&#xff0c;但是没有足够的权限去执行这个操作。 解决办法&…