プログラマーに必要ないくつかの一般的なソートおよび検索アルゴリズムの概要

プログラマーに必要ないくつかの一般的なソートおよび検索アルゴリズムの概要

[[434262]]

序文

最近、アルゴリズムの基礎を固めるために、アルゴリズムの本にある基本的なアルゴリズムをもう一度見直しました。フロントエンドエンジニアが知っておくべきソートアルゴリズムと検索アルゴリズムの知識を特にまとめました。理解すべき高度なアルゴリズムはまだたくさんありますが、基礎を固める必要があります。この記事では、次のアルゴリズムの知識を画像とテキストの形で紹介します。読んで何かを得ていただければ幸いです。

  • バブルソートとその最適化
  • 選択ソート
  • 挿入ソート
  • マージソート
  • クイックソート
  • シーケンシャルサーチ
  • バイナリ検索

文章

[[434263]]

すべてのフロントエンドエンジニアにとって、最も面倒なのはアルゴリズムの問​​題だと思いますが、アルゴリズムは多くの場合、人のプログラミング能力を測る非常に重要な指標でもあります。現在、多くの主流のフレームワークとライブラリには、大量のアルゴリズムとデザインパターンが適用されています。自分のランクを上げるには、絶えず「モンスターを倒して」(つまり、アルゴリズムを磨いて)アップグレードし、「最強の王」になるしかありません。

実際、フロントエンド開発はここ数年でますます洗練された開発に傾倒しています。多くのスーパーアプリケーション(TaobaoやWeChatなど)は究極のユーザーエクスペリエンスを追求しています。時間はお金であり、エンジニアは以前と同じように使用できるプログラムを開発しないようにする必要があります。より詳細なテスト(ユニットテスト、パフォーマンステストなどを含む)を実行する必要があることがよくあります。ソートを例に挙げてみましょう。大量のデータをソートする場合、バブルソートを使用すると間違いなく批判されます。バブルソートのパフォーマンスは非常に悪いためです(複雑さはO(n ^ 2))。実際のプロジェクトでは、バブルソートを使用することはほとんどなく、クイックソートやシェルソートを使用することが多いです。ソートアルゴリズムのパフォーマンスに関しては、

「フロントエンドアルゴリズムシリーズ」フロントエンドのコードを60倍高速化する方法

詳細な紹介があります。次に、記事の冒頭で、いくつかの一般的なソートおよび検索アルゴリズムを実装する方法を学びましょう。

1. バブルソートとその最適化

ソートアルゴリズムを学ぶとき、習得するのが最も簡単なのはバブルソートです。これは実装が非常に簡単なためですが、実行パフォーマンスの観点からは最悪です。

バブルソートの考え方は、隣接する 2 つの項目を比較し、前者が後者よりも大きい場合はそれらの位置を交換するというものです。

バブルソートのプロセスとパフォーマンステストをより便利に実証するために、著者はまず、指定された数のランダム配列を動的に生成し、要素の位置シーケンスを生成するメソッドであるいくつかのツールメソッドを記述します。コードは次のとおりです。

  1. // 指定された数のランダム配列を生成する
  2. const generateArr = (num = 10) => {
  3. arr = [] とします
  4. (i = 0; i< num; i++)の場合{
  5. item = Math.floor(Math.random() * (num + 1)) とします。
  6. arr.push(アイテム)
  7. }
  8. リターン
  9. }
  10.  
  11. // 指定された数の要素のx軸座標を生成する
  12. const generateArrPosX = (n= 10, w = 6, m = 6) => {
  13. pos = [] とします
  14. ( i = 0; i< n; i++ とします) {
  15. アイテム = (w + m) * i とする
  16. pos.push(アイテム)
  17. }
  18. 戻り位置
  19. }

上記の 2 つの方法を使用すると、任意の数と配列項目の座標の配列を生成できます。次に、この 2 つの方法を使用します。

バブルソートアルゴリズムの乞食バージョンを直接書いてみましょう。

  1. バブルソート(arr = []) {
  2. len = arr.lengthとします
  3. (i = 0; i< len; i++)の場合{
  4. (j = 0; j < len - 1; j++)の場合{
  5. arr[j] > arr[j+1] の場合
  6. // 交換する
  7. [arr[j], arr[j+1]] = [arr[j+1], arr[j]]
  8. }
  9. }
  10. }
  11. リターン
  12. }

