JavaScript における一般的なソートアルゴリズムの詳細な説明

JavaScript における一般的なソートアルゴリズムの詳細な説明

諺にこうあります:

雷鋒が雷鋒塔を倒し、Java が JavaScript を実装します。

Java に頼って普及しようとしていた JavaScript (当初は LiveScript と呼ばれていました) は、当時名前を変えて、今ではとても普及しています。 Node.js の登場により、JavaScript をフロントエンドとバックエンドの両方で使用できるようになりました。 Java は依然としてエンタープライズ ソフトウェア開発の分野で優位に立っていますが (C/C++ の達人の方々、私を攻撃しないでください...)、Web の世界では JavaScript が比類なくトップの座を占めています。

しかし、コンピュータ アルゴリズムとデータ構造の従来の分野では、ほとんどの専門的な教科書や書籍のデフォルト言語は Java または C/C++ です。最近、アルゴリズムとデータ構造に関する知識を深めようとしており、JavaScript をデフォルト言語として使用するアルゴリズムの本を探していたため、これが私にとっては少々問題となっていました。 O'REILLYのAnimalシリーズに「JavaScriptで記述するデータ構造とアルゴリズム」という本があることを知り、ワクワクしながら2日間かけて最初から最後まで読みました。これはフロントエンド開発者向けの非常に優れたアルゴリズム入門書です。しかし、大きな欠点があります。それは、明らかな小さな誤りが多数あり、転職した私のようなプログラマーでも一目でわかるほど明らかな誤りです。もう 1 つの問題は、この本では多くの重要なアルゴリズムとデータ構造の知識が説明されていないことです。重度の強迫性障害の患者である私にとって、これらの問題は耐え難いものです。そこで、意見の相違があったときに、私は情報を探して自分でアルゴリズムを要約することにしました。さて、アルゴリズムの分野で最も基本的な知識であるソートアルゴリズムから始めましょう。

以下のコードには、自分では見つけられないバグやエラー、文法上の不規則性があるはずだと考えています。そのため、専門家にエラーを指摘してもらいたいと思っています。継続的に修正することによってのみ、長期的な進歩を遂げることができるからです。

古典的なアルゴリズムのトップ10

図で要約すると次のようになります。

用語集:

n: データサイズ

k: 「バケット」の数

インプレース: 一定のメモリを占有し、追加のメモリを占有しない

アウトプレース: 余分なメモリを消費する

安定性: ソート後の2つの等しいキー値の順序は、ソート前の順序と同じである

バブルソート

最も単純なソートアルゴリズムの 1 つであるバブルソートは、辞書に載っている Abandon と同じような感覚です。常に最初のページにあり、一番最初なので、最も馴染みがあります。 。 。バブルソートには、フラグを設定する最適化アルゴリズムもあります。シーケンスのトラバーサル中に要素が交換されない場合、シーケンスがすでに順序付けられていることが証明されます。しかし、この改善はパフォーマンスの向上にはあまり役立ちません。 。 。

最速はいつですか

入力データがすでに正の順序になっている場合 (すでに正の順序になっているのに、なぜバブルソートが必要なのでしょうか...)

一番遅いのはい​​つですか?

入力データが逆順の場合 (for ループを記述してデータを逆順に出力できるのに、なぜバブル ソートを使用する必要があるのでしょうか。私は自由ですか...)

バブルソートアニメーションのデモンストレーション

JavaScriptコードの実装

  1. 関数bubbleSort(arr) {
  2. var len = arr.length;
  3. (var i = 0; i < len; i++)の場合{
  4. (var j = 0; j < len - 1 - i; j++)の場合{
  5. if (arr[j] > arr[j+1]) { //隣接する要素をペアで比較する
  6. var temp = arr[j+1]; //要素の交換
  7. arr[j+1] = arr[j];
  8. arr[j] =一時;
  9. }
  10. }
  11. }
  12. arrを返します
  13. }

