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源码剖析》---侯捷

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[高阶数据结构六]最短路径算法

1.前言 最短路径算法是在图论的基础上讲解的&#xff0c;如果你还不知道图论的相关知识的话&#xff0c;可以阅读下面几篇文章。 [高阶数据结构四] 初始图论_初始图结构-CSDN博客 [高阶数据结构五] 图的遍历和最小生成树_图的遍历和生成树求解-CSDN博客 本章重点&#xff1a;…

uniapp:封装商品列表为组件并使用

封装商品列表为组件并使用 商品组件封装 <template><!-- 商品列表 --><view class"goods_list"><view class"goods_item" v-for"item in goods" :key"item.id"><image :src"item.img_url">…

【AI系统】LLVM 架构设计和原理

LLVM 架构设计和原理 在上一篇文章中&#xff0c;我们详细探讨了 GCC 的编译过程和原理。然而&#xff0c;由于 GCC 存在代码耦合度高、难以进行独立操作以及庞大的代码量等缺点。正是由于对这些问题的意识&#xff0c;人们开始期待新一代编译器的出现。在本节&#xff0c;我们…

【C语言】结构体(二)

一&#xff0c;结构体的初始化 和其它类型变量一样&#xff0c;对结构体变量可以在定义时指定初始值 #include <stdio.h> #include <stdlib.h> struct books // 结构体类型 {char title[50];char author[50]; //结构体成员char subject[100];int book_id; }…

四、初识C语言(4)

一、作业&#xff1a;static修饰局部变量 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> //作业&#xff1a;static修饰局部变量 int sum (int a) {int c 0;static int b 3;c 1;b 2;return (abc); } int main() {int i 0;int a …

Linux 中的 ls 命令:从使用到源码解析

ls 命令是 Linux 系统中最常用和最基本的命令之一。下面将深入探讨 ls 命令的使用方法、工作原理、源码解析以及实际应用场景。 1. ls 命令的使用** ls 命令用于列出目录内容&#xff0c;显示文件和目录的详细信息。 1.1 基本用法 ls [选项] [文件或目录]例如&#xff1a; …

The selected directory is not a valid home for Go SDK

在idea里配置go语言的环境时&#xff0c;选择go语言的安装目录&#xff0c;一直提示这个 The selected directory is not a valid home for Go SDK后来查了一下&#xff0c;发现原来idea识别不出来 需要改一下配置文件&#xff0c;找到go环境的安装目录&#xff0c;我是默认安…

Leetcode581. 最短无序连续子数组(HOT100)

链接 我的代码&#xff1a; class Solution { public:int findUnsortedSubarray(vector<int>& nums) {vector<int> res nums;sort(res.begin(),res.end());int l 0,r nums.size()-1;while(nums[l]res[l]){l;if(lnums.size()){return 0;}}while(nums[r]res…

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

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

【Robocasa】Code Review

文章目录 OverviewalgoInitializationImportant Class MethodsTrain LoopTest Time ConfigsdemoConfig FactoryConfig StructureConfig Locking默认锁定状态配置修改的上下文管理器 dataset示例数据集对象参数说明 model基础模块EncoderCoreVisualCoreScanCore随机化器 (Random…

【单细胞数据库】癌症单细胞数据库CancerSEA

数据库地址&#xff1a;home (hrbmu.edu.cn) Cite Huating Yuan, Min Yan, Guanxiong Zhang, Wei Liu, Chunyu Deng, Gaoming Liao, Liwen Xu, Tao Luo, Haoteng Yan, Zhilin Long, Aiai Shi, Tingting Zhao, Yun Xiao, Xia Li, CancerSEA: a cancer single-cell state atlas…

React 的学习记录一:与 Vue 的相同点和区别

目录 一、学习目标 二、学习内容1️⃣——React的特点 1.组件化设计 2.单向数据流 3.声明式 UI 4.虚拟 DOM 5.Hooks 6.JSX 7.React Native 三、React与vue的比较总结 四、总结 一、学习目标 时间&#xff1a;两周 内容&#xff1a; React的特点React的入门React的…

数据库管理-第267期 23ai:Oracle Data Redaction演示(20241128)

数据库管理267期 2024-11-286 数据库管理-第267期 23ai&#xff1a;Oracle Data Redaction演示&#xff08;20241128&#xff09;1 示例表及数据2 创建编校策略2.1 名字全编校2.2 电话部分编校 3 DML演示3.1 场景13.2 场景2 总结 数据库管理-第267期 23ai&#xff1a;Oracle Da…

hue 4.11容器化部署,已结合Hive与Hadoop

配合《Hue 部署过程中的报错处理》食用更佳 官方配置说明页面&#xff1a; https://docs.gethue.com/administrator/configuration/connectors/ 官方配置hue.ini页面 https://github.com/cloudera/hue/blob/master/desktop/conf.dist/hue.ini docker部署 注意&#xff1a; …

Spring Boot自定义启动banner

在启动 Springboot 应用时&#xff0c;默认情况下会在控制台打印出 Springboot 相关的banner信息。 自定义banner 如果你想自定义一个独特的启动banner&#xff0c;该怎么做呢&#xff1f;Springboot 允许我们通过自定义启动banner来替换默认的banner。只需要在 resources 目…

leaflet 的基础使用

目录 一、创建dom节点 二、创建地图 三、添加底图&#xff08;天地图&#xff09;&#xff0c;在地图创建完成后添加底图 本章主要讲述leaflet在vue中的使用&#xff1a; leaflet 详情总目录&#xff1a;传送 一、创建dom节点 <div class"map" id"map_…

ubuntu的用户使用

ubuntu系统中的常规用户登录方式 在系统root用户是无法直接登录的,因为root用户的权限过大所以其安全性比较差 在登录系统时一般使用在安装系统时建立的普通用户登录 如果需要超级用户权限: Ubuntu用户密码破解 在系统安装完成后默认grub启动等待时间为0&#xff0c;建议改…

浏览器拨测:将网站护航的阵地再前推一米

作者&#xff1a;泉思 “从你在地址栏里敲下回车开始到你在网页上看到内容中间经过了哪些步骤”&#xff0c; 这是一个非常常见的互联网公司的面试题。想必很多开发者对于这个问题可以给出一个非常完整的回答&#xff0c;但是对于用户来说&#xff0c;在网页上看到内容仅仅是服…

【RL Application】语义分割中的强化学习方法

&#x1f4e2;本篇文章是博主强化学习&#xff08;RL&#xff09;领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对相关等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅…

【C++】优先队列(Priority Queue)全知道

亲爱的读者朋友们&#x1f603;&#xff0c;此文开启知识盛宴与思想碰撞&#x1f389;。 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 目录 一、前言 二、优先队列&#xff08;Priority Queue&#xff09…