STL算法之其它算法_中

目录

lower_bound(应用于有序区间)

upper_bound(应用于有序区间)

binary_search(应用于有序区间)

next_permutation

prev_permutation


lower_bound(应用于有序区间)

        这是二分查找(binary search)的一种版本,试图在已排序的[first,last)中寻找元素value。如果[first,last)具有与value相等的元素(s),便返回一个迭代器,指向其中第一个元素。如果没有这样的元素存在,便返回“假设这样的元素存在时应该出现的位置”。也就是说,它会返回一个迭代器,指向第一个“不小于value”的元素。如果value大于[first,last)内的任何一个元素,则返回last。以稍许不同的观点来看lower_bound,其返回值是“不破坏排序状态的原则下,可插入value的第一个位置”。如下图所示

        这个算法有两个版本,版本一采用operator<进行比较,版本二采用仿函数comp。更正式地说,版本一返回[first,last)中最远的迭代器i,是的[first,i)中的每个迭代器j都满足*j < value。版本二,满足上述迭代区间每个迭代器j,满足“comp(*j, value)为真”。

//版本一
template <class ForwardIterator, class T>
inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value) {
    return __lower_bound(first, last, value, distance_type(first), iterator_category(first));
}

//版本二
template <class ForwardIterator, class T, class Compare>
inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare comp) {
    return __lower_bound(first, last, value, comp, distance_type(first), iterator_category(first));
}

        下面是版本一的两个辅助函数。

// 版本一的forward_iterator版本
template <class ForwardIterator, class T, class Distance>
ForwardIterator __lower_bound(ForwardIterator first, ForwardIterator last, const T& value, Distance*, forward_iterator_tag) {
    Distance len = 0;
    distance(first, last, len);
    Distance half;
    ForwardIterator middle;
    
    while(len > 0) {
        half = len >> 1;
        middle = first;
        advance(middle, half);
        if (*middle < value) {
            first = middle;
            ++first;
            len = len - half - 1;
        }
        else len = half;
    }
    return first;
}

// 版本一的random_access_iterator版本
template <class RandomAccessIterator, class T, class Distance>
ForwardIterator __lower_bound(RandomAccessIterator first, RandomAccessIterator last, const T& value, Distance*, random_access_iterator_tag) {
    Distance len = 0;
    distance(first, last, len);
    Distance half;
    RandomAccessIterator middle;
    
    while(len > 0) {
        half = len >> 1;
        middle = first + half;
        if (*middle < value) {
            first = middle + 1;
            len = len - half - 1;
        }
        else len = half;
    }
    return first;
}

对于版本二的两个辅助函数,只需将*middle < value,修改成comp(*middle, value)即可,此处不在赘述。

upper_bound(应用于有序区间)

        算法upper_bound是二分查找(binary search)法的一个版本。它试图在已排序的[first,last)中寻找value。更明确地说,它会返回“不在破坏顺序的情况下,可插入value的最后一个合适位置”。(lower_bound(应用于有序区间)中有图说明)

        由于STL规范“区间圈定”时的起头和结尾并不对称,前开后必,所以upper_bound与lower_bound返回值意义不同。如果你查找某值,而它的确出现在区间之内,则lower_bound返回的是一个指向该元素的迭代器。而uppder_bound不这么做。因为upper_bound所返回的是在不破坏排序状态的情况下,value可被插入的“最后一个”合适位置。如果value存在,那么它返回的迭代器将指向value的下一个位置,而非指向value本身。

        upper_bound有两个版本,版本一采用operator<进行比较,版本二采用仿函数comp。更正式地说,版本一返回[first,last)区间内最远的迭代i,使得[first,i)内的每个迭代器j都满足“value <*j不为真”。版本二是上述区间内的每个迭代器j都满足“comp(value, *j)不为真”。

//版本一
template <class ForwardIterator, class T>
inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& value) {
    return __upper_bound(first, last, value, distance_type(first), iterator_category(first));
}

//版本二
template <class ForwardIterator, class T, class Compare>
inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& value, Compare comp) {
    return __upper_bound(first, last, value, comp, distance_type(first), iterator_category(first));
}

下面是两个辅助函数

// 版本一的forward_iterator版本
template <class ForwardIterator, class T, class Distance>
ForwardIterator __upper_bound(ForwardIterator first, ForwardIterator last, const T& value, Distance*, forward_iterator_tag) {
    Distance len = 0;
    distance(first, last, len);
    Distance half;
    ForwardIterator middle;
    
    while(len > 0) {
        half = len >> 1;
        middle = first;
        advance(middle, half);
        if (value < *middle)
            len = half;
        else  {
            first = middle;
            ++first;
            len = len - half - 1;
        }
    }
    return first;
}

