私は最近、配列のk番目に小さい要素を計算するアルゴリズムであるクイック選択を実装しました。これは、おおまかに言って、ピボットの周りで配列を繰り返しパーティション分割し、配列を適切に縮小することによって機能します。
実装は、余分なメモリの浪費を避けるために、参照によって受け取る入力配列を再配置します。
以下の2つのオプションのどちらをお好みですか(アルゴリズムを使用する人として)?
私は通常期待します
- アルゴリズムは入力配列のコピーを作成し、そのコピーをいじります。
ただし、別の方法を使用するのには非常に理由があります。
つまり、特定の状況に最適なものを決定するである必要があります。
1、または可能であれば両方
言語が読み取り専用と可変の仮パラメーターの区別を関数に許可している場合(C++でのconst参照、値の配列型+参照による受け渡しなど)、特定の使用法では、配列が破棄されることを気にしない場合があります。
それ以外の場合は、渡されたデータの並べ替えが期待に反し、並列処理との相互作用が悪いという他の回答に同意します。
明確に文書化されていない限り、1(入力を変更しないでください)。
配列を関数に渡し、入力データを破棄するのは非常に予期しない動作です。通常の状況では、これを大きなバグと呼びます。
操作を元に戻しても、スレッドの安全性が損なわれることに注意してください(読み取りも未定義の動作になるため)。
編集:最適化オプションを使用している場合(そしてそれが必要であることを確信している場合)、オプションのパラメーターを関数に追加することができます。つまり、bool mayRearrangeArray = false
。このようにして、ユーザーはオプションを選択できますが、デフォルトでは安全側にあります。
2のほうが柔軟性があるので、感謝します。こうすることで、入力データを気にすればコピーを作成できますが、効率を重視する場合は、元のデータ。
もちろん、入力シーケンスを変更するのは、非常に明確に宣言するのがあなたの仕事です。
または、別の言い方をすると、クイックセレクトはインプレースの「部分ソート」アルゴリズムと考えることができ、通常、この種のアルゴリズムへのインターフェースdo入力データを変更します。std::sort
とstd::make_heap
について考えます。
実際、C++は実際には標準ライブラリ(関数std::nth_element
)にQuickSelectを実装しています。何だと思う?入力データを変更します;)
答えは通常、使用している言語と使用しているユーザーの種類によって異なります。
パフォーマンスが重要な言語では、その場で変更を行うのが一般的です。メモリの割り当ては高価であり、メモリが限られているマシンでは問題になる可能性があるため、Cの開発者(私はパフォーマンスの「王様」と考えています)は常に適切なソートを行います。並べ替えアルゴリズムのほとんどすべての実装を見ると、この方法で実装されていることがわかります。
一方、MATLABは通常、パフォーマンスよりも明快さを重視しています。したがって、MATLABの並べ替えアルゴリズムは、新しい値を含む新しく作成された配列を返すことがよくあります。
あなたの言語がその場での修正をサポートしているなら、私はakappaがコメントで作った理由のためにその道を進むことを勧めます。単純に配列をコピーして、それをその場でのソートに渡すソートを作成するのは簡単です。逆に進むことは不可能なので、その場で並べ替えを行うことで、より多くのオプションをサポートできます。