C++ 11標準では、std::sort
が O(n logn)複雑度になることを保証しています(最悪の場合)。これは、C++ 98/03のaverage-case保証とは異なります。ここで、std::sort
はQuicksortで実装できます(小さなnの挿入ソートと組み合わせることができます) 、最悪の場合はO(n ^ 2)になります(ソートされた入力などの特定の入力の場合)。
異なるSTLライブラリのstd::sort
実装に変更はありましたか? C++ 11のstd::sort
は、さまざまなSTLにどのように実装されますか?
libstdc ++ および libc ++ のオンラインソースを参照すると、両方のライブラリが、イントロソートのメインループからのよく知られたソーティングアルゴリズムの全範囲を使用すること:
_std::sort
_の場合、_insertion_sort
_のヘルパールーチン(O(N^2)
アルゴリズムですが、小さなシーケンスで競合できるように適切なスケーリング定数を使用)と、サブ0、1、2、3要素のシーケンス。
_std::partial_sort
_の場合、どちらのライブラリも_heap_sort
_(一般的にはO(N log N)
)のバージョンを使用します。これは、このメソッドに、ソートされたサブシーケンスを保持するNice不変式があるためです(通常、スケーリングが大きくなります)。完全なソートのためにそれをより高価にするために定数)。
_std::nth_element
_の場合、_selection_sort
_のヘルパールーチンがあります(これも、小さなシーケンスで競合できるようにするための適切なスクラリング定数を持つO(N ^ 2)アルゴリズムです)。通常の並べ替えでは、_insertion_sort
_は通常_selection_sort
_より優先されますが、_nth_element
_の場合、最小の要素を持つことの不変量は_selection_sort
_の動作と完全に一致します。
問題は、どうすればよいか[〜#〜] stl [〜#〜]が_std::sort
_と言うことです最悪の場合はO(N log(N))、本質的にはQuickSortですが。 STLのソートはIntroSortです。 IntroSortは本質的にQuickSortです。導入された違いにより、最悪のケースの複雑さが変わります。
どのパーティション設定を選択しても、QuickSortが実行されるシーケンスO(N ^ 2)が存在します。選択したパーティショニングは、最悪のケースが発生する確率を下げるだけです。 ( ランダムピボット選択 、3つの中央値、 etc。 )
編集: @ maxim1000の訂正に感謝します。ピボット選択アルゴリズムを使用したクイックソート Median of Medians はO(N log(N))最悪の場合の複雑さですが、オーバーヘッドがあるため、実際には使用されません。これは、理論的には、ピボット選択により、優れた選択アルゴリズムがワーストケースの複雑さをどのように変更できるかを示しています。
IntroSortは、QuickSortの分岐を制限します。これが最も重要なポイントであり、その制限は2 * (log N)です。制限に達すると、IntroSortはO(N log(N))の最悪の場合の複雑さを持つ任意の並べ替えアルゴリズムを使用できます。
O(log N)サブ問題があると分岐が停止します。すべての部分問題O(n log n)を解くことができます。 (小文字のnはサブ問題のサイズを表します)。
(n log n)の合計は、現在、最悪の場合の複雑さです。
QuickSortの最悪の場合。既に並べ替えられた配列があり、常にこの配列の最初の要素をピボットとして選択するとします。すべての反復で、最初の要素のみを削除します。この方法で最後まで行けば、明らかにO(N ^ 2)になります。 IntroSortを使用してQuickSortを停止し、深さlog(N)に達したら、残りのソートされていない配列にHeapSortを使用します。
_16 -> 1 /**N**/
\
> 15 -> 1 /**N - 1**/
\
> 14 -> 1 /**N - 2**/
\
> 13 -> 1 /**N - log(N)**/
\
> 12 /**(HeapSort Now) (N - log(N)) log (N - log(N))**/
_
それらを合計します。
分岐が停止するまで、N + (N - 1) + ... + (N - log(N))
操作が実行されます。ガウスを使用して合計する代わりに、単にN + (N - 1) + ... + (N - log(N)) < N log(N)
と言うことができます。
HeapSortパートは_(N - log(N)) log(N - log(N)) < N log(N)
_です
全体的な複雑さ< 2 N log(N)
。
定数は省略できるため、IntroSortの最悪の場合の複雑さはO(N log(N))です。
追加情報:[〜#〜] gcc [〜#〜] STL実装のソースコードは ここ です。 Sort
関数は行5461にあります。
修正: *Microsoft .NET* sort実装は2012年からIntroSortです。関連情報は こちら です。