Java プログラマーにとって必須 - データ構造とアルゴリズムの迅速な並べ替え (1)

クイックソートの基本的な考え方:

クイックソートアルゴリズムの問​​題に関しては、分割統治アルゴリズムの典型的な実装例とも言えますが、まず、ソートされていない一連のシーケンスが、参照番号によって左右の2つのシーケンスS1とS2に分割されます。 S1 の要素はすべて基準番号より大きい、小さい、S2 の要素はすべて基準番号より大きい、そして左右の配列を再度すばやく並べ替えると、S1 と S2 の基準番号を自由に見つけることができます。毎回最下位ビットを参照番号として設定する必要はなく、このように部分列(S1 と S2 の部分列を含む)に対してクイックソートアルゴリズムを適用すると、最終的に生成される列は自然に順序付き列になります。
分割統治アルゴリズムのアイデアのステップを使用して説明します。
1. 分割ステップ: ベンチマーク番号を選択し、シーケンスをベンチマーク番号より大きい部分とベンチマーク番号より小さい部分に分割します。
2. ガバナンスステップ: サブシーケンスを再帰的に並べ替える
3. 組み合わせステップ: このアルゴリズムにはこのステップがありません。

抽象的な概念では、クイック ソート アルゴリズムを明確に理解することはできません。クイック ソートを明確に理解するために、51CTO フォーラムの投稿から鮮やかな説明を借りてみましょう。

ここで、「6 1 2 7 9 3 4 5 10 8」という 10 個の数字を並べ替えるとします。まず、このシーケンス内の数値を基本番号としてランダムに見つけます。便宜上、最初の数値 6 を基本数値とします。次に、次の配置と同様に、このシーケンス内の基数より大きいすべての数値を 6 の右側に配置し、基数より小さい数値を 6 の左側に配置する必要があります。

3 1 2 5 4 6 9 7 10 8

初期状態では、数字 6 はシーケンスの位置 1 にあります。私たちの目標は、6 をシーケンスの中間の位置 (この位置を k としましょう) に移動することです。ここで、この k を見つけて、k 番目の位置を分割点とする必要があります。左側の数値はすべて 6 以下であり、右側の数値はすべて 6 以上です。
最初のシーケンス「6 1 2 7 9 3 4 5 10 8」の両端から「プローブ」を開始します。まず右から左に 6 未満の数値を見つけ、次に左から右に 6 より大きい数値を見つけて、それらを交換します。ここで 2 つの変数 i と j を使用して、それぞれシーケンスの左端と右端の部分を指すことができます。これら 2 つの変数に「Sentinel i」および「Sentinel j」という素敵な名前を付けます。最初に、センチネル i がシーケンスの一番左側 (つまり i=1) を指し、数字の 6 を指すものとします。センチネル j がシーケンスの右端の部分 (つまり = 10) を指し、数値を指すものとします。

ここに画像の説明を書きます

まずセンチネルJが出動を開始した。ここで設定する参照番号は一番左の番号なので、最初にセンチネル j を送信することが非常に重要です (理由を考えてください)。Sentinel j は、6 未満の数字を見つけて停止するまで、段階的に左に移動します (つまり、j–)。次に、センチネル i は 6 より大きい数値を見つけて停止するまで、右に一歩ずつ移動します (つまり i++)。最後にセントリーjは5番の前で止まり、セントリーiは7番の前で止まりました。

ここに画像の説明を書きます

ここで、センチネル i とセンチネル j が指す要素の値を交換します。交換後の流れは以下の通りです。

6 1 2 5 9 3 4 7 10 8
ここに画像の説明を書きます

この時点で、最初の交換は終了します。次に、セントリー j は左に移動し続けます (注意: セントリー j は毎回最初に開始する必要があります)。彼は 4 を見つけた後で停止しました (これは基本番号 6 より小さく、要件を満たしていました)。センチネル i も右への移動を続け、9 (基本番号 6 よりも大きく、要件を満たしている) を見つけて停止しました。このとき再度交換が行われますが、交換後のシーケンスは以下のとおりです。

6 1 2 5 4 3 9 7 10 8

2回目の交換が終了し、「調査」が続きます。センチネル j は左に移動を続け、3 (基準番号 6 より小さく、要件を満たしている) を見つけて停止しました。センチネル i は右に移動し続けます、おおおお!このときセントリーiとセントリーjが出会い、セントリーiもセントリーjも3になりました。この時点で「検出」が終了することを示します。基数の 6 と 3 を交換します。交換後の流れは以下の通りです。

3 1 2 5 4 6 9 7 10 8
ここに画像の説明を書きます

この時点で、最初の「検出」ラウンドは本当に終了します。このとき、基数の6を分割点とし、6の左側の数字はすべて6以下、右側の数字はすべて6以上になります。今のプロセスを振り返ると、実際には、セントリー j の使命はベンチマーク数値より小さい数値を見つけることであり、セントリー i の使命は、i と j が一致するまでベンチマーク数値より大きい数値を見つけることです。
はい、説明が終わりました。塩基番号 6 が返されたので、それはシーケンス内の位置 6 にあります。この時点で、元の数列は 6 を分割点として 2 つの数列に分割され、左側の数列は「3 1 2 5 4」、右側の数列は「9 7 10 8」になります。次に、これら 2 つのシーケンスを個別に処理する必要があります。6 の左右の配列がまだ非常に混乱しているためです。でも、やり方はマスターしたので、あとは先ほどのやり方をシミュレーションして、6の左と右のシーケンスをそれぞれ処理するだけです。それでは、まず 6 の左側のシーケンスを処理しましょう。
左側のシーケンスは「3 1 2 5 4」です。3 を基数としてこの数列を調整し、3 の左側の数字がすべて 3 以下になり、3 の右側の数字がすべて 3 以上になるようにしてください。さて、書き始めましょう。
シミュレーションが正しければ、調整後のシーケンスの順序は次のようになります。

2 1 3 5 4

OK、これで 3 が元の位置に戻りました。次に、3 の左側のシーケンス「2 1」と右側のシーケンス「5 4」を処理する必要があります。シーケンス「2 1」は 2 に基づいて調整されます。処理後のシーケンスは「1 2」となり、2 は元の位置に戻ります。シーケンス「1」には数値が 1 つだけあり、処理は必要ありません。この時点で、シーケンス「2 1」が完全に処理され、シーケンス「1 2」が得られました。シーケンス「5 4」もこの方法で処理され、最終的に得られるシーケンスは次のようになります。

1 2 3 4 5 6 9 7 10 8

シーケンス「9 7 10 8」については、新しいサブシーケンスを分割できなくなるまで、同じプロセスがシミュレートされます。最終的には、次のようなシーケンスが得られます。

1 2 3 4 5 6 7 8 9 10

この時点で、仕分けは完全に完了します。注意深い学生は、クイック ソートの各ラウンドが実際にはこのラウンドのベンチマーク数値を返すことであることに気づいたかもしれません。すべての数値が返されるまでソートは終了します。次の横暴な図は、アルゴリズム全体の処理プロセスを説明しています。

ここに画像の説明を書きます

おすすめ

転載: blog.csdn.net/NTSDB/article/details/52730753