sorted
andlist.sort
およびその他の、修飾される可能性のある処理を行うすべての関数にはkey
パラメーターがあり、特に順序付けを行う関数にもパラメーターがあることに気付くでしょうreverse
。(これについては、 Sorting Mini-HOWTO で説明しています。)
したがって、それらがどのように実装されているかを見ることができます。残念ながら、CPython では、これらすべてが C で実装されています。さらに、「timsort」と呼ばれるカスタム アルゴリズムを使用します (「参考文献」をlistsort.txt
参照)。しかし、ここで重要な部分を説明できると思います。これは非常に単純です。コードはコードlist.sort
から分離されておりsorted
、両方とも多数の機能に分散しています。しかし、最上位の functionlistsort
を見るだけで、reverse
フラグがどのように処理されるかがわかります。
1982 /* Reverse sort stability achieved by initially reversing the list,
1983 applying a stable forward sort, then reversing the final result. */
1984 if (reverse) {
1985 if (keys != NULL)
1986 reverse_slice(&keys[0], &keys[saved_ob_size]);
1987 reverse_slice(&saved_ob_item[0], &saved_ob_item[saved_ob_size]);
1988 }
最初と最後でリストを逆にするのはなぜですか? そもそもリストがほとんどソートされている場合、多くのソート アルゴリズム (timsort と挿入ソートの両方を含む) は、逆順よりも正しい順序で開始する方がはるかに優れています。はい、それは O(N)reverse
呼び出しを無駄にしますが、あなたはすでにそれらの 1 つを行っています。また、ソートアルゴリズムは少なくとも O(N log N) であり、あなたのアルゴリズムは具体的には O(N^2) であるため、これはそうではありません。アルゴリズム的に悪化させないでください。もちろん、N が小さく、並べ替えが適切で、ランダムな順序のリストの場合、この無駄な 2N は N log N にかなり近いため、実際には違いが生じる可能性があります。N が大きくなるにつれて消えていく違いですがlist
、いくつかの大きな s ではなく、何百万もの小さな s をソートしている場合は、心配する価値があるかもしれません。
2 番目に、逆スライスを作成して逆方向に実行していることに注意してください。これは、少なくとも潜在的に、元のlist
オブジェクトを__getitem__
逆の順序で参照することで最適化できます。つまり、2 つの反転は実際には O(1) です。これを行う最も簡単な方法は、文字通り逆スライスを作成することです: lst[::-1]
. 残念ながら、これは実際には新しい reversed を作成するlist
ため、timsort には独自のカスタム reverse-slice オブジェクトが含まれます。ReversedList
しかし、クラスを作成することで、Python でも同じことができます。
余分な関数呼び出しのコストがおそらく違いを圧倒するほど高いため、これはおそらく CPython では実際には高速ではありません。しかし、あなたは 2 つの呼び出しのアルゴリズムのコストについて不平を言っています。reverse
これにより、組み込みの並べ替え関数と同じ方法で問題が解決されます。
PyPy がどのようにそれを行うかを見ることもできます。で実装list
されていlistobject.py
ます。リストに含まれる内容に応じて、いくつかの異なる Strategy クラスの 1 つに委任されますが、すべての戦略 (何もしないものを除く) に目を通すと、それらは基本的に同じことを行います:sort
リスト、次にreverse
それ。
したがって、CPython には十分であり、PyPy には十分です...おそらくあなたにとっては十分です。