選択ソート

どのようなデータが入力されても時間の計算量は O(n²) であるため、最も安定したソート アルゴリズムの 1 つです。 。 。したがって、使用する場合、データサイズが小さいほど良いです。唯一の利点は、余分なメモリスペースを占有しないことです。

選択ソートアニメーションのデモンストレーション

JavaScriptコードの実装

  1. 関数selectionSort(arr) {
  2.  
  3. var len = arr.length;
  4.  
  5. var minIndex、 temp ;
  6.  
  7. (var i = 0; i < len - 1; i++)の場合{
  8.  
  9. 最小インデックス = i;
  10.  
  11. (var j = i + 1; j < len; j++)の場合{
  12.  
  13. if (arr[j] < arr[minIndex]) { //最小の数値を見つける
  14.  
  15. minIndex = j; //最小数のインデックスを保存する
  16.  
  17. }  
  18. }
  19.  
  20. temp = arr[i];
  21.  
  22. arr[i] = arr[最小インデックス];
  23.  
  24. arr[最小インデックス] = temp ;  
  25. }
  26.  
  27. arrを返します  
  28. }

挿入ソート

挿入ソートのコード実装はバブルソートや選択ソートほど単純で粗雑ではありませんが、その原理は最も理解しやすいはずです。ポーカーをプレイしたことがある人なら誰でも数秒で理解できるはずです。もちろん、ポーカーをプレイしているときにカードをランク​​順に並べることはないと言うのであれば、おそらくこの人生で挿入ソート アルゴリズムに興味を持つことはないでしょう。 。 。

挿入ソートには、バブルソートと同様に、半挿入と呼ばれる最適化アルゴリズムもあります。このアルゴリズムに関しては、教科書からの古典的な引用を使うのは面倒なので、「興味のある学生は授業後に自分で勉強することができます。」 。 。

挿入ソートのアニメーションデモンストレーション

JavaScriptコードの実装

  1. 関数挿入ソート(arr) {
  2.  
  3. var len = arr.length;
  4.  
  5. var preIndex、現在の;
  6.  
  7. (var i = 1; i < len; i++)の場合{
  8.  
  9. プレインデックス = i - 1;
  10.  
  11. 現在の値= arr[i];
  12.  
  13. preIndex >= 0 && arr[preIndex] > current の場合{
  14.  
  15. arr[preIndex+1] = arr[preIndex];
  16.  
  17. プレインデックス--;  
  18.  
  19. }
  20.  
  21. arr[preIndex+1] =現在の;
  22.  
  23. }
  24.  
  25. arrを返します
  26.  
  27. }

シェルソート

シェルソートは挿入ソートのより効率的な実装です。挿入ソートとは異なり、より遠い要素を優先します。シェルソートの核心は、間隔シーケンスの設定にあります。間隔シーケンスは事前に設定することも、動的に定義することもできます。間隔シーケンスを動的に定義するアルゴリズムは、アルゴリズム (第 4 版) の共著者である Robert Sedgewick によって提案されました。ここではこのアプローチを使用します。

JavaScriptコードの実装

  1. 関数shellSort(arr) {
  2.  
  3. var len = arr.length、
  4.  
  5. 温度
  6.  
  7. ギャップ = 1;
  8.  
  9. while(gap < len/3) { //間隔シーケンスを動的に定義する
  10.  
  11. ギャップ = ギャップ*3+1;
  12.  
  13. }
  14.  
  15. ギャップの場合、ギャップ > 0、ギャップ = Math.floor(gap/3)) {
  16.  
  17. ( var i = ギャップ; i < len; i++) {
  18.  
  19. temp = arr[i];
  20.  
  21. (var j = i-gap; j >= 0 && arr[j] > temp ; j-=gap)の場合{
  22.  
  23. arr[j+ギャップ] = arr[j];
  24.  
  25. }
  26.  
  27. arr[j+ギャップ] = temp ;
  28.  
  29. }
  30.  
  31. }
  32.  
  33. arrを返します
  34.  
  35. }

