挿入ソートとバブルソートアルゴリズム


87

いくつかのソートアルゴリズムを理解しようとしていますが、バブルソートと挿入ソートのアルゴリズムの違いを理解するのに苦労しています。

両方ともO(n 2)であることは知っていますが、バブルソートでは、パスごとに配列の最大値が一番上にバブルされ、挿入ソートでは、パスごとに最小値が一番下に沈むように見えます。彼らはまったく同じことをしているのではありませんが、異なる方向に向かっていますか?

挿入ソートの場合、比較/潜在的なスワップの数はゼロから始まり、毎回増加します(つまり、0、1、2、3、4、...、n)が、バブルソートの場合、これと同じ動作が発生しますが、バブルソートは、ソート時に最後の要素と比較する必要がなくなったため、ソート(つまり、n、n-1、n-2、... 0)。

しかし、これらすべてについて、一般的に挿入ソートの方が優れているというコンセンサスのようです。誰か教えてもらえますか?

編集:私は主に、アルゴリズムの効率や漸近的な複雑さではなく、アルゴリズムの動作の違いに関心があります。


1
これは他の場所で十分に文書化されています。たとえば、en.wikipedia.org / wiki / Sorting_algorithmを参照してください。ここで複製するのは無意味であり、良い答えは広大です。
バトシェバ2013年

@Bathsheba賛成した75人と質問を見た88k人は反対しているようです; )
パーサー

@パーサー:ハ!次に、回答を確認する必要があります。現在の最高投票数の回答は役に立ちます。他の人についてはよくわかりません。回答の反対票によって失われたいくつかの担当者ポイントは次のとおりです。受け入れられた答えの「挿入ソートがバブルソートよりも速い理由」という主張は必ずしも真実ではありません。
バトシェバ

@Bathsheba Oh no
パーサー

回答:


41

i番目の反復のバブルソートでは、合計ni-1回の内部反復(n ^ 2)/ 2がありますが、挿入ソートでは、i番目のステップで最大i回の反復がありますが、内部ループを停止できるため、平均してi / 2です。以前、現在の要素の正しい位置を見つけた後。したがって、(0からnまでの合計)/ 2、つまり(n ^ 2)/ 4の合計があります。

そのため、挿入ソートはバブルソートよりも高速です。


2
アルゴリズムの説明はどこでもウェブ上にあると思います。
sasha.sochka 2013年

4
はい、しかしOPはまだメカニズムの違いを捉えていないようです
UmNyobe 2013年

15
さて、私が基本を理解していると仮定することができます。私が欲しかったのは比較でした、そしてこれは本当にとても良いです。つまり、挿入ソートではi番目の要素が沈み、バブルソートではバブルアップしますが、挿入ソートでは最下部にドロップするのではなく、の正しい位置にドロップするだけです。すでにソートされたセクション。したがって、比較/スワップが少なくなります。そうですか?
ミグウェル

2
何?「つまり、(0からnまでの合計)/ 2、つまり(n ^ 2)/ 4の合計です」これには、いくつかのexplが必要です。0 + 1 + 2 + 3 + 4 + 5 = 15; 15/2 = 7.5; 7.5 * 4 = 30; SQRT(30)=ちんぷんかんぷん
ジョン・スミス

@JohnSmith答えにわずかな誤りがあると思います。1からnまでの合計は三角数であるためn *(n + 1)/ 2です。詳細については、三角数を調べてください。したがって、2で割るとn *(n + 1)/ 2になります。
CognizantApe

124

挿入ソート

i回の反復後、最初のi要素が順序付けられます。

各反復で、次の要素は、適切な場所に到達するまで、ソートされたセクションを介してバブルされます。

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要素が最大になり、順序付けられます。

各反復で、ソートされていないセクションをふるいにかけて最大値を見つけます。

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])

外側のループの反復の1つでスワップが行われない場合、通常の実装は早期に終了することに注意してください(つまり、配列がソートされているため)。

挿入ソートでは、ソート要素はソートされたセクションにバブルされますが、バブルソートでは、最大値はソートされていないセクションからバブルされます。


10
おかげで、これは非常に明確です!私が強調する必要があった主なことは、挿入ソートのbreakステートメントは、各反復を早期に終了できることを意味すると思います。つまり、ソートされたセクションでその位置を見つけたときです。バブルソートでは、ソートされていないセクションの最大の要素がソートされたセクションに到達するまでスワッピングを継続する必要があるため、早期に終了することはありません。しかし、それは素晴らしい要約なので、+ 1
Migwell 2013年

4
これが最良の答えだと思います:)
Adelin 2014

