いくつかのソートアルゴリズムを理解しようとしていますが、バブルソートと挿入ソートアルゴリズムの違いを見つけるのに苦労しています。
両方ともO(n2)、しかし、バブルソートは各パスの配列の最大値を単に上にバブルし、挿入ソートは各パスの最下部に単に最小値をシンクするように思えます。彼らはまったく同じことをしていませんが、方向が異なりますか?
挿入ソートの場合、比較/潜在的なスワップの数はゼロから始まり、毎回増加します(つまり、0、1、2、3、4、...、n)が、バブルソートの場合も同じ動作が起こりますが、ソート(つまり、n、n-1、n-2、... 0)。バブルソートは、ソート時に最後の要素と比較する必要がなくなるためです。
しかし、これらすべてのために、挿入ソートは一般的に優れているというコンセンサスがあるようです。誰に理由を教えてもらえますか?
編集:主に、アルゴリズムの動作の違いに興味があります。効率や漸近的な複雑さではありません。
I番目の反復のバブルソートでは、ni-1個の内部反復(n ^ 2)/ 2合計がありますが、挿入ソートでは、i番目のステップで最大i個の反復がありますが、内部ループを停止できるため、平均でi/2です以前、現在の要素の正しい位置を見つけた後。したがって、(合計は0からn)/ 2(n ^ 2)/ 4合計です。
そのため、挿入ソートはバブルソートよりも高速です。
i反復後、最初のi要素が順序付けられます。
各反復で、次の要素はsortedセクションを介して適切な場所に到達するまでバブルされます。
sorted | unsorted
1 3 5 8 | 4 6 7 9 2
1 3 4 5 8 | 6 7 9 2
4はソートされたセクションにバブルされます
擬似コード:
for i in 1 to n
for j in i downto 2
if array[j - 1] > array[j]
swap(array[j - 1], array[j])
else
break
i反復の後、最後のi要素が最大で、順序付けされています。
各反復でnsortedセクションをふるいにかけて、最大値を見つけます。
unsorted | biggest
3 1 5 4 2 | 6 7 8 9
1 3 4 2 | 5 6 7 8 9
5はソートされていないセクションからバブルアウトされます
擬似コード:
for i in 1 to n
for j in 1 to n - i
if array[j] > array[j + 1]
swap(array[j], array[j + 1])
(配列がソートされることを意味するため)外側のループのいずれかの反復中にスワップが行われない場合、典型的な実装は早期に終了することに注意してください。
挿入では、ソート要素はソートされたセクションにバブルされ、バブルソートでは、最大値がソートされていないセクションからバブルアウトされます。
別の違いは、私はここでは見ませんでした:
バブルソートにはスワップごとに3つの値の割り当て:プッシュフォワードしたい値(1番)を保存するために、まず一時変数を作成する必要があります。 (no.2)の値を保存したばかりのスポットに他のスワップ変数を書き込みます。その後、他のスポット(no.3)のスポットに一時変数を書き込む必要があります。変数を正しいスポットに並べ替えるには、各スポットでこれを行う必要があります(前進したい)。
挿入ソートを使用すると、変数を一時変数にソートし、変数の正しいスポットに到達する限り、すべての変数をそのスポットの前に1スポット後方に配置します。 スポットごとに1つの値の割り当てになります。最後に、一時変数をスポットに書き込みます。
それにより、価値の割り当てもはるかに少なくなります。
これは最速のスピードベネフィットではありませんが、言及できると思います。
私は理解できると表明したいと思います。
挿入ソートの主な利点は、オンラインアルゴリズムであることです。開始時にすべての値を持つ必要はありません。これは、ネットワークまたは何らかのセンサーからのデータを処理するときに役立ちます。
これは、他の従来のn log(n)
アルゴリズムよりも高速になると感じています。複雑さはn*(n log(n))
になるためです。ストリーム(O(n)
)から各値を読み取り/保存し、すべての値(O(n log(n))
)をソートしてO(n^2 log(n))
になります
それどころか、Insert Sortを使用するには、ストリームから値を読み取るためにO(n)
と、値を正しい場所に置くためにO(n)
が必要です。したがって、O(n^2)
のみです。他の利点は、値を保存するためのバッファが不要で、最終的な宛先でソートすることです。
バブルソートはオンラインではありません(アイテムの数がわからないと入力のストリームをソートできません)。これは、ソートされた要素のグローバルな最大値を実際に追跡しないためです。アイテムが挿入されたら、最初からバブルを開始する必要があります
誰かが大きな数のリストから上位k個の要素を探している場合のみ、つまり、k回の反復後のバブルソートでは、上位k個の要素が得られます。ただし、挿入ソートでk回繰り返した後は、それらのk個の要素が確実にソートされるだけです。
バブルソートは、あらゆる状況でほとんど役に立ちません。挿入ソートでスワップが多すぎる場合のユースケースでは、N回未満のスワップが保証されるため、選択ソートを使用できます。選択ソートはバブルソートよりも優れているため、バブルソートにはユースケースがありません。
挿入ソート:
1.挿入ではソートの入れ替えは不要です。
2.挿入ソートの時間の複雑さは、最良の場合はΩ(n)、最悪の場合はO(n ^ 2)です。
3.バブルソートに比べて複雑さが少ない。
4.例:図書館に本を挿入し、カードを整理します。
バブルソート:1.バブルソートではスワップが必要です。
2.バブルソートの時間の複雑さは、最良の場合はΩ(n)、最悪の場合はO(n ^ 2)です。
3.挿入ソートと比較してより複雑。
どちらのソートもO(N ^ 2)ですが、挿入ソートでは隠された定数ははるかに小さくなります。隠された定数は、実行されるプリミティブ操作の実際の数を指します。
挿入ソートの実行時間が改善されるのはいつですか?
挿入ソートは常にバブルソートよりも優れているとは限らないことに注意してください。両方の利点を最大限に活用するには、配列のサイズが小さい場合は挿入ソートを使用し、より大きな配列のソート(またはクイックソート)をマージできます。
adjacent-inputs
のみを比較する必要はありません。adjacent-inputs
のみを比較および交換.挿入ソートは、「最初の位置(最小)にある要素を探し、次の要素をシフトしてスペースを空け、最初の位置に配置します。良い。今、すべき要素を見てください。 2番目にある...など...
バブルソートの動作は異なるため、「順序が間違っている2つの隣接する要素を見つけた場合は、それらを入れ替えます」として再開できます。