次に、テストしてみましょう。generateArr メソッドを使用して、60 個の配列項目の配列を生成し、要素の座標を動的に生成します。

  1. // 座標を生成する
  2. 定数 pos = generateArrPosX(60)
  3. // 60 個の項目の配列を生成する
  4. 定数arr = generateArr(60)

コードを実行すると、次のランダム ノード構造が生成されます。

ここでは CSS の部分を紹介しません。自分で実装できます。次に、上で書いたバブル ソートをテストします。[Sort] をクリックすると、結果は次のようになります。

配列が順番にソートされていることがわかります。コードの実行にかかる時間を測定するために console.time を使用できます。上記の「乞食バージョン」のバブル ソートには 0.2890625 ミリ秒かかります。

コードを詳細に分析すると、2 層の for ループ ソートによって冗長なソートが大量に発生することがわかります。外側のループで実行されたラウンド数を内側のループから減算すると、内側のループでの不要な比較を回避できるため、次のようにコードを最適化します。

  1. // バブルソートの最適化バージョン
  2. バブルソート(arr = []) {
  3. len = arr.lengthとします
  4. // 最適化
  5. (i = 0; i< len; i++)の場合{
  6. (j = 0; j < len - 1 - i; j++)の場合{
  7. arr[j] > arr[j+1] の場合
  8. // 交換する
  9. [arr[j], arr[j+1]] = [arr[j+1], arr[j]]
  10. }
  11. }
  12. }
  13. リターン
  14. }

最適化されたバブルソートには 0.279052734375 ミリ秒かかります。これは以前よりわずかに改善されていますが、まだ推奨されるソートアルゴリズムではありません。

2. 選択ソート

選択ソートの考え方は、データ構造内で最小の値を見つけてそれを最初に配置し、次に 2 番目に小さい値を見つけてそれを 2 番目に配置する、というものです。

引き続き前のパターンに従い、次のように 60 個の項目の配列を生成します。

選択ソートコードは次のとおりです。

  1. 選択ソート(arr) {
  2. len = arr.lengthとします。
  3. インデックス最小
  4. (i = 0; i< len -1; i++)の場合{
  5. インデックス最小値 = i
  6. (j = i; j < len; j++)の場合{
  7. arr[indexMin] > arr[j] の場合
  8. インデックス最小値 = j
  9. }
  10. }
  11. if(i !== インデックス最小値) {
  12. [arr[i], arr[indexMin]] = [arr[indexMin], arr[i]]
  13. }
  14. }
  15. リターン
  16. }

「並べ替え」をクリックすると、結果は次のようになります。

これは、コードが正常に実行され、ソートを実行できることを示しています。コンソールには 0.13720703125 ミリ秒かかり、これは明らかにバブル ソートのパフォーマンスよりも優れています。

3. 挿入ソート

挿入ソートの考え方は、最初の項目がソートされていると仮定して、一度に 1 つの配列項目をソートし、次に 2 番目の項目と比較して 2 番目の項目の位置を決定し、同じ方法を使用して 3 番目の項目の位置を決定し、最後に配列全体を小さいものから大きいものの順にソートするというものです。

コードは次のとおりです。

  1. 挿入ソート(arr) {
  2. len = arr.lengthとします。
  3. じ、
  4. 温度;
  5. (i = 1; i< len; i++)の場合{
  6. j = 私
  7. temp = arr[i]
  8. j > 0 && arr[j-1] > temp
  9. arr[j] = arr[j-1]
  10. じ --  
  11. }
  12. arr[j] =一時;
  13. }
  14. }

実行結果は次のとおりです。

コンソールの印刷時間は 0.09912109375 ミリ秒です。

4. マージソート

マージソートアルゴリズムは上記の 3 つよりもパフォーマンスが優れており、実際のプロジェクトで使用できますが、実装は比較的複雑です。

マージソートは分割統治アルゴリズムです。元の配列を小さな配列に分割し、各小さな配列に要素が 1 つだけ含まれるようにしてから、小さな配列を大きな配列にマージし、最後にソートされた大きな配列に変換するという考え方です。

実装プロセスを次の図に示します。

