促进 C++库

……其中一个世界。 赫伯·萨特安德烈亚历山德雷斯库,C类++编码标准

这是旧版本Boost的文档。单击此处查看此页面的最新版本。

标题<boost/algorithm/minmax.hpp>

动机
简介
功能模板说明
定义
类型要求
前提条件
后置条件
复杂性
例子
笔记
理论基础
关于性能的注释
致谢

动机

minmax库由两个标头组成,<boost/algorithm/minmax.hpp><boost/algorithm/minmax_element.hpp>.(请参见理论基础.)这个库解决的问题是同时最小值和最大值计算需要只有一个比较,但使用标准::分钟标准::最大强制进行两次比较。更糟糕的是,计算最小值和范围内的最大元素n个元素只需要3个/2+1比较,而不是2个(两次通过)被…强迫标准::min_element标准::max_element.我一直认为必须调用两个函数来计算范围的范围,对输入执行两次传递足够了。目前的库解决了这两个问题。

第一个文件实现了函数模板极小极大作为C语言的直接扩展++标准。当它返回一对常数&,我们必须使用增压管接头图书馆来建造这样的对。(请注意:其目的不是修复标准::分钟标准::最大,但要再添加一个将两者结合的算法;请参阅理论基础.)

第二个文件实现了函数模板最小最大元素。在第二部分,它还提出了通常无法通过minmax算法,在某些元素相等的情况下更灵活。这些变体也可以提供基于政策的设计,但我反对(参见理论基础)。

如果你有兴趣性能,你会看到的最小最大元素只是效率稍低比单个最小元素(_E)最大元素(_E),因此两次单独呼叫的效率是最小元素(_E)最大元素(_E)。来自理论观点,所有的最小最大元素功能最多执行3个/2+1比较和n个增量前向迭代器.

简介<boost/algorithm/minmax.hpp>

#包括<boost/tuple/tuple.hpp>命名空间增强{模板<T类>元组<T const&,T const&>最小值(常数T&a,常数T&b);模板<类T,类二元谓词>元组<T const&,T const&>minmax(常量T&a、常量T&b、二元谓词comp);}

简介<boost/algorithm/minmax_element.hpp>

#include<utility>//用于std::pair命名空间增强{模板<类前向迭代器>std::pair<ForwardIterator,ForwardItherator>minmax_element(首先是ForwardIterator,最后是ForwardInterator);模板<类前向迭代器,类二元谓词>std::pair<ForwardIterator,ForwardItherator>minmax_element(首先是ForwardIterator,最后是ForwardInterator,二进制谓词comp);}
此外,还有一系列扩展指定如果元素相等,则要选择哪个元素。他们是:我不会让你厌烦完整的大纲,它们完全一样声明为相应的_元素功能。尽管如此,你可以找到完整的大纲在这里.

功能模板说明

这个极小极大算法返回一对第页包含其中之一(a、b)(b、a),因此p.first<p.second在第一版中,比较(p.first,p.second)在第二个版本中。如果元素是等价的,这对(a、b)返回。
[1]

这个最小最大元素在语义上等同于第一个最小第一个最大元素.

第一个最小元素第一个最大元素找到最小的和范围内最大的元素[第一,最后).如果有这些元素的几个实例,返回第一个。他们是与…相同标准::最小元素标准::max_element仅为对称性而包含在此库中。

最后一个元素(_min_element)最后一个最大元素找到最小的和范围内最大的元素[第一,最后)。他们几乎与…相同标准::min_element标准::max_element,除返回最大元素的最后一个实例(而不是首先,作为第一个最小元素最后一个最大元素将)。

算法系列包括第一个最小第一个最大元素,第一个最小最大元素,最后一个最小第一个最大元素,最后最小最大元素可以概括为遵循(使用哪一个什么对于第一最后的):哪一个_最小值_什么_最大元素(_E)发现(根据哪一个)最小元素和(根据什么)最大元素在范围内[第一,最后)。第一个版本是语义上的相当于:

