我试图将C ++的反向功能作为练习来实现。练习说明(来自Caltech的高级C ++课程)暗示您应该使用distance
函数,该函数计算两个迭代器之间的项数。使用这个提示,我编写了下面的函数,它看似起作用:
template <typename BidirectionalIterator>
void my_reverse(BidirectionalIterator first, BidirectionalIterator last) {
last--; // input "last" is one past the end
while( first != last && distance(first, last) > 1 ){
std::swap(*first, *last);
first++;
last--;
}
return;
}
但我对此方法有疑问:如果我没有弄错,在每一步调用distance
会使其成为O(n ^ 2)算法。
所以我用以下内容替换了while条件:
while( first < last ){
这似乎也有效。但它让我有点紧张,因为BidirectionalIterators上的文档并不能保证迭代器可以像这样订购。我是否可以相信此排序将始终按预期工作,v.end()
对于STL容器对象v.begin()
始终大于v
?
(我的担忧来自于像Haskell程序员一样认为BidirectionalIterators可以保证具有Eq的属性,可以这么说,但不是Ord。)
答案 0 :(得分:3)
双向迭代器(也不是随机访问迭代器)不支持operator<
。尝试将std::list
迭代器传递给您的函数,您将看到它无法编译。他们不支持这种操作的原因正是因为它非常昂贵。
至于使用distance
:
如果我没有弄错的话,在每一步调用距离都会成为一个问题 O(n ^ 2)算法。
你是正确的 1 。这不是实现反向算法的好方法。没有必要获得迭代器之间的距离。您只能使用operator!=
和/或operator==
来执行此操作,这两个都是O(1)。
<子> 1。除非你传递随机访问迭代器,在这种情况下,距离将使用operator-
,算法将是O(n),如预期的那样。
答案 1 :(得分:3)
如果有人将空范围(first == last
)传递给它,您的算法会有未定义的行为,因为您在检查该条件之前递减last
。你需要
void my_reverse(BidirectionalIterator first, BidirectionalIterator last) {
while((first != last) && (first != --last)){
std::swap(*first, *last);
first++;
}
return;
}
而不是引用迭代器并在结果上调用std::swap
,您可以使用std::iter_swap
为您完成所有操作。
void my_reverse(BidirectionalIterator first, BidirectionalIterator last) {
while((first != last) && (first != --last)){
std::iter_swap(first, last);
first++;
}
return;
}
答案 2 :(得分:0)
...也许
void my_reverse(BidirectionalIterator first, BidirectionalIterator last)
{
while (first != last && --last != first)
{
std::swap(*first, *last);
++first;
}
}
这里的事情是每次交换都需要在递增first
和递减last
(按任意顺序)之后完成,但它们彼此相等的点可能只在一次这样的操作之后已执行,因此对于每个执行swap
,应该有两个可能会从循环中断开的比较。