マージソート

分割統治の考え方の典型的なアルゴリズムの応用として、マージソートは次の 2 つの方法で実装されます。

  • トップダウン再帰(すべての再帰メソッドは反復を使用して書き換えることができるため、2 番目のメソッドがあります)
  • ボトムアップ反復

「データ構造とアルゴリズムの JavaScript 記述」では、著者はボトムアップの反復法を紹介しています。しかし、再帰的な方法については、著者は次のように考えています。

ただし、再帰が深すぎて言語が処理できないため、JavaScript ではこれを行うことはできません。

ただし、アルゴリズムの再帰の深さが深すぎるため、JavaScript ではこれは実現できません。

正直に言うと、この文章はよく分かりません。これは、JavaScript コンパイラのメモリが少なすぎて再帰が深すぎるため、メモリ オーバーフローが簡単に発生する可能性があることを意味しますか?偉大な神様が私にアドバイスを与えてくれることを願っています。

選択ソートと同様に、マージソートのパフォーマンスは入力データの影響を受けませんが、時間の計算量が常に O(n log n) であるため、選択ソートよりもはるかに優れたパフォーマンスを発揮します。コストは、必要な追加のメモリスペースです。

マージソートのアニメーションデモンストレーション

マージソートの JavaScript コードの実装:

  1. function mergeSort(arr) { //トップダウン再帰法を使用する
  2.  
  3. var len = arr.length;
  4.  
  5. 長さが2以下の場合
  6.  
  7. arrを返します
  8.  
  9. }
  10.  
  11. var middle = Math.floor(len / 2)、
  12.  
  13. = arr.slice(0, 中央)、
  14.  
  15. = arr.slice(中央);
  16.  
  17. merge(mergeSort(), mergeSort())を返します  
  18. }
  19.  
  20.   
  21.  
  22. 関数merge(,)  
  23. {
  24.  
  25. var 結果 = [];    
  26.  
  27. while (.長さ &&.長さ) {
  28.  
  29. [0] <=[0])の場合{
  30.  
  31. 結果.push(.shift());
  32.  
  33. }それ以外{
  34.  
  35. 結果.push(.shift());
  36.  
  37. }  
  38. }   
  39.  
  40. while (.長さ)
  41.  
  42. 結果.push(.shift());  
  43.   
  44.  
  45. while (.長さ)
  46.  
  47. 結果.push(.shift());  
  48.   
  49.  
  50. 結果を返します
  51.  
  52. }

クイックソート

クイックソートは、ソートアルゴリズムにおける分割統治の考え方のもう 1 つの典型的な応用です。本質的に、クイックソートはバブルソートに基づく再帰的な分割統治法とみなされるべきです。

クイック ソートという名前は単純で大雑把です。この名前を聞いた瞬間に、その存在の意味がわかります。つまり、高速で効率的です。これは、ビッグ データを処理するための最速のソート アルゴリズムの 1 つです。最悪ケースの時間計算量は O(n²) に達しますが、これは優れた結果です。ほとんどの場合、平均時間計算量が O(n log n) のソート アルゴリズムよりも優れたパフォーマンスを発揮します。しかし、その理由はわかりません。 。 。幸いなことに、私の強迫性障害は再発し、多くの情報を確認した後、ついに「アルゴリズム アートおよび情報科学コンテスト」で満足のいく答えを見つけました。

クイックソートの最悪ケースの実行時間は、例えばシーケンシャルシーケンスのクイックソートの場合、O(n²) です。しかし、償却予想時間は O(n log n) であり、O(n log n) 表記法で暗示される定数係数は非常に小さく、複雑性が安定して O(n log n) に等しいマージソートよりもはるかに小さくなります。したがって、弱い順序を持つほとんどの乱数シーケンスでは、クイック ソートがマージ ソートよりも常に優れています。