2
明確さ、教訓的な値、および各アルゴリズムのメインループ不変条件のプラス1 。複雑さの比較(nの関数として表される)が明示的に含まれていないのは残念ですが、とにかく、これから違いがわかるので、受け入れられたものよりも良い答えだと思います。
Honza Zidek 2015

すべてのステップで挿入擬似コードのアイテムを交換する理由を尋ねることができますか?if(a [j-1]> a [j])then a [j] = a [j-1] ELSE if(a [j-1] <e && a [j]> e)than a [j] = e; break; 、ここで、eはソートする必要のあるアイテムです。このソリューションでは、すでにソートされているアイテムを交換するのではなく、コピーするだけです。少し混乱しているので、説明をお待ちしております。
Karoly 2016

@Karoly、もっとシンプルなので自分のバージョンを選びました。あなたのものは少し速いです、あなたがそれを指摘するのは良いことです。ウィキペディアでは両方のバージョンについて説明しています。
トム

16

もう1つの違いは、ここには表示されませんでした。

バブルソートには、スワップごとに3つの値が割り当てられますあります。値を保存した場所に他のスワップ変数を書き込むよりも、プッシュしたい値(no.1)を保存するために、最初に一時変数を作成する必要があります。 of(no.2)の場合、一時変数を他のスポット(no.3)に書き込む必要があります。変数を正しいスポットにソートするには、スポットごとにこれを行う必要があります(先に進みたい)。

挿入ソートあなたは一時変数のソートにあなたの変数を配置し、限り、あなたはあなたの変数の正しい場所に達すると、後方にそのスポット1点の前にすべての変数を置きます。これにより、スポットごとに1つの値が割り当てられますます。最後に、一時変数をその場に書き込みます。

これにより、値の割り当てもはるかに少なくなります。

これは最強のスピードメリットではありませんが、言及できると思います。

私は理解できると自分自身を表現したことを願っています、そうでなければ、申し訳ありませんが、私は英国人ではありません


1
「そして、すべての変数をそのスポット1スポットの前に後方に配置します」—そして、データをシフトするために、割り当ての負荷も必要としませんか?(データがリンクリストではなく、とにかく連続して保存されていると仮定)
Mark K Cowan

@MarkKCowan、はい、上記のユーザーが言ったように、挿入ソートが「スポット」ごとに割り当てを行う場所です。基本的に、挿入ソートは内側のループに1つの割り当てで記述できますが、バブルソートには内側のループに3つの割り当てがあります。
JSQuareD 2017

9

挿入ソートの主な利点は、オンラインアルゴリズムであるということです。開始時にすべての値を持っている必要はありません。これは、ネットワークやセンサーからのデータを処理するときに役立つ場合があります。

これは他の従来のn log(n)アルゴリズムよりも速いだろうと私は感じています。複雑さは、n*(n log(n))たとえば、ストリーム(O(n))から各値を読み取って保存し、次にすべての値(O(n log(n)))を並べ替えると、O(n^2 log(n))

それどころか、挿入ソートを使用O(n)すると、ストリームから値を読み取りO(n)、値を正しい場所に配置する必要があるため、それO(n^2)だけです。他の利点は、値を格納するためのバッファが不要であり、最終的な宛先でそれらをソートすることです。


データの順序どおりの走査が単に配列をスキャンする以外のものであることが問題ない場合は、その場ではるかに効率的に並べ替えることができます。たとえば、要素を受け取ったら、バイナリツリーに要素を挿入します。これによりO(n log(n))、途中のすべてのステップでソートされたコレクションを持つために実行された合計作業が得られます。(任意の時点での順序どおりの走査はですO(m))。最後にソートされた結果が必要であるが、ソートの計算をデータの転送時間とオーバーラップさせたい場合は、ヒープが適している可能性があります。(そして、挿入ソートのように、その場で機能します)。
ピーターコーデス2017

とにかく、バブルソートも挿入ソートも、O(f(n))複雑さのクラスが実装の詳細や一定の要因よりも重要になるほど大きな問題サイズがあるため、これには理想的ではありません。
ピーターコーデス2017

訂正:ヒープはこれには適していません。ソートされた順序で要素を削除すると、ほとんどのソート作業が実行されます。そのため、成長は非常に安価です。ここでの目標は、最後の要素が到着するまでにほとんどの作業を完了することです。
ピーターコーデス2017

