主要なソートアルゴリズムのパフォーマンス比較とデモンストレーション例

主要なソートアルゴリズムのパフォーマンス比較とデモンストレーション例

ソートとは、もともと無秩序だったシーケンスを、順序のあるシーケンスに並べ替えることを意味します。

ソート方法には安定性が関係しています。いわゆる安定性とは、ソートするシーケンスに 2 つ以上の同一の項目がある場合、ソートの前後でこれらの同一の項目の相対的な位置がチェックされ、変化があるかどうかが調べられることを意味します。変化がない場合、ソート方法は安定しています。変化がある場合、ソート方法は不安定であることを意味します。

レコード内のキーワードが繰り返されない場合、ソート結果は一意であり、選択したソート方法が安定しているかどうかは問題ではありません。キーワードが繰り返される場合、ソート方法を選択するときに、特定のニーズに基づいて安定したソート方法を選択するか、不安定なソート方法を選択するかを検討する必要があります。では、どのソートアルゴリズムが不安定なのでしょうか?

「高速、一部、選択ヒープ」: 「高速」はクイック ソート、「一部」はシェル ソート、「選択」は選択ソート、「ヒープ」はヒープ ソートを指します。つまり、これら 4 つのソート方法は不安定であり、その他のソート方法は自然に安定しています。

ソートアルゴリズムの分類

1. 挿入ソート

つまり、すでに整列したシーケンスに新しいレコードを挿入することは、軍事訓練で整列するようなものです。すでに列が形成されており、そこに新しいメンバーが加わると、その新しいメンバーはチーム内の適切な位置に「挿入」されます。このタイプのソートには、直接挿入ソート、バイナリ挿入ソート、シェル ソートが含まれます。

2. 取引所の仕分け

このタイプの方法の核心は「交換」です。つまり、各ソートは一連の「交換」アクションを通じて完了します。たとえば、軍事訓練の列に並んでいるとき、インストラクターは次のように言います。「あなたは隣の人よりも背が高いです。あなたたち2人は交換してください。それでも隣の人よりも背が高い場合は、交換を続けます。」このタイプのソートには、バブルソートとクイックソートが含まれます。

3. クラスソートを選択

この方法の核となるのは「選択」です。つまり、ソート処理のたびに最小 (または最大) のレコードが選択され、シーケンス内の最初の (または最後の) レコードと交換され、最小 (または最大) のレコードが配置されます。例えば、軍事訓練のために整列するとき、教官は最も小さい生徒を選び、最後の位置にいる生徒と位置を交換するように指示し、残りの生徒は選択を続けます。このタイプのソートには、選択ソートとヒープソートが含まれます。

4. マージクラスのソート

いわゆるマージとは、2 つ以上の順序付けられたシーケンスを新しい順序付けられたシーケンスに結合することです。例えば、軍事訓練で整列する際、教官は次のように言っています。「まず、全員が隣の人とペアになり、そのグループの中に並びます。そのペアと隣のペアは4人組になり、そのグループの中に並びます。これを繰り返し、すべての生徒が1つのグループに統合されて整列します。」このタイプのソートには、(双方向) マージ ソートが含まれます。

5. カーディナリティソート

このタイプの方法は非常に特殊です。これは、論理キーワードを複数のキーワードに分割する、マルチキーワードソートの考え方に基づいています。たとえば、トランプのデッキは、基数ソートの考え方に従って最初にスーツでソートし、次に 4 つの山に分けることができます。次に、各山を AK の順序でソートして、最終的にトランプのデッキ全体が整列するようにします。

ソートアルゴリズム分析

この記事で分析する主なソートアルゴリズムは、バブルソート、選択ソート、挿入ソート、シェルソート、クイックソート、マージソート、ヒープソートです。

交換アルゴリズム

ほとんどのソート アルゴリズムは 2 つのレコードを交換するアクションを使用するため、さまざまなソート アルゴリズムの使用を容易にするために、交換アクションは個別にカプセル化されます。

  1. //スワップ関数 
  2. Array.prototype.swap = 関数(i, j) {
  3. var temp = this [i];
  4. これ[i] =これ[j];
  5. this [j] = 一時;
  6. }

挿入ソート

