C ++标准要求std::partition
在ForwardIterator
和BidirectionalIterator
之间使用不同数量的谓词应用程序。对于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)
答案 0 :(得分:4)
在两种情况下,谓词pred
都完全执行 N 次 - 每个元素必须测试一次。 ForwardIterator
和BidirectionalIterator
之间的差异在于互换金额。
BidirectionalIterator
最多会进行 N / 2 交换,因为它一旦从左侧达到不满足的值,就会立即从前面和后面扫描范围从权利的谓词和价值来实现它,它交换它们。所以在最坏的情况下,它可以在 N / 2 交换中完成它。
ForwardIterator
没有那个优势,在最坏的情况下可能会为每个元素进行交换。
标准要求这两个不同的限制,因为它们都是最好的限制。因此程序员可以依赖每个标准库实现都会这样做。
答案 1 :(得分:3)
确实如此,时间复杂性仍然相同。
值得注意的是,掉期实际上相当昂贵。特别适用于大型物体。大多数时候他们涉及三个移动操作。在这种情况下,我们应该将掉期数量减少到最小。通过使用双向迭代器,即使时间复杂度相同,我们也可以在效率方面获得显着改进。
请记住,在真实环境中,快速执行简单操作可能至关重要。只要有可能这样做,就应该这样做。当使用复杂算法(通常用于NP完全问题变化)需要花费大量时间来计算时,在一半的时间内执行操作可能是至关重要的。您希望延迟0.2秒到0.1秒吗?时间的复杂性是一堆很好的理论,但现实世界并不那么美好,而第二部分的每一部分都很重要。