stl partition演算法有兩種寫法,哪種效率高?

partition分別對於forward_iterator和bidirectional_iterator採取兩種不同的寫法,兩種演算法都是O(N)但哪種效率更好?

雙向迭代器

template&
_BidirectionalIterator
__partition(_BidirectionalIterator __first, _BidirectionalIterator __last,
_Predicate __pred, bidirectional_iterator_tag)
{
while (true)
{
while (true)
if (__first == __last)
return __first;
else if (__pred(*__first))
++__first;
else
break;
--__last;
while (true)
if (__first == __last)
return __first;
else if (!bool(__pred(*__last)))
--__last;
else
break;
std::iter_swap(__first, __last);
++__first;
}
}

單向迭代器

template&
_ForwardIterator
__partition(_ForwardIterator __first, _ForwardIterator __last,
_Predicate __pred, forward_iterator_tag)
{
if (__first == __last)
return __first;

while (__pred(*__first))
if (++__first == __last)
return __first;

_ForwardIterator __next = __first;

while (++__next != __last)
if (__pred(*__next))
{
std::iter_swap(__first, __next);
++__first;
}

return __first;
}


這兩種演算法是有名字的。單向迭代器使用的是Lomuto partition,雙向的那個叫做Hoare partition。

兩種方法都是O(n),但Hoare演算法常數小,少做三倍的交換,且在所有值返回的結果都相等的時候更高效。

但是兩者都不能避免快排退化(


因為所有的雙向迭代器都一定可以被當成單項迭代器,那麼既然他還給雙向迭代器寫了一份,那當然只能是因為作者認為雙向迭代器有更好的做法。


如果 bidirectional iterator 效率跟 forward iterator 的一樣 他就沒必要專門為 bidirectional iterator 特化一份,所以肯定是 bidirectional iterator 的快。時間複雜度相同不代表速度相同啊 那個其實不叫O(n)啊 其實叫θ(n)啊 這個式子是省掉了低階項和常數因子的 所以雖然都是 θ(n)常數因子不同就實際時間就不一樣呀! 具體差多少的話就自己多測試幾次


我來回答一下。

你看得很仔細。這兩種劃分策略的漸進時間複雜度都是線性的,但前者(bi版本)的效率略高,常數更小。這其實也不難想到——bi版本做一次操作可以解決兩個元素(頭上一個,尾上一個),但fw版本交換一次只能解決一個元素。比較一下最壞情況:

bi版本最壞有3/2n次元素移動

fw版本最壞有3n次元素移動

所以bi版本更好一點。

參考資料:https://kluedo.ub.uni-kl.de/files/3463/wild-master-thesis.pdf

看其中的3.4.2 Implementation of the Partitioning Step

(這篇碩士論文對快速排序寫得很深入,可以當做排序愛好者的深度文獻)


推薦閱讀:

演算法導論第三版的翻譯水平如何?
該直接上《演算法導論》 還是先看完 《演算法 第四版》?
有能算出反三角函數的準確值的演算法嗎?
演算法能受到版權保護嗎?
隨機森林中訓練每一棵樹輸入的m個特徵都是隨機選取的嗎?

TAG:操作系統 | 演算法 | STL | C |