アルゴリズムのアイデア: 各ラウンドで、ソートするキーワードは、挿入が完了するまで、そのキーワード値のサイズに応じて、ソートされた部分シーケンスの適切な位置に挿入されます。

  1. // ソートを挿入 
  2. Array.prototype.insertionSort = 関数() {
  3. (var i = 1 ; i < this .length; ++i)の場合
  4. {
  5. var j = i,
  6. 値 = this [i];
  7. (j > 0 && this [j - 1 ] > 値)の間
  8. {
  9. これ[j] =これ[j - 1 ];
  10. --j;
  11. }
  12. this [j] = 値;
  13. }
  14. }

アルゴリズムのパフォーマンス: 内部ループでは、this[j]=this[j-1]が基本操作です。最悪の場合、つまりシーケンス全体が逆順である場合、基本操作の実行回数は合計で n*(n-1)/2 となり、時間の計算量は O(n*n) となります。最良のケース、つまりシーケンス全体がすでに順序付けられている場合、ループ内の操作はすべて一定レベルであり、その時間計算量は O(n) であるとします。したがって、このアルゴリズムの平均時間計算量は O(n*n) です。このアルゴリズムでは追加の値が 1 つだけ必要なので、空間計算量は O(1) です。

シェルソート

アルゴリズムのアイデア: シェル ソートは縮小増分ソートとも呼ばれ、ソートするシーケンスを特定の規則に従っていくつかのサブシーケンスに分割し、これらのサブシーケンスを個別に挿入してソートします。この規則は増分です。たとえば、5、3、1 の増分を使用してシーケンスを分割し、各シェル ソートの増分を徐々に減らすことができます。シェル ソートの各ソートにより、シーケンス全体がより整然としたものになります。シーケンス全体が基本的に整然としたら、別の挿入ソートを使用すると、より効率的になります。これがシェル ソートの考え方です。

  1. // シェルソート 
  2. Array.prototype.shellSort = 関数() {
  3. (var step = this .length >> 1 ; step > 0 ; step >>= 1 )の場合
  4. {
  5. (var i = 0 ; i < ステップ; ++i)の場合
  6. {
  7. (var j = i + step; j < this .length; j += step)の場合
  8. {
  9. var k = j、値 = this [j];
  10. while (k >= ステップ && this [k - ステップ] > 値)
  11. {
  12. this [k] = this [k - ステップ];
  13. k -= ステップ;
  14. }
  15. this [k] = 値;
  16. }
  17. }
  18. }
  19. }

アルゴリズムのパフォーマンス: シェルソートの平均時間計算量は O(nlogn) で、空間計算量は O(1) です。シェルソートで増分を取るときは、まず増分シーケンスの最後の値が 1 でなければならないことに注意してください。次に、増分シーケンスの値には 1 以外の共通因数がないことが必要です。たとえば、8、4、2、1 のようなシーケンスは取らないでください (共通因数は 2 です)。

バブルソート

アルゴリズムの考え方: 一連の「交換」アクションによって完了します。まず、最初のレコードが 2 番目のレコードと比較されます。最初のレコードの方が大きい場合は、2 つのレコードが交換され、そうでない場合は交換されません。次に、2 番目のレコードが 3 番目のレコードと比較されます。2 番目のレコードの方が大きい場合は、2 つのレコードが交換され、そうでない場合は交換されません。最後に、最初のレコードが最後のレコードと交換され、バブル ソートが完了します。この過程で、大きなレコードは石のように底に沈み、小さなレコードは徐々に浮かび上がってきます。バブルソートアルゴリズムが終了する条件は、1 回のソートパスで要素の交換が発生しないことです。

  1. //バブルソート 
  2. Array.prototype.bubbleSort = 関数() {
  3. (var i = this .length - 1 ; i > 0 ; --i)の場合
  4. {
  5. (var j = 0 ; j < i; ++j)の場合
  6. もし( this [j] > this [j + 1 ])
  7. これを.swap(j, j + 1 );
  8. }
  9. }

アルゴリズムのパフォーマンス: 最も内側のループでの要素交換操作は、アルゴリズムの基本的な操作です。最悪の場合、ソートするシーケンスが逆順になっていると、基本操作の実行回数は合計で (n-1+1)*(n-1)/2=n(n-1)/2 となり、時間の計算量は O(n*n) になります。最良の場合、ソートするシーケンスが順序どおりになっていると、時間の計算量は O(n) となり、平均的な場合の時間の計算量は O(n*n) になります。アルゴリズムの追加の補助空間は交換に使用される 1 つのテンポラリのみなので、空間計算量は O(1) です。