このメソッドを実装するには、マージ関数と再帰関数を用意し、次のようにコードを実装する必要があります。

  1. // マージソート
  2. マージソートレコード(arr) {
  3. len = arr.lengthとします
  4. 長さが1の場合
  5. リターン
  6. }
  7. mid = Math.floor(len / 2)とします。
  8. = arr.slice(0, 中央)、
  9. = arr.slice(mid, len)
  10. merge(mergeSortRec(), mergeSortRec())を返します
  11. }
  12. //マージメソッド
  13. マージ() {
  14. 結果 = []
  15. l = 0,
  16. r = 0;
  17. l <.長さ && r <) {
  18. if([l]<(r)){
  19. result.push([l++])
  20. }それ以外{
  21. result.push([r++])
  22. }
  23. }
  24. while(l <.length) {
  25. result.push([l++])
  26. }
  27. while(r <.length) {
  28. result.push([r++])
  29. }
  30. 結果を返す
  31. }

上記のコードの再帰関数は、大きな配列を複数の小さな配列に分割して項目を 1 つだけにし、それらをレイヤーごとに結合して並べ替えます。わからないことがあれば、作者とコミュニケーションをとったり、私が描いたスケッチを使って理解したりすることができます。

5. クイックソート

クイック ソートは、よく使用されるソート アルゴリズムです。その複雑度は O(nlog^n) で、他の O(nlog^n) 複雑度よりもパフォーマンスが優れています。また、分割統治法を使用して元の配列を分割します。クイック ソートは実装が複雑なため、考え方は次のとおりです。

  1. 配列の中央の項目をピボットとして選択する
  2. 2 つのポインタを作成します。左側のポインタは配列の最初の項目を指し、右側のポインタは配列の最後の項目を指します。ピボットよりも大きい要素が見つかるまで左側のポインタを移動し、ピボットよりも小さい要素が見つかるまで右側のポインタを移動して、位置を交換します。左側のポインタが右側のポインタより先になるまで、このプロセスを繰り返します。
  3. アルゴリズムは、配列が完全にソートされるまで、分割された小さな配列に対して手順 1 と 2 を繰り返します。

コードは次のとおりです。

  1. // クイックソート
  2. クイックソート(arr,,) {
  3. インデックスを付ける 
  4. (arr.length > 1)の場合{
  5. インデックス= パーティション(arr,,)
  6. if(<インデックス- 1) {
  7. クイックソート(arr,,インデックス-1)
  8. }
  9. if(インデックス<) {
  10. クイックソート(arr,インデックス,)
  11. }
  12. }
  13. }
  14. // プロセスを分割する
  15. パーティション(arr,,) {
  16. part = arr[Math,floor(( right + left ) / 2)]とします。
  17. i =
  18. j = 
  19. i <= j の間 {
  20. while(arr[i] < 部分) {
  21. 私は++
  22. }
  23. while(arr[j] > part) {
  24. じ --  
  25. }
  26. i <= jの場合{
  27. // 交換する
  28. [arr[i], arr[j]] = [arr[j], arr[i]]
  29. 私は++
  30. じ --  
  31. }
  32. }
  33. 戻る
  34. }

7. シーケンシャルサーチ

検索アルゴリズムも、よく使用されるアルゴリズムの 1 つです。たとえば、ユーザーまたはデータを検索する必要がある場合、フロントエンドでもバックエンドでも検索アルゴリズムを使用します。まず、最も単純で効率の悪い順次検索を紹介しましょう。基本的な考え方は、データ構造内の各要素をクエリする要素と比較し、指定された要素のインデックスを返すことです。

シーケンシャル検索が非効率な理由は、検索する値が見つかるまで毎回クエリが配列の先頭から開始され、全体的なクエリが十分に柔軟で動的ではないためです。順次検索コードは次のように実装されます。

  1. シーケンシャルサーチ(arr, アイテム) {
  2. ( i = 0 とします; i< arr.length; i++) {
  3. if(item === arr[i]) {
  4. 戻る
  5. }
  6. }
  7. -1を返す
  8. }

次に、より一般的に使用され、柔軟性の高い検索アルゴリズムであるバイナリ検索を見てみましょう。

8. バイナリ検索

バイナリ検索のアイデアはやや「投機的」ですが、理論的根拠のある一種の「投機」です。まず、検索対象のデータ構造をソートする必要があり、次に次の処理を実行します。

  1. 配列の中央値を見つける
  2. 中央の値が検索対象の値である場合、中央の値のインデックスが直接返されます。
  3. 検索する値が中央値より小さい場合は、手順 1 に戻り、間隔範囲を狭めて、中央値の左側のサブ配列で検索を続けます。
  4. 検索する値が選択した値より大きい場合は、手順 1 に戻り、間隔の範囲を狭めて、中央の値の右側のサブ配列で検索を続けます。
  5. 見つからない場合は-1を返します