// 版本一的random_access_iterator版本
template <class RandomAccessIterator, class T, class Distance>
ForwardIterator __upper_bound(RandomAccessIterator first, RandomAccessIterator last, const T& value, Distance*, random_access_iterator_tag) {
    Distance len = 0;
    distance(first, last, len);
    Distance half;
    RandomAccessIterator middle;
    
    while(len > 0) {
        half = len >> 1;
        middle = first + half;
        if (value < *middle) 
            len = half;
        else {
            first = middle + 1;
            len = len - half - 1;
        }
    }
    return first;
}

对于版本二的两个辅助函数,只需将value < *middle,修改成comp(value, *middle)即可,此处不在赘述。

binary_search(应用于有序区间)

        算法binary_search是一种二分查找法,试图在已排序的[first, last)中寻找元素value。如果[first,last)内有等同于value的元素,便返回true,否则返回false。

        返回单纯的bool或许不能满足需求,前面所介绍的lower_bound,upper_bound能提供额外信息。事实上binary_search便是利用lower_bound先找出迭代器,而后对迭代器进行解引用并于value进行比较,判断值是否存在。

        binary_search的第一个版本采用operator<进行比较,第二版本采用仿函数comp进行比较。

        正式地说,当且仅当[first,last)中存在一个迭代器i是的*i<value和value<*i皆不为真,则第一个版本返回true。第二个版本则是上述迭代器i,满足comp(*i, value)和comp(value,*i)皆不为真,则第二版本返回true。

//版本一
template <class ForwardIterator, class T>
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value) {
    ForwardIterator I = lower_bound(first, last, value);
    return I != last && !(value < *I);
}

//版本二
template <class ForwardIterator, class T, class Compare>
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp) {
    ForwardIterator I = lower_bound(first, last, value, comp);
    return I != last && !comp(value, *I);
}

next_permutation

        STL提供了两个用来计算排列组合关系的算法,分别是next_permutation和pre_permutation.首先我们必须了解什么是“下一个”排列组合,什么事“前一个”排列组合。考虑三个字符所组成的序列{a,b,c}。这个序列有六个可能得排列组合:abc,acb,bac,cab,cba。这些排列组合根据less-than操作符做字典顺序的排序。也就是,abc名列第一,因为每一个元素都小于其后的元素。acb是次一个排列组合,因为它是固定了a(序列内最小元素)之后所做的新组合。同样的道理,那些固定b而做的排列组合,在次序上将先于那些固定c而做的排列组合。以bac和bca为例。bac在bca之前,因为序列ac小于ca。面对bca,我们可以说前一个排列组合是bac。而其后一个排列组合是cab。序列abc没有前一个排列组合,cba没有后一个排列组合。

        next_permutation()会取得[first,last)所标示之序列的下一个排列组合。如果没哟下一个排列组合,便返回false;否则返回true。

        这个算法有两个版本。版本一使用元素型别所提供的less-than操作符来决定下一个排列组合,版本二则是以仿函数comp来决定。

        稍后将出现的实现,简述如下,符号如下图所示:

        首先,从尾端往前寻找两个相邻的元素,令第一个元素为*i,第二个元素为*ii,且满足*i<*ii.找到这样一组相邻元素后,再从最尾端开始往前检验,找出第一个大于*i的元素,令为*j,将i,j元素对调,再将II之后的所有元素颠倒排序。此即所求值下一个排列组合。

        举个实例,假设手上有序列{0,1,2,3,4},下图便是套用上述演算法则,一步一步获得“下一个”排列组合。图中只框出那符合“第一元素为I,第二元素为*ii,且满足*i<*ii”的相邻元素。

以下便是版本一的实现细节。