クイックソート

アルゴリズムのアイデア: 軍事訓練の列を例にとると、インストラクターは、*** 番目の生徒が中央に立ち、彼より背の低い生徒は彼の左側に、背の高い生徒は彼の右側に立つように指示します。これはクイック ソートです。したがって、クイックソートでは、ピボットを使用してシーケンスを 2 つの部分に分割します。ピボットの片側はピボットより小さく (またはそれ以下)、もう片側はピボットより大きくなります (またはそれ以上)。

  1. // 再帰クイックソート 
  2. Array.prototype.quickSort = function(s, e) {
  3. s == null場合
  4. s = 0 ;
  5. e == null場合
  6. e = this .length - 1 ;
  7. もし(s >= e)
  8. 戻る;
  9. これは.swap((s + e) ​​>> 1 , e);
  10. var インデックス = s - 1 ;
  11. (var i = s; i <= e; ++i)の場合
  12. this [i] <= this [e] の場合this .swap(i, ++index) ;
  13. this .quickSort(s, index - 1 );
  14. これは.quickSort(index + 1 , e);
  15. }

アルゴリズムのパフォーマンス: クイック ソートの時間計算量は、最良の場合で O(nlogn) です。ソートするシーケンスが無秩序に近いほど、アルゴリズムは効率的になります。最悪の場合、時間計算量は O(n*n) です。ソートするシーケンスが順序に近いほど、アルゴリズムの効率は低くなります。アルゴリズムの平均時間計算量は O(nlogn) です。平均時間で見ると、クイックソートはすべてのソートアルゴリズムの中で最も高速です。このアルゴリズムの空間計算量は O(logn) です。クイック ソートは再帰的に実行され、スタックの支援を必要とするため、以前のソート方法よりも多くの補助スペースが必要になります。

クイックソートの効率は、選択した「ピボット」に関係しています。選択したピボットが中央値に近いほど、アルゴリズムの効率が高くなります。したがって、アルゴリズムの効率を向上させるために、最初に「ピボット」を選択するときに、サンプリングと同様に、データパイルからランダムに 3 つの値を選択し、その 3 つの値の平均を「ピボット」として取得するなど、いくつかの変更を加えることができます。クイックソートアルゴリズムの効率を向上させる方法については、この記事では詳しく説明せず、ここで終わります。 (興味のある読者は自分で調べてください)

選択ソート

アルゴリズムのアイデア: このアルゴリズムの主なアクションは「選択」です。単純な選択方法を使用して、シーケンスを最初から最後までスキャンし、最小のレコードを見つけて最初のレコードと交換し、残りのレコードからこの選択と交換を続行して、最終的にシーケンスを順序付けます。

  1. //並べ替えを選択 
  2. Array.prototype.selectionSort = 関数() {
  3. (var i = 0 ; i < this .length; ++i)の場合
  4. {
  5. var インデックス = i;
  6. (var j = i + 1 ; j < this .length; ++j)の場合
  7. {
  8. if ( this [j] < this [index])
  9. インデックス = j;
  10. }
  11. これを.swap(i, インデックス);
  12. }
  13. }

アルゴリズムのパフォーマンス: 最も内側のループの比較を基本操作とすると、その実行時間は (n-1+1)*(n-1)/2=n(n-1)/2 となり、時間計算量は O(n*n) となります。このアルゴリズムには temp という余分なスペースが 1 つだけあるため、スペース計算量は O(1) となります。

ヒープソート

アルゴリズムの考え方: ヒープはデータ構造です。ヒープを理解する最も良い方法は、完全な二分木として考えることです。この完全な二分木は、葉以外のノードの値が、その左と右の子ノードの値より大きくない (または小さくない) という条件を満たします。父親が年上で子供が年下の場合、そのようなヒープは大きなトップヒープと呼ばれます。父親が年下で子供が年上の場合、そのようなヒープは小さなトップヒープと呼ばれます。ヒープ定義によれば、ルートノードの値が最大(または最小)であるため、順序付けされていないシーケンスをヒープに調整することで、シーケンスの最大(または最小)値を見つけ、見つかった値をシーケンスの最大(または先頭)の値と交換できます。このようにして、順序付けされたシーケンスの要素数は 1 増加し、順序付けされていないシーケンスの要素数は 1 減少します。この操作を新しい順序付けされていないシーケンスに対して繰り返すと、シーケンスのソートが実現されます。ヒープソートにおける最も重要な操作は、シーケンスをヒープに調整することです。ソートプロセス全体は、ヒープの定義に準拠していない完全なバイナリツリーを、ヒープの定義に準拠した完全なバイナリツリーに継続的に調整するプロセスです。