理解を容易にするために、次のスケッチを描きました。

上の図から、バイナリ検索の実装プロセスを簡単に理解できます。次に、コードの実装を見てみましょう。

  1. バイナリサーチ(arr, アイテム) {
  2. // ソートアルゴリズムを呼び出して、まずデータをソートします
  3. this.quickSort(arr)
  4.  
  5. min = 0 とします。
  6. 最大= 配列の長さ - 1、
  7. 中、
  8. エル
  9. while(最小値<=最大値) {
  10. 中間 = Math.floor((最小+最大) / 2)
  11. el = arr[mid]
  12. if(el < アイテム) {
  13. 最小= 中間 + 1
  14. }そうでない場合 (el > 項目) {
  15. 最大= 中間 -1
  16. }それ以外{
  17. 戻る途中
  18. }
  19. }
  20. -1を返す
  21. }

実際、検索アルゴリズムは数多く存在します。著者は、JS での基本的な検索アルゴリズムの実装と、170 万のデータでのパフォーマンス テストを詳細に紹介しています。

参考資料: JavaScript のデータ構造とアルゴリズムの学習

この記事はWeChatの公開アカウント「Fun Talk Front End」から転載したものです。

<<:  Nvidiaの自動運転チップOrinはどれほど強力か:CEOのHuang RenxunはL2をデモンストレーションするためにメルセデスベンツを発見し、都市のシーンを簡単に処理できる

>>:  顔検出と認識がますます普及しているのはなぜでしょうか?その背後にある技術は何ですか?

ブログ    
ブログ    
ブログ    
ブログ    
ブログ    
ブログ    
ブログ    

推薦する

人工知能に関するよくある誤解

ビッグデータ、自動化、ニューラルネットワークが日常語となっている世界では、人工知能とその背後にあるプ...

人類は人工知能のせいで滅びるのか?ホーキング博士の最後の論文にヒントがあるかもしれない

[[251536]] 「完全な人工知能の開発は人類の終焉を意味するかもしれない...人工知能は自ら進...

AI、VR、ブロックチェーンにより、新しい時代は貧しい人々にとっての楽園となるのでしょうか?

今日の社会では貧困がまだ存在しています。 [[275832]]国連開発計画(UNDP)のデータによる...

AIとビッグデータに焦点を当て、インテルとToutiaoが技術革新研究所を設立

[原文は51CTO.comより] 8月22日、インテルとToutiaoの共同戦略協力記者会見と「デー...

GPT のプログラミング バージョンは 30,000 スターに急上昇し、AutoGPT は危険にさらされています。

執筆者 | 王 瑞平AutoGPT に続いて、GPT ファミリーに新しいメンバーである GPT-En...

...

ハーバード大学の研究者がAIを活用して世界中の密猟を阻止

ハーバード大学ジョン・A・ポールソン工学応用科学大学院のリリー・シューさんは、幼いころから環境と保護...

言語モデルの氷山の一角: 微調整は不要、AI21 Labs は凍結モデルの未開発の可能性を探る

現在、特定の NLP タスクのパフォーマンスを最適化するための最善のアプローチは、事前トレーニング済...

...

今のところ人工知能があなたの仕事を奪うことはないが、すでにあなたの履歴書に載っている

[[387879]] AI、つまり人工知能は、最近誰もが口にする言葉になっているようです。私はこのテ...

あなたの AI は規制に対応できる準備ができていますか?

現在、人工知能 (AI) に関する同様の規制が世界中の複数の地域で施行され始めており、GDPR に関...

マスクを着用していても、AIはあなたが何を言っているか理解できる

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

人工知能にブレーキをかけるべき6つの理由

人工知能は徐々にビジネスプロセスに導入されつつあります。しかし、CIO は立ち止まって、AI ツール...

ビッグデータアルゴリズムとアプリケーションシナリオパート1: 統計と分布

アルゴリズムはビッグデータの最も価値のある部分です。ビッグデータマイニングとは、大量、不完全、ノイズ...

数学者は解けないコンピュータの問題を発見した

最近、海外メディアの報道によると、数学者たちは自分たちには解決できない機械学習に関連したコンピュータ...