クイックソートアニメーションのデモンストレーション

クイックソートの JavaScript コードの実装:

  1. 関数quickSort(arr, left , right ) {
  2.  
  3. var len = arr.length、
  4.  
  5. パーティションインデックス、
  6.  
  7. = typeof!= 'number' ? 0 :
  8.  
  9. right = typeof right != 'number' ? len - 1 : right ;
  10.  
  11. <)の場合{
  12.  
  13. パーティションインデックス = パーティション(arr、);
  14.  
  15. クイックソート(arr,, パーティションインデックス-1);
  16.  
  17. クイックソート(arr、パーティションインデックス+1、);
  18.  
  19. }
  20.  
  21. arrを返します
  22.  
  23. }
  24.  
  25. function partition(arr, left , right ) { //パーティション操作
  26.  
  27. var pivot = left , //ピボット値を設定する
  28.  
  29. インデックス= ピボット + 1;
  30.  
  31. (var i =インデックス; i <=; i++) {
  32.  
  33. (arr[i] < arr[pivot])の場合{
  34.  
  35. swap(arr, i,インデックス);
  36.  
  37. インデックス++;
  38.  
  39. }
  40.  
  41. }
  42.  
  43. swap(arr, ピボット,インデックス- 1);
  44.  
  45. 戻る インデックス-1;
  46.  
  47. }
  48.  
  49. 関数swap(arr, i, j) {
  50.  
  51. var temp = arr[i];
  52.  
  53. arr[i] = arr[j];
  54.  
  55. arr[j] =一時;
  56.  
  57. }

ヒープソート

ヒープソートは、ヒープの概念を使用してソートする選択ソートであると言えます。方法は2つあります。

  • 最大トップヒープ: 各ノードの値は、その子ノードの値以上であり、ヒープソートアルゴリズムで昇順でソートするために使用されます。
  • ミニトップヒープ: 各ノードの値は、その子ノードの値以下であり、ヒープソートアルゴリズムの降順のために使用されます。

ヒープソートアニメーションのデモンストレーション

ヒープソートの JavaScript コードの実装:

  1. var len; //宣言された複数の関数はデータ長を必要とするため、lenはグローバル変数として設定されます
  2.  
  3. function buildMaxHeap(arr) { //最大ヒープを構築する
  4.  
  5. len = 配列の長さ;
  6.  
  7. (var i = Math.floor(len/2); i >= 0; i -- ) {  
  8.  
  9. ヒープ化(arr, i);
  10.  
  11. }
  12. }
  13. function heapify(arr, i) { //ヒープ調整
  14.  
  15. var= 2 * i + 1、
  16.  
  17. = 2 * i + 2、
  18.  
  19. 最大 = i;
  20.   
  21.  
  22. if ( left < len && arr[ left ] > arr[largest]) {
  23.  
  24. 最大 =;
  25.  
  26. }
  27.  
  28. if ( right < len && arr[ right ] > arr[largest]) {
  29.  
  30. 最大 =;
  31.  
  32. }
  33.  
  34. (最大 != i)の場合{
  35.  
  36. swap(arr, i, 最大);
  37.  
  38. ヒープ化(arr, 最大);
  39. }
  40. }
  41.  
  42. 関数swap(arr, i, j) {
  43.  
  44. var temp = arr[i];
  45.  
  46. arr[i] = arr[j];
  47.  
  48. arr[j] =一時;
  49.  
  50. }
  51.  
  52. 関数heapSort(arr) {
  53.  
  54. ビルドMaxHeap(arr);
  55.  
  56. (var i = arr.length-1; i > 0; i --) {  
  57.  
  58. スワップ(arr, 0, i);
  59.  
  60. 長さ--;  
  61.  
  62. ヒープ化(arr, 0);
  63. }
  64.  
  65. arrを返します
  66. }

カウントソート

