web-dev-qa-db-ja.com

クイック選択で入力配列を変更する必要がありますか?

私は最近、配列のk番目に小さい要素を計算するアルゴリズムであるクイック選択を実装しました。これは、おおまかに言って、ピボットの周りで配列を繰り返しパーティション分割し、配列を適切に縮小することによって機能します。

実装は、余分なメモリの浪費を避けるために、参照によって受け取る入力配列を再配置します。

以下の2つのオプションのどちらをお好みですか(アルゴリズムを使用する人として)?

  1. アルゴリズムは入力配列のコピーを作成し、そのコピーをいじります。
  2. アルゴリズムは入力配列を変更します(順序が重要な場合に備えて、ユーザーはコピーを渡すように注意する必要があります)。
4
blazs

私は通常期待します

  1. アルゴリズムは入力配列のコピーを作成し、そのコピーをいじります。

ただし、別の方法を使用するのには非常に理由があります。

  1. 配列は非常に大きく、ユーザーはループで関数を呼び出します。
    これを行う場合は、異常な動作であるため、必ずドキュメントで呼び出してください
  2. 入力配列はユーザ​​ーに対して不透明です。つまり、ユーザーは関数の1つを呼び出すことによって生成し、特定の順序が約束されたことはなく、その中の内容を正確に把握していない場合もあります。

つまり、特定の状況に最適なものを決定するである必要があります。

6
Dan Pichelman

1、または可能であれば両方

言語が読み取り専用と可変の仮パラメーターの区別を関数に許可している場合(C++でのconst参照、値の配列型+参照による受け渡しなど)、特定の使用法では、配列が破棄されることを気にしない場合があります。

それ以外の場合は、渡されたデータの並べ替えが期待に反し、並列処理との相互作用が悪いという他の回答に同意します。

1
Caleth

明確に文書化されていない限り、1(入力を変更しないでください)。

配列を関数に渡し、入力データを破棄するのは非常に予期しない動作です。通常の状況では、これを大きなバグと呼びます。

操作を元に戻しても、スレッドの安全性が損なわれることに注意してください(読み取りも未定義の動作になるため)。

編集:最適化オプションを使用している場合(そしてそれが必要であることを確信している場合)、オプションのパラメーターを関数に追加することができます。つまり、bool mayRearrangeArray = false。このようにして、ユーザーはオプションを選択できますが、デフォルトでは安全側にあります。

0
Eiko

2のほうが柔軟性があるので、感謝します。こうすることで、入力データを気にすればコピーを作成できますが、効率を重視する場合は、元のデータ。

もちろん、入力シーケンスを変更するのは、非常に明確に宣言するのがあなたの仕事です。

または、別の言い方をすると、クイックセレクトはインプレースの「部分ソート」アルゴリズムと考えることができ、通常、この種のアルゴリズムへのインターフェースdo入力データを変更します。std::sortstd::make_heapについて考えます。

実際、C++は実際には標準ライブラリ(関数std::nth_element)にQuickSelectを実装しています。何だと思う?入力データを変更します;)

0
akappa

答えは通常、使用している言語と使用しているユーザーの種類によって異なります。

パフォーマンスが重要な言語では、その場で変更を行うのが一般的です。メモリの割り当ては高価であり、メモリが限られているマシンでは問題になる可能性があるため、Cの開発者(私はパフォーマンスの「王様」と考えています)は常に適切なソートを行います。並べ替えアルゴリズムのほとんどすべての実装を見ると、この方法で実装されていることがわかります。

一方、MATLABは通常、パフォーマンスよりも明快さを重視しています。したがって、MATLABの並べ替えアルゴリズムは、新しい値を含む新しく作成された配列を返すことがよくあります。

あなたの言語がその場での修正をサポートしているなら、私はakappaがコメントで作った理由のためにその道を進むことを勧めます。単純に配列をコピーして、それをその場でのソートに渡すソートを作成するのは簡単です。逆に進むことは不可能なので、その場で並べ替えを行うことで、より多くのオプションをサポートできます。

0
Cort Ammon