template <class BidirectionalIterator>
bool next_permutation(BidirectionalIterator first, BidirectionalIterator last) {
    if (first == last) return false;
    BidirectionalIterator I = first;
    ++I;
    if (I = last) return false;
    I = last;
    --I;
    for (;;) {
        BidirectionalIterator II = I;
        --I;
        if (*I < *II) {
            BidirectionalIterator J = last;
            while(!(*I < *--J);
            iter_swap(I,J);
            reverse(II, last);
            return true;
        }
        if (I == first) {            // 进行到了最前面都未找到符合条件的元素
            reverse(first, last);    // 全部重排,重新再来一遍?
            return false;
        }
    }
}

版本二只是将operator<用comp替换,此处不在罗列代码。

prev_permutation

        所谓“前一个”排列组合,其意义已在上一节阐述。实际做法简述如下,从最尾端开始往前寻找两个相邻元素,令第一个元素为*i,第二个元素为*ii,且满足*i>*ii.找到这样一组相邻元素后,再从尾端开始往前检验,找到第一个小于*i的元素,令为*j,将i,j元素对调,再将ii之后的所有元素颠倒排序。此即前一个排列组合。

template <class BidirectionalIterator>
bool prev_permutation(BidirectionalIterator first, BidirectionalIterator last) {
    if (first == last) return false;
    BidirectionalIterator I = first;
    ++I;
    if (I = last) return false;
    I = last;
    --I;
    for (;;) {
        BidirectionalIterator II = I;
        --I;
        if (*II < *I) {
            BidirectionalIterator J = last;
            while(!(*--J < *I );
            iter_swap(I, J);
            reverse(II, last);
            return true;
        }
        if (I == first) {            // 进行到了最前面都未找到符合条件的元素
            reverse(first, last);    // 全部重排,重新再来一遍?
            return false;
        }
    }
}

代码如下:版本二只是将operator<用comp替换,此处不在罗列代码。

参考文档《STL源码剖析》---侯捷

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

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

相关文章

Windows下从命令行(Powershell/CMD)发送内容到系统通知中心

Windows下从命令行&#xff08;Powershell/CMD&#xff09;发送内容到系统通知中心 01 前言 在平时写脚本的时候&#xff0c;将日志等信息直接输出到控制台固然是最直接的&#xff0c;而如果是一些后台执行的任务&#xff0c;不需要时刻关注运行细节但是又想知道一些大致的情…

计算机的错误计算(一百七十二)

摘要 探讨 MATLAB 对于算式 的计算误差。 例1. 在 MATLAB 中计算 的值。 直接贴图吧&#xff1a; 这样&#xff0c;MATLAB 的输出中只有3位正确数字&#xff0c;有效数字的错误率为 (16-3)/16 81.25% . 因为16位的正确输出为 0.2971242332737277e-18&#xff08;ISReals…

第30天:安全开发-JS 应用NodeJS 指南原型链污染Express 框架功能实现审计0

时间轴&#xff1a; 演示案例&#xff1a; 环境搭建-NodeJS-解析安装&库安装 功能实现-NodeJS-数据库&文件&执行 安全问题-NodeJS-注入&RCE&原型链 案例分析-NodeJS-CTF 题目&源码审计 开发指南-NodeJS-安全 SecGuide 项目、 环境搭建-NodeJ…

SQL优化与性能——数据库事务管理

数据库事务管理是数据库系统中至关重要的一部分&#xff0c;确保了数据的一致性、完整性、可靠性和隔离性。尤其在高并发、高负载的系统中&#xff0c;事务管理的设计和实现直接影响到系统的稳定性和性能。本章将详细探讨以下内容&#xff1a;事务的ACID特性、使用 BEGIN、COMM…

Rook入门:打造云原生Ceph存储的全面学习路径(上)

文章目录 一.Rook简介二.Rook与Ceph架构2.1 Rook结构体系2.2 Rook包含组件2.3 Rook与kubernetes结合的架构图如下2.4 ceph特点2.5 ceph架构2.6 ceph组件 三.Rook部署Ceph集群3.1 部署条件3.2 获取rook最新版本3.3 rook资源文件目录结构3.4 部署Rook/CRD/Ceph集群3.5 查看rook部…

机器学习——生成对抗网络(GANs):原理、进展与应用前景分析

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一. 生成对抗网络的基本原理二. 使用步骤2.1 对抗性训练2.2 损失函数 三. GAN的变种和进展四. 生成对抗网络的应用五. 持续挑战与未来发展方向六. 小结 前言 生…

IDEA连接Apifox客户端

IDEA连接Apifox客户端 一、下载Apifox安装包二、IDEA配置三、配置Apifox和IDEA项目同步 一、下载Apifox安装包 Apifox官网&#xff0c;根据自己的操作系统下载对应的Apifox安装包&#xff0c;我是windows系统所以下载的是windows版。 下载 默认仅为我安装&#xff0c;点击下一…

Python毕业设计选题:基于django+vue的校园影院售票系统

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 管理员登录 管理员功能界面 用户管理 影院信息管理 电影类型管理 电影信息管理 系统…

《Java核心技术I》线程状态

12.2 线程状态 线程可以有6种状态&#xff1a; New(新建)Runnable(可运行)Blocked(阻塞)Waiting(等待)Timed waiting(计时等待)Terminated(终止) 确定当前线程的状态&#xff0c;只需要调用getState()方法。 12.2.1 新建线程 当new创建一个线程时&#xff0c;线程还未运行…

树莓派基本配置-基础配置配置

树莓派基本配置 文章目录 树莓派基本配置前言硬件准备树莓派刷机串口方式登录树莓派接入网络ssh方式登录树莓派更换国内源xrdp界面登录树莓派远程文件传输FileZilla 前言 树莓派是一款功能强大且价格实惠的小型计算机&#xff0c;非常适合作为学习编程、物联网项目、家庭自动化…

python---面向对象-python中的实践(2)

如何定义一个类&#xff1f; class 类名:pass怎样通过类&#xff0c;创建出一个对象&#xff1f; 根据类创建对象one Money() 执行流程1. 类的定义2. 根据类&#xff0c;创建出一个对象3. 将对象的唯一标识返回class Money:passprint(Money.__name__) xxx Money print(xxx.…

以达梦为数据库底座时部署的微服务页面报乱码,调整兼容模式

1.问题描述 部署微服务&#xff0c;文件、代码是延用的mysql类型的&#xff0c;部署前做了部分适配&#xff0c;但是在使用dm数据库进行安装的服务在页面上查询出的数据却都是乱码 2.查询官网&#xff0c;注意到一个参数COMPATIBLE_MODE兼容模式的配置 考虑是延用mysql&…

.net core MVC入门(三)——Product页面添加

文章目录 项目地址一、Product数据库准备 项目地址 教程作者&#xff1a;教程地址&#xff1a; 代码仓库地址&#xff1a; 所用到的框架和插件&#xff1a; dbt airflow一、Product数据库准备 添加Product的EF上下文 public DbSet<Category> Categories { get; set; …

DDR3与MIG IP核(三)

.init_calib_complete&#xff1a;DDR3初始化信号 MIG IP核的28位地址对应DDR3地址的对应关系&#xff1a;3代表8个bank 写数据时序图&#xff1a;&#xff08;三种写数据的方式&#xff09; 1&#xff1a;写数据app_wdf_data时序发生在写命令app_cmd和写地址app_addr之前 2…

Python酷库之旅-第三方库Pandas(251)

目录 一、用法精讲 1186、pandas.tseries.offsets.BusinessMonthEnd.is_year_start方法 1186-1、语法 1186-2、参数 1186-3、功能 1186-4、返回值 1186-5、说明 1186-6、用法 1186-6-1、数据准备 1186-6-2、代码示例 1186-6-3、结果输出 1187、pandas.tseries.offs…

写NFC微信小程序跳转Uri标签

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1b8bEEGz&ftt&id615391857885 Dim dispstr As String Dim status As Byte Dim status1 As Byte Dim afi As Byte Dim myctrlword As Byte Dim mypiccserial(0 To 7) …

关于单片机的原理与应用!

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///目前正在学习C&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于单片…

【Linux】————(日志、线程池及死锁问题)

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;Linux 创作时间 &#xff1a;2024年11月29日 日志 关于日志&#xff0c;首先我们来说一下日志的作用&#xff0c; 作用&#xff1a; 问题追踪&#xff1a;通过日志不仅仅包括我们程序的一些bug&#xff0c;也可以在…

基于深度学习的甲状腺结节影像自动化诊断系统(PyQt5界面+数据集+训练代码)

随着医学影像技术的发展&#xff0c;计算机辅助诊断在甲状腺结节的早期筛查中发挥着重要作用。甲状腺结节的良恶性鉴别对临床治疗具有重要意义&#xff0c;但传统的诊断方法依赖于医生的经验和影像学特征&#xff0c;存在一定的主观性和局限性。为了解决这一问题&#xff0c;本…

本地项目通过git传递给新建的github库

第一步&#xff0c;打开终端进入本地项目目录 第二步&#xff0c;初始化Git仓库 git init第三步&#xff0c;添加远程仓库 git remote add origin https://github.com/用户名/仓库名.git第四步&#xff0c;添加所有文件到Git版本控制 git add .这个命令会将所有文件添加到暂…