とにかく、n挿入のためにソートされた配列を維持する必要がある場合、実際には、ソートされていない要素が1つ上にある、ほぼソートされた配列をソートするのに最適なアルゴリズムに要約されます。多くのO(n log(n))ソートアルゴリズムはO(n)ほとんどソートされている場合であるため、sum(M=1..n, O(M * log(M)) )作業が必要になるとは限りません。それは確かにそうO(n^2 log(n))ですが、アルゴリズムを正しく選択すれば、それらはO(n^2)完全な作業になります。ただし、これには挿入ソートが最も効率的です。
ピーターコーデス2017

7

バブルソートは、ソートされた要素のグローバルな最大値を実際に追跡しないため、オンラインではありません(アイテムの数がわからないと入力のストリームをソートできません)。アイテムを挿入するときは、最初からバブリングを開始する必要があります


5

誰かが多数のリストから上位k個の要素を探している場合にのみ、バブルソートは挿入ソートよりも優れています。つまり、k回の反復後のバブルソートでは、上位k個の要素が取得されます。ただし、挿入ソートでk回繰り返した後は、それらのk個の要素が確実にソートされるだけです。


2

どちらのソートもO(N ^ 2)ですが、挿入ソートでは非表示の定数がはるかに小さくなります。非表示の定数は、実行されたプリミティブ操作の実際の数を示します。

挿入ソートの方が実行時間が長いのはいつですか?

  1. 配列はほぼソートされています-この場合、挿入ソートはバブルソートよりも少ない操作を実行することに注意してください。
  2. 配列のサイズは比較的小さいです:現在の要素を配置するために要素を移動する挿入ソート。これは、要素の数が少ない場合にのみバブルソートよりも優れています。

挿入ソートは必ずしもバブルソートよりも優れているとは限らないことに注意してください。両方の世界を最大限に活用するには、配列のサイズが小さい場合は挿入ソートを使用し、大きな配列の場合はマージソート(またはクイックソート)を使用できます。


2
要素の数が少なくない場合、バブルソートはどのように優れているでしょうか?私の理解では、ISでスライドするか、BSでスワップするかは、要素の数ではなく、比較する要素が大きい(IS)か小さい(BS)かによって異なります。間違っていたら訂正してください。
ムスタファ

1

各反復でのスワップの数

  • 挿入ソートは、各反復で最大1つのスワップを実行します
  • バブルソートは、各反復で0からnのスワップを実行します。

ソートされた部分へのアクセスと変更

  • 挿入ソートは、ソートされた部分にアクセス(および必要に応じて変更)して、考慮している数値の正しい位置を見つけます。
  • 最適化されると、バブルソートはすでにソートされているものにアクセスしません。

オンラインかどうか

  • 挿入ソートはオンラインです。つまり、挿入ソートは、適切な位置に配置される前に、一度1つの入力を受け取ります。だけを比較する必要はありませんadjacent-inputs
  • バブルソートはオンラインではありません。一度に1つの入力を操作することはありません。各反復で入力のグループ(すべてではないにしても)を処理します。バブルソートadjacent-inputs、各反復で比較と交換のみを行います。

0

バブルソートは、すべての状況でほとんど役に立たない。挿入ソートのスワップ数が多すぎるユースケースでは、スワップのN回未満が保証されるため、選択ソートを使用できます。選択ソートはバブルソートよりも優れているため、バブルソートにはユースケースがありません。


0

挿入ソート:

1.挿入ソートではスワッピングは必要ありません。

2.挿入ソートの時間計算量は、最良の場合はΩ(n)、最悪の場合はO(n ^ 2)です。

3.バブルソートと比較して複雑さが少ない。

4.例:図書館に本を挿入し、カードを配置します。

バブルソート:1。バブルソートでは交換が必要です。

2.バブルソートの時間計算量は、最良の場合はΩ(n)、最悪の場合はO(n ^ 2)です。

3.挿入ソートと比較してより複雑。


1
なぜスワッピングが不要なのですか?要素を交換して、要素を正しい位置に配置します。そして、私はバブルソートがもっと複​​雑だとは言いません。
パーサー

-1

挿入ソートは、「最初の位置(最小)にあるはずの要素を探し、次の要素をシフトしてスペースを作り、最初の位置に置く。良い。次に、2番目にあるはずの要素を見てください。 ... "など...

バブルソートの動作は異なり、「順序が間違っている隣接する要素が2つ見つかった場合は、それらを交換しますとして再開できます。


これは挿入ソートには役立ちますが、バブルソートの説明には実際のループが含まれていないため、実際に比較することはできません。挿入ソートにも効果的にルールがあります。順序が間違っている2つの隣接する要素を見つけた場合は、それらを交換します。ループの動作方法が異なります。
ミグウェル2013年

3
その選択ソートではありませんか?
ハロルド2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.