ヒープソート実行プロセス(大きなトップヒープ):

(1)順序付けられていないシーケンスによって決定された完全な二分木の最初の非葉ノードから始めて、各ノードを右から左へ、下から上に調整すると、最終的に大きなトップヒープが得られます。現在のノード (a) の値をその子ノードと比較します。値が a より大きい子ノードがある場合は、その最小値を選択して a と交換します。 a が次の層に来ると、a の子ノードの値がすべて a の値よりも小さくなるまで上記のプロセスが繰り返されます。

(2)現在の順序なしシーケンスの最初の要素(ツリーのルートノード(a))を、順序なしシーケンスの最後の要素(b)と交換します。 a は順序付きシーケンスに入り、最終位置に到達します。順序なしシーケンスの要素は 1 減少し、順序付きシーケンスの要素は 1 増加します。このとき、ノード b のみがヒープ定義を満たさない可能性があるため、調整されます。

(3)順序なしシーケンスに要素が1つだけ残るまで手順2を繰り返します。

  1. //ヒープソート 
  2. Array.prototype.heapSort = 関数() {
  3. (var i = 1 ; i < this .length; ++i)の場合
  4. {
  5. (var j = i, k = (j - 1 ) >> 1 ; k >= 0 ; j = k, k = (k - 1 ) >> 1 )の場合
  6. {
  7. もし(これ[k] >=これ[j])
  8. 壊す;
  9. これを.swap(j, k);
  10. }
  11. }
  12. (var i = this .length - 1 ; i > 0 ; --i)の場合
  13. {
  14. これを.swap( 0 , i);
  15. (var j = 0 、 k = (j + 1 ) << 1 ; k <= i; j = k、 k = (k + 1 ) << 1 )の場合
  16. {
  17. (k == i || this [k] < this [k - 1 ])の場合
  18. --k;
  19. もし(これ[k] <=これ[j])
  20. 壊す;
  21. これを.swap(j, k);
  22. }
  23. }
  24. }

アルゴリズムのパフォーマンス: 完全な二分木の高さは [log(n+1)] です。つまり、各ノードを調整する時間の計算量は O(logn) です。基本操作の総数は、2 つの並列ループの基本操作の数の合計です。アルゴリズム全体の時間の計算量は O(logn)*n/2+O(logn)*(n-1)、つまり O(nlogn) です。余分なスペースは temp だけなので、スペースの複雑さは O(1) です。

ヒープソートの利点は、1,000,000 件のレコードから上位 10 件の小さいレコードを選択するなど、レコード数が多いシナリオに適していることです。この場合、ヒープソートが最適です。レコード数が少ない場合は、ヒープソートは推奨されません。また、ハッシュテーブル + ヒープソートは、大量データの処理に最適な組み合わせです。大量データ処理については、今後のブログ投稿で紹介する予定です。

マージソート

アルゴリズムのアイデア: その核心は「2 つずつマージ」です。まず、元のシーケンスを、それぞれ 1 つの要素のみを含むサブシーケンスと見なします。2 つずつマージして、順序付けられた 2 つのタプルをいくつか形成します。これで、マージ ソートの最初のラウンドが完了します。次に、このシーケンスをいくつかの 2 つのタプルのサブシーケンスと見なします。2 つずつマージを続けて、順序付けられた 4 つのタプルをいくつか形成します。これで、マージ ソートの 2 回目のラウンドが完了します。以下同様に続きます。サブシーケンスが 2 つだけになったら、もう一度マージしてマージ ソート全体を完了します。

  1. //マージソート 
  2. Array.prototype.mergeSort = 関数(s, e, b) {
  3. s == null場合
  4. s = 0 ;
  5. e == null場合
  6. e = this .length - 1 ;
  7. b == null場合
  8. b =新しい配列( this .length);
  9. もし(s >= e)
  10. 戻る;
  11. var m = (s + e) ​​>> 1 ;
  12. これは.mergeSort(s, m, b);
  13. これは.mergeSort(m + 1 , e, b);
  14. (変数 i = s、j = s、k = m + 1 ; i <= e; ++i)の場合
  15. b[i] = this [(k > e || j <= m && this [j] < this [k]) ? j++ : k++];
  16. (var i = s; i <= e; ++i)の場合
  17. これは[i] = b[i]です。
  18. }

