为什么C ++标准要求std :: partition满足不同类型迭代器的不同复杂性?

时间:2016-08-27 13:01:52

标签: c++ algorithm c++11

C ++标准要求std::partitionForwardIteratorBidirectionalIterator之间使用不同数量的谓词应用程序。对于ForwardIterator版本,谓词应用程序的数量应为< = N ,其中 N = std::distance(first, last),但{{1}在版本中,谓词应用程序的数量应为< = N / 2。显然,两个版本都具有时间复杂度 O N )。

我的问题是,为什么要为不同类型的迭代器提供不同的要求呢?这样的要求迫使很多编译器?

例如:MSVC,以两种方式实现函数BidirectionalIterator以满足这样的要求,这似乎不是很优雅。

还有一个问题:是否存在任何依赖于此系数的算法,这样当 N / 2变为 N 时,渐近复杂度会有所不同?根据我的理解,如果我们考虑std::partition,对于Master's Theorem中的表单,T(n) = aT(n/b) + f(n)中的系数并不重要。

C.f。 MSVC分区的等效实现:

f(n)

2 个答案:

答案 0 :(得分:4)

在两种情况下,谓词pred都完全执行 N 次 - 每个元素必须测试一次。 ForwardIteratorBidirectionalIterator之间的差异在于互换金额。

BidirectionalIterator最多会进行 N / 2 交换,因为它一旦从左侧达到不满足的值,就会立即从前面和后面扫描范围从权利的谓词和价值来实现它,它交换它们。所以在最坏的情况下,它可以在 N / 2 交换中完成它。

ForwardIterator没有那个优势,在最坏的情况下可能会为每个元素进行交换。

标准要求这两个不同的限制,因为它们都是最好的限制。因此程序员可以依赖每个标准库实现都会这样做。

答案 1 :(得分:3)

确实如此,时间复杂性仍然相同。

值得注意的是,掉期实际上相当昂贵。特别适用于大型物体。大多数时候他们涉及三个移动操作。在这种情况下,我们应该将掉期数量减少到最小。通过使用双向迭代器,即使时间复杂度相同,我们也可以在效率方面获得显着改进。

请记住,在真实环境中,快速执行简单操作可能至关重要。只要有可能这样做,就应该这样做。当使用复杂算法(通常用于NP完全问题变化)需要花费大量时间来计算时,在一半的时间内执行操作可能是至关重要的。您希望延迟0.2秒到0.1秒吗?时间的复杂性是一堆很好的理论,但现实世界并不那么美好,而第二部分的每一部分都很重要。