これは、挿入ソートの2行の汎用C++11実装です。
template< typename ForwardIterator, typename Compare = std::less<typename std::iterator_traits<ForwardIterator>::value_type> >
void insertion_sort(ForwardIterator first, ForwardIterator last, Compare cmp = Compare())
{
for (auto it = first; it != last; ++it) {
auto const insertion = std::upper_bound(first, it, *it, cmp);
std::rotate(insertion, it, std::next(it));
}
}
アルゴリズムは、要素の範囲(2つのイテレーターfirst
とによって与えられるlast
)と比較関数(デフォルトで、ポイントされる要素に組み込まれている可能性があります)を取りますoperator<
。
メインループ(要素数が線形)は、サブインターバルを[first, it)
並べ替えたままにし、次の要素を配置する場所の挿入ポイントを繰り返し検索します。これは、メインループに相当します。これは、二分探索(対数の複雑さ)で行われます。コードでは、逆線形検索を使用します(線形の複雑さはありますが、キャッシュ動作が向上する可能性があります)。
挿入ポイントを検出した後、2つの範囲とを回転させるだけです。これは、現在の要素を挿入ポイントにスワップすることを意味します。この回転は、これまでにソートされた要素の数に比例します。メインループにネストされているため、挿入ソートの全体的な複雑さは2次式です。。コードは、挿入ポイントのスワッピングと検索を統合しますが、それによって複雑さが変わることはありません。[insertion, it)
[it, it+1)
O(N^2)
入力範囲がすでにソートされている場合、挿入ポイントは常に、が指す要素と等しくなることに注意してください。これは、が何も交換する必要がないことをit
意味します。std::rotate
十分にスマートで最適化されたコンパイラは、その最適化を実行できるはずです。その場合、ソートされた範囲での挿入ソートは線形の複雑さを持ちます。
選択ソートへの同様の2行のアプローチがここに示されています。