アルゴリズムのパフォーマンス: 基本操作として「マージ操作」を選択できます。「マージ操作」は、マージするテーブル内の要素を、マージ結果を格納するテーブルにコピーするプロセスです。回数は、マージする 2 つのサブシーケンス内の要素数の合計です。このアルゴリズムは合計で logn 回のソート パスを実行する必要があり、各ソート パスでは n 個の基本操作が実行されます。したがって、マージ ソート全体で実行される基本操作の合計数は nlogn です。つまり、時間の計算量は O(nlogn) です。つまり、マージ ソートの時間計算量は初期シーケンスに依存しません。マージソートではソートするシーケンス全体を転送する必要があるため、空間計算量は O(n) になります。

いくつかの結論

(1)クイックソート、シェルソート、マージソート、ヒープソートの平均時間はO(nlogn)であり、その他の平均時間はO(n*n)である。

(2)クイックソート、シェルソート、選択ソート、ヒープソートは不安定であるが、その他は安定している。

(3)バブルソート、クイックソート、選択ソート、ヒープソートは、1回のソートパスで要素が最終位置に到達することを保証できるソートである。

(4)選択ソートとバイナリ挿入ソートは、要素の比較回数が元の順序に依存しないソートである。

(5)ソートパスの数は、元のシーケンス(交換型ソート)と関連している。

(6)直接挿入ソートと二分挿入ソートの違いは挿入位置を見つける方法である。一方は順次探索法であり、もう一方は二分探索法である。

<<:  アルゴリズムの視覚化: 理解しにくいコードをゴッホの星空に描く

>>:  ディープラーニングの深層: モデリング知識とオープンソースツールのオプション

ブログ    
ブログ    

推薦する

...

...

...

「データオープン化」の道で、百度アポロはウェイモをリード

6月17日、世界最大のコンピュータービジョンカンファレンスであるCVPRの自動運転セミナーにおいて、...

TensorFlow、危険です! Google自身が放棄している

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

メタバースを強化してインテリジェントなインタラクションの新たな未来を切り開く

4月23日、51CTO主催の「MetaConメタバーステクノロジーカンファレンス2022」がオンライ...

2020年にスパムはなくなるでしょうか?

16 年前、ビル・ゲイツはスパムの問題は 2006 年までに解決すると約束しました。 2020 年...

ナレッジグラフの紹介と応用

[[376661]]人間は知識を獲得する過程で、物事の本質にますます注意を払うようになります。人工知...

ジャック・マー氏:中国のAIは必ず米国のAIを上回る。ゲイツ氏は米国がボスだと反論した。

周知のとおり、AI はテクノロジー業界の次のトレンドとなっており、このトレンドは世界規模です。そこで...

ChatGPT-4、Bard、Claude-2、Copilot空間タスクの正確性の比較

大規模言語モデル (LLM) を含む生成 AI は、エンコード、空間計算、サンプル データ生成、時系...

Baidu が DeepVoice の最終バージョンをリリース: 10,000 人の声を真似て 30 分でアクセントを習得

今年初め、検索大手の百度は、人気のディープラーニング技術を使用してテキスト読み上げ(TTS)変換を実...

ブロックチェーン + AI、完璧な組み合わせですね?

「この二つの技は同じ名前だが、技の内容は大きく異なる。一つは全真剣術の強力な技で、もう一つは玉女剣...

清華大学と北京大学は確実にトップ20に入っています!世界のAI研究の年間ランキングが発表され、中国と米国の間には大きな差がある

さらに、テクノロジー業界に特化したベンチャーキャピタル企業であるサンダーマーク・キャピタルは、毎年こ...

OpenAI の危機は解決されましたが、人工知能の未来はどこに向かうのでしょうか?

OpenAI は、人工知能 (AI) の作成と推進を専門とする非営利団体です。そのビジョンは、人間...

クラウドとSaaSのセキュリティには包括的なアプローチが必要

米国国土安全保障省および米国国税庁の元最高情報責任者であり、現在は Learning Tree In...