序文
今日は、jsアルゴリズムについて引き続き説明します。以下の説明により、検索アルゴリズムの基本的な実装とさまざまな実装方法のパフォーマンスを理解し、forループ、forEach、およびWhileのパフォーマンスの違いを発見できます。 Webワーカーを介してアルゴリズムのシャーディングを行う方法は、アルゴリズムのパフォーマンスを大幅に向上させます。
同時に、古典的なバイナリアルゴリズムとハッシュテーブルルックアップアルゴリズムについても簡単に紹介しますが、これらはこの章の焦点ではありません。後で対応する記事を立ち上げて、これらの高度なアルゴリズムを詳細に紹介します。興味のある友人は私のコラムをフォローするか、私たちに参加できます。見る。
アルゴリズムのパフォーマンスについては、前の章「フロントエンドアルゴリズムシリーズ」のgetFnRunTime関数を引き続き使用します。フロントエンドコードの速度を60倍にする方法。興味がある場合は、確認して学習できます。ここではあまり説明しません。
前章「フロントエンドアルゴリズムシリーズ」では、フロントエンドコードの速度を60倍にする方法について、 19,000個のデータをシミュレートしました。この章では、効果をより明確にするために、170万個のデータを偽造してテストしますが、信じてください。jsに来てください。これは何もないと言った。。。
1.forループ検索
基本的な考え方:forループを介して配列をトラバースし、配列内で検索する値のインデックスを見つけて、それを新しい配列にプッシュします。
コードは次のように実装されています。
const getFnRunTime = require('./getRuntime');
/**
* 普通算法-for循环版
* @param {*} arr
* 耗时:7-9ms
*/
function searchBy(arr, value) {
let result = [];
for(let i = 0, len = arr.length; i < len; i++) {
if(arr[i] === value) {
result.push(i);
}
}
return result
}
getFnRunTime(searchBy, 6)
n回の安定性をテストした後の結果を図に示します。
2.forEachループ
基本的な考え方は、forループに似ています。
/**
* 普通算法-forEach循环版
* @param {*} arr
* 耗时:21-24ms
*/
function searchByForEach(arr, value) {
let result = [];
arr.forEach((item,i) => {
if(item === value) {
result.push(i);
}
})
return result
}
21〜24ミリ秒かかりますが、パフォーマンスはforループほど良くないことがわかります(当分の間、本質も同じです)。
3.whileループ
コードは次のように表示されます。
/**
* 普通算法-while循环版
* @param {*} arr
* 耗时:11ms
*/
function searchByWhile(arr, value) {
let i = arr.length,
result = [];
while(i) {
if(arr[i] === value) {
result.push(i);
}
i--;
}
return result
}
whileループとforループのパフォーマンスは類似しており、どちらも優れていることがわかりますが、forEachのパフォーマンスが良くないという意味ではないため、使用されていません。forループと比較して、foreachはコードを削減しましたが、foreachはIEnumerableに依存しています。実行時の効率はforループよりも低くなります。ただし、ループ時間が不確実なループを処理する場合、またはループ時間を計算する必要がある場合は、foreachを使用する方が便利です。そして、foreachのコードがコンパイルシステムのコードによって最適化された後、それはforループに似ています。
4.バイナリ検索
二分法検索一意の順序付けられた配列を持つ配列内のその他のアプリケーションシナリオ。ここでは、そのパフォーマンスをfor / while / forEachと比較しません。
基本的な考え方:シーケンスの中央位置から開始し、現在の位置の値が検索する値と等しい場合、検索は成功します。検索する値が現在の位置の値よりも小さい場合、シーケンスの前半で検索します。検索する値がより大きい場合、現在の位置の値は、シーケンスの後半で見つかるまで検索されます
コードは次のように表示されます。
/**
* 二分算法
* @param {*} arr
* @param {*} value
*/
function binarySearch(arr, value) {
let min = 0;
let max = arr.length - 1;
while (min <= max) {
const mid = Math.floor((min + max) / 2);
if (arr[mid] === value) {
return mid;
} else if (arr[mid] > value) {
max = mid - 1;
} else {
min = mid + 1;
}
}
return 'Not Found';
}
大量のデータがあるシーンでは、二分法は非常に効率的ですが、不安定です。これは、ビッグデータクエリでの小さな欠点でもあります。
5.ハッシュテーブルルックアップ
ハッシュテーブルルックアップは、ハッシュテーブルルックアップとも呼ばれます。レコードの保存場所は、比較せずにキーワードを検索することで取得できます。レコードの保存場所とそのキーワードの間に明確な対応関係が確立されるため、各キーは保管場所f(キー)に対応します
ハッシュテーブルルックアップのシナリオを使用します。
ハッシュテーブルの最も適切な解決策は、指定された値に等しいレコードを見つけることです。
ハッシュ検索は、同じキーワードが複数のレコードに対応する状況には適していません
18〜22歳のクラスメートの検索などの範囲検索には適していません
ここでは、誰もがハッシュをより簡単に理解できるように、最初に最も単純なバージョンのhashTableを提供します。
/**
* 散列表
* 以下方法会出现数据覆盖的问题
*/
function HashTable() {
var table = [];
// 散列函数
var loseloseHashCode = function(key) {
var hash = 0;
for(var i=0; i<key.length; i++) {
hash += key.charCodeAt(i);
}
return hash % 37
};
// put
this.put = function(key, value) {
var position = loseloseHashCode(key);
table[position] = value;
}
// get
this.get = function(key) {
return table[loseloseHashCode(key)]
}
// remove
this.remove = function(key) {
table[loseloseHashCode(key)] = undefined;
}
}
この方法はデータの競合の問題を引き起こす可能性がありますが、解決策もあります。ここには多くの知識ポイントが含まれているため、後で紹介する記事を公開します。
オープンアドレッシング
2番目の検出方法
ランダム検出
Webワーカーの最適化を使用する
上記の方法により、さまざまなアルゴリズムのパフォーマンスとアプリケーションのシナリオをすでに理解しています。アルゴリズムを使用する場合、Webワーカーを介してそれらを最適化し、大きな配列を複数のブロックに分割するなど、プログラムを並行して処理できるようにすることもできます。 Webワーカースレッドは、計算結果を処理し、最終的に結果をマージして、ワーカーイベントメカニズムを介してブラウザーに渡すのに役立ちます。効果は非常に重要です。
総括する
複雑な配列クエリの場合、for / whileのパフォーマンスはforEachや他の配列メソッドよりも高くなります
バイナリ検索方式のO(logn)は非常に効率的なアルゴリズムです。しかし、その欠点も明らかです。それは正常である必要があり、配列が正常であることを保証することは困難です。もちろん、配列を作成するときに並べ替えることはできますが、2番目のボトルネックになります。配列である必要があります。配列の読み取りの効率はO(1)ですが、要素の挿入と削除の効率はO(n)です。その結果、順序付き配列を作成する際の効率が低下します。
ハッシュテーブルルックアップの基本的な使用法と使用シナリオ。
条件が許せば、Webワーカーを使用してアルゴリズムを最適化し、バックグラウンドで並行して実行させることができます。
さて、この記事は比較的単純ですが、非常に重要です。誰もが検索アルゴリズムをより直感的に理解し、誰もがより良い議論とコミュニケーションの方法を持っていることを願っています。