标准::make_pair(增强::哪一个_min_element(第一个,最后一个),促进::什么_max_element(第一个,最后一个),
第二个版本为:
std::make_pair(升压::哪一个_最小元素(第一个、最后一个、comp),促进::什么_最大元素(第一个、最后一个、comp).


注释:的第一个最小最大元素也可以描述如果稳定排序,则查找范围中的第一个和最后一个元素。

定义

定义于最小最大马力在里面最小最大元素.hpp.

类型要求

对于minmax,T型必须是的模型
莱斯坦可比.

对于所有其他函数模板,具有两个模板参数的版本:

对于具有三个模板参数的版本:

前提条件

后置条件

除了上面的语义描述之外。对于最小最大元素以及所有哪一个_最小值_什么_最大元素(_E)变量,返回值为最后的std::make_pair(最后一个,最后一个)当且仅当[第一,最后)是空范围。否则返回值或结果对的两个成员都是范围[第一,最后).

复杂性

Minmax只进行一次比较,否则会有恒定的复杂性。使用boost::元组<T const&>防止复制构造函数,以防参数通过引用传递。

所有其他算法的复杂性都是线性的。他们都在表演精确到n个增量操作,如果[第一,最后)为空,否则:

哪里n个是中的元素数[第一,最后).

例子

本示例包含在下面的图书馆
最小值_ex.cpp.
整型main(){使用命名空间标准;boost::tuple<int const&,int const&>result1=boost:,minmax(1,0);断言(结果1.get<0>()==0);断言(result1.get<1>()==1);列表<int>L;生成(前端插入器(五十) ,1000兰特);typedef列表<int>::const_iterator迭代器;pair<iterator,iterator>result2=boost::minmax_element(L.begin(),L.end());cout<<“最小元素是”<<*(result2.first)<<endl;cout<<“最大元素是”<<*(result2.second)<<endl;断言(result2.first==std::min_element(L.begin(),L.end());断言(result2.second==std::max_element(L.begin(),L.end());}

笔记

[1]我们不支持习语,如领带(a,b)=最小最大值(a,b)订购两个元素,b条,尽管这样会如果我们返回一个引用而不是一个常量,则会产生预期的效果参考。原因是两个不必要的任务是如果a和b正常,则执行。最好坚持如果(b<a)掉期(a,b)以达到这一效果。

[2]这些算法总是至少执行第3页/2-2页比较,这是任何情况下的比较次数(Cormen、Leiserson、Rivest:“简介到算法”,第9.1节,练习9.1-)。算法本质上是比较成对的元素,对前两个元素执行1个比较,然后对剩余的每对元素进行3次比较(一次用于排序元素和一个用于更新最小值和最大值)。什么时候?元素的数量是奇数,需要将最后一个元素与电流最小值和电流最大值。此外,对于极小极大,如果一对中的两个成员可能相等,以及更新存储第二个,我们保存第一个以在末尾检查更新应该存储第一个(在相等的情况下)。这很难预测是否执行了最后一次比较,因此最多在这两种情况下。

[3]这些算法总是至少执行第3页/2-2页比较,这是任何情况下的比较次数。方法与注释相同[2]和上面一样,当元素数为奇数时,最后一个元素需要与当前最小值以及当前最大值进行比较。如果前者成功,我们可以避免后者的比较,因此而不是确切地在奇怪的情况下。

理论基础:

为什么不是单个标题&boost/algorithm/minmax.hpp>?

这是最初提出并经正式批准的设计审查。随着Boost.tuple需求的明确(由于限制属于标准::对),要求另一个也变得很烦人的库最小最大元素它不需要它。因此分为两个头文件。

您的minmax与std::min和标准::最大。

我知道std::min和std::max,以及所有正在进行的辩论(请咨询亚历山德雷斯库的论文以及其中的链接)。但我看不出这有什么用库修复了C++标准的一部分。我谦卑地认为它超出了这个图书馆的范围。相反,我是遵循标准的方式,只需再提供一个功能属于同一个家庭。如果其他人想修复std::min,则为他们修复可能也适用于boost::minmax。

为什么不最小/最大元素_if?

在图书馆的第一版中,我提议_如果的版本所有的算法(好吧,不是全部,因为那太多了)。然而,没有理由这么做,我所有的版本使用优秀的<boost/iterator_adaptors.hpp>库。即,呼叫min_element_if(第一个,最后一个,pred)也一样实施单位:

//等价于min_element_if(first、last、pred)最小元素(boost::make_filter_iterator(first,last,pred),boost::make_filter_iterator(last,last,pred));
可以说最小元素_if版本略短,但迭代器适配器的开销不大,并且它们消除了大量代码(考虑first/last和用if变体加倍!)。

讨论:关于std::max_element

这个理论有点历史性,但解释了为什么这些第一个/最后一个最小值/最大元素功能。

C++标准要求标准::min_element标准::max_element返回最小和最大元素的第一个实例(相反比方说最后一个)。这种任意选择具有一定的一致性:在例如,在向量<int>类型的v的情况下标准::min_element(v.begin(),v.end(),标准::less<int>())==标准::max_element(v.begin(),v.end(),标准::更大<int>()).

当然这没有什么错:这只是一个问题选择。另一种指定min_element和max_element的方法是定义如果范围是稳定排序的,则它们作为第一个和最后一个元素。稳定的排序对于消除迭代器之间的歧义是必要的具有相同值的。)在这种情况下,min应该返回第一个实例max应该返回最后一个。然后,这两个函数通过reverse_iterator(标准::first_min_element(v.begin(),v.end(),标准::less<int>()))==标准::last_max_element(v.rbegin(),v.ren(),标准::更大<int>()).这个定义与前一个定义略有不同。

当试图设计minmax_element时,定义问题出现了,使用(Cormen、Leiserson、Rivest:“简介算法”,第9.1节)应该可以推导出算法仅使用3个/2比较,如果[第一,最后)n个元素,但如果尝试编写一个名为第一个最小第一个最大元素()返回这两个标准::最小元素标准::max_element在一对中,琐碎的实现不起作用微妙地说,是关于相等元素的:我必须思考一段时间才能找到一个只执行三个的方法对每对进行比较,并返回第一个min和第一个max元素。很长一段时间,似乎如果尝试这样做,最坏的情况是每对都要进行四次比较案例。此实现实现了三个目标。

改变…的意思是不可能的(甚至是不可取的)最大元素(_E),但提供一个名为最小最大元素(_E),它返回一对最小元素(_E)最大元素(_E).尽管打电话很容易最小元素(_E)最大元素(_E),这执行2(n-1)比较,并需要传递输入。相反,最小最大元素将执行比较次数越少,执行单一的传递输入。当迭代器类型不是原始指针时,节省的开销可能会很大,甚至只是InputIterator概念的一个模型(尽管如果接口必须是由于无法复制返回类型,因此可以例如。返回值)。

为了从算法的所有变体中获益,我建议介绍这两者第一个最小元素最后一个最小元素,和他们的对手第一个_max元素最后一个最大元素.然后我还提出了所有变体算法:第一个最小最大元素最后一个最小第一个最大元素,最多只能执行3个/2比较,并且只对输入进行一次传递。事实上,这是可以证明的计算minmax至少需要3(无2)-2中的比较问题的任何实例(Cormen,Leiserson,Rivest,第2版,第节9.1). 我给出的实现没有执行不必要的比较(其结果可以通过上一个比较)。

看起来第一个最小最大元素可能只是一点点慢于第一个最小元素独自一人,仍然比第一个最小元素最后一个最大元素单独调用。[2]

为什么是算法而不是累加器?

minmax算法在计算范围时很有用。在计算机图形学中,我们需要一组对象的边界框。在这种情况下,单程通过的要求更为严格因为这三个方向必须同时完成。思想食粮:那里对于一个可堆叠的好的泛型编程库来说很重要更新最小值更新最大值存储对最小结果最大结果变量,与用于(_E)算法)。

我相信许多标准的顺序算法可以重新制定使用累加器(以及其他许多累加器,例如在统计、期望/差异等)。似乎还有地方放另一个图书馆,但我没有看到它与minmax竞争,而是扩展了几个算法(包括minmax)到累加器框架。然而,我觉得是这样的超出了此库的范围,无法提供此类累加器。

这第一个/最后一个是基于策略的完美应用程序设计。

是的,我本来可以这样做,使用默认策略最小元素(_E)最大元素(_E)选择第一个结果的出现。这会减少minmax_element变量的组合。但它也会有意在更改的界面boost::minmax_element.的目标之一最小最大元素算法是它的最终添加到C++标准中,与标准::min_element标准::max_element(我觉得这很自然考虑到实现的短促性正确处理所需的细节)。因此,通过以下方式更改界面不幸的是,增加政策意味着要背离标准并为实现这一目标设置了障碍。此外,代码在没有策略的情况下,仍保持可读性和简单性。所以我很高兴保持这样。

关于性能

致谢

我在CS903(理工大学。,
http://photon.poly.edu/~hbr/cs903/)谁有过最小最大元素由于任务有助于澄清问题,并提出最佳比较次数第一个最小最大元素.识别周围的问题最大元素(_E)是唯一的我自己的。

一个最小最大元素实现,执行3(n/2)+O(对数n)当元素为随机_混乱日期:,是我的学生马克·格利塞建议的。当前执行的3(无2)+1John Iacono建议进行最坏情况下的比较。

最后,Matthew Wilson和Jeremy Siek提供了预审查评论,而Gennadiy Rozental、John Maddock、Craig Henderson、Gary鲍威尔参加了由托马斯管理的图书馆的审查威特。特别是,Gennadiy建议对代码进行因子分解;虽然我没有完全遵循,但他的建议确实使代码更具可读性,并且仍然可以与较旧的编译器一起使用。审查结束后的晚些时候,我终于申请添加库以获得埃里克·尼伯勒(Eric Niebler)表示标准::对对于极小极大并建议改用Boost.tuple。非常感谢大家的宝贵建议和评论。

另请参见

最小值,最大,最小元素(_E),最大元素(_E),莱斯坦可比,分类,第n个元素(_E).

上次修改时间:2004-07-01

©版权所有Hervé布伦尼曼,理工大学,2002-2004年。使用、修改和分发受Boost软件的约束许可证,1.0版。(见随附文件许可证_1_0.txt或复制于http://www.boost.org/LICENSE_1_0.txt)