カウンティングソートの中核は、入力データの値をキーに変換し、それを追加の配列スペースに格納することです。線形時間計算量を持つソート方法として、カウンティングソートでは、入力データが特定の範囲の整数である必要があります。

カウントソートアニメーションデモンストレーション

カウントソートの JavaScript コードの実装:

  1. 関数countingSort(arr, maxValue) {
  2. var バケット = 新しい配列(maxValue+1)、
  3. ソートインデックス = 0;
  4. arrLen = arr.長さ、
  5. バケット長さ = 最大値 + 1;
  6.  
  7. (var i = 0; i < arrLen; i++)の場合{
  8. if (!bucket[arr[i]]) {
  9. バケット[arr[i]] = 0;
  10. }
  11. バケット[arr[i]]++;
  12. }
  13.  
  14. ( var j = 0; j < バケット長さ; j++) {
  15. while(バケット[j] > 0) {
  16. arr[ソートされたインデックス++] = j;
  17. バケット[j] --;  
  18. }
  19. }
  20.  
  21. arrを返します
  22. }

バケットソート

バケットソートは、カウントソートのアップグレード版です。これは関数のマッピング関係を利用しますが、その効率の鍵はこのマッピング関数の決定にあります。

バケットソートをより効率的にするには、次の 2 つのことを行う必要があります。

  1. 十分な余裕がある場合は、バケットの数を増やしてみてください
  2. 使用されるマッピング関数は、N 個の入力データを K 個のバケットに均等に分散できます。

同時に、バケット内の要素のソートでは、比較ソート アルゴリズムの選択がパフォーマンスに大きく影響します。

最速はいつですか

入力データが各バケットに均等に分散できる場合

一番遅いのはい​​つですか?

入力データが同じバケットに割り当てられている場合

バケットソートの JavaScript コードの実装:

  1. 関数bucketSort(arr,bucketSize) {
  2. (arr.length === 0)の場合{
  3. arrを返します
  4. }
  5.   
  6. var 私;
  7. var 最小値 = arr[0];
  8. var 最大値 = arr[0];
  9. (i = 1; i < arr.length; i++)の場合{
  10. (arr[i] < 最小値)の場合{
  11. minValue = arr[i]; //入力データの最小値
  12. }そうでなければ(arr[i] > maxValue) {
  13. maxValue = arr[i]; //入力データの最大値
  14. }
  15. }
  16.   
  17. //バケットの初期化
  18. var DEFAULT_BUCKET_SIZE = 5; //デフォルトのバケット数を5に設定する
  19. バケットサイズ = バケットサイズ || DEFAULT_BUCKET_SIZE;
  20. var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;
  21. var バケット = 新しい配列(bucketCount);
  22. ( i = 0; i < バケットの長さ; i++) {
  23. バケット[i] = [];
  24. }
  25.   
  26. //マッピング関数を使用して各バケットにデータを分配する
  27. (i = 0; i < arr.length; i++)の場合{
  28. バケット[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
  29. }
  30.   
  31. arr.長さ = 0;
  32. ( i = 0; i < バケットの長さ; i++) {
  33. insertionSort(buckets[i]); //挿入ソートを使用して各バケットをソートする
  34. ( var j = 0; j < バケット[i].length; j++) {
  35. arr.push(バケット[i][j]);
  36. }
  37. }
  38.   
  39. arrを返します
  40. }

基数ソート

基数ソートには2つの方法がある

  1. MSDは最上位ビットからソートする
  2. LSDは最下位ビットからソートする

基数ソート vs カウンティングソート vs バケットソート

これら 3 つのソート アルゴリズムはすべてバケットの概念を使用しますが、バケットの使用方法には明らかな違いがあります。

  • 基数ソート: キー値の各桁に応じてバケットを割り当てる
  • カウントソート: 各バケットには1つのキー値のみが格納されます
  • バケットソート: 各バケットには特定の範囲の値が格納されます

LSD 基数ソートのアニメーションデモンストレーション:

基数ソートの JavaScript コード実装:

  1. //LSD 基数ソート
  2. var カウンタ = [];
  3. 関数radixSort(arr, maxDigit) {
  4. var mod = 10;
  5. var dev = 1;
  6. ( var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
  7. (var j = 0; j < arr.length; j++)の場合{
  8. var バケット = parseInt((arr[j] % mod) / dev);
  9. if (counter[bucket] == ​​null ) {
  10. カウンター[バケット] = [];
  11. }
  12. counter[bucket].push(arr[j]);
  13. }
  14. var pos = 0;
  15. (var j = 0; j < counter.length; j++)の場合{
  16. var 値 = null ;
  17. カウンタ[j]!= nullの場合{
  18. while ((値 = counter[j].shift()) != null ) {
  19. arr[pos++] = 値;
  20. }
  21. }
  22. }
  23. }
  24. arrを返します
  25. }

最後に

ソートアルゴリズムは本当に奥が深く、私がまだまとめていない、あるいは自分で解明していないアルゴリズムが数多くあります。これらの 10 個のソートアルゴリズムをまとめただけでも涙が出ました。 。 。

したがって、将来的にさらに多くの仕分け姿勢を習得したら、必ず戻ってきます

<<:  ディープラーニングの父ヒントン氏が、人工知能を一新するカプセルネットワークの最新動向を発表

>>:  機械学習とデータマイニングを一般の人に説明する方法

ブログ    
ブログ    

推薦する

LoraHubはレゴのように組み立てることができ、LoRAのモジュール特性を探索することができます。

低ランク適応 (LoRA) は、基本的な LLM が特定のタスクに効率的に適応できるようにする、一般...

顔認識を完了するための3行のPythonコード

顔認識パッケージこれは世界で最もシンプルな顔認識ライブラリです。 Python リファレンスまたはコ...

ガートナーなど権威ある組織:人工知能、国内外のどのAI技術が強いのか?

2020年末、我が国は第14次5カ年計画を発表し、2035年までの中国の長期目標を策定しました。 ...

クラウドベースの生成 AI システムを実行するためのベスト プラクティス

翻訳者 |ブガッティレビュー | Chonglou何だと思う?クラウド コンピューティング カンファ...

...

自動応答は人工知能ではなく、自律応答は

セキュリティ オペレーション センター (SOC) のアナリストは推論と意思決定に優れていますが、2...

人工知能と機械学習がスタートアップに与える影響

人工知能 (AI) と機械学習 (ML) は、スタートアップを含む複数の業界に革命をもたらしました。...

LLM幻覚問題の徹底レビュー! HITチームの50ページのレビューが公開された

幻覚だよ、古い友人よ。 LLM が私たちの視野に入って以来、錯覚の問題は常に無数の開発者を悩ませてき...

Meta主任AI研究者ヤン・リクン氏:今日のAIは愚かであり、規制当局は我々に干渉すべきではない

ソーシャルメディアFacebookの親会社Metaの主任人工知能研究者ヤン・ルカン氏は10月20日、...

JVM チューニングの概要: 基本的なガベージ コレクション アルゴリズム

ガベージ コレクション アルゴリズムは、さまざまな観点から分類できます。基本的なリサイクル戦略によれ...

衛星と機械学習はどのようにして海洋のプラスチック廃棄物を検出できるのでしょうか?

プラスチック廃棄物が海洋生物にとって常に恐ろしい脅威となっていることは誰もが知っているはずです。しか...

AIが建物をスマートにする5つの方法

[[407368]]今の世界は30年前とは大きく異なります。この変化の理由の一部は技術の発展です。今...

2 ステップで 25 フレームの高品質アニメーションを生成 (SVD の 8% として計算) | オンラインでプレイ可能

消費されるコンピューティング リソースは、従来の Stable Video Diffusion (S...

...