JavaScriptアルゴリズムの複雑度分析
8289 ワード
新しい年は、まず簡単で重要な知識点を共有するために整理します.時間の複雑さと空間の複雑さ.前の文章の中で、時間の複雑さを言っていますから、まだ分からない仲間もいるかもしれません.(ps:前の記事にコメントしてくれた友達ががっかりしないでください.ゆっくり来てください.)
まずみんなに思考問題を出して、テーマ:sum=1+2+3++n、sumの値を計算します.
なぜ複雑度分析が必要ですか?データ構造とアルゴリズムを学習すると、「速い」と「省」の問題を理解するために、つまりどのようにあなたのコードを設計すれば演算効率が速くなり、スペースが小さくなりますか?コードの実行効率はどう計算しますか?ここでは複雑度分析が使われます. 実行時間はコードで正確に計算できますが、多くの限界があります. データ規模の違いは試験結果に直接影響を与えます.例えば、同じ並べ替えアルゴリズムでは、順序が違っています.最後の計算効率の結果も違っています.ちょうど配列が整いました.実行時間はもっと短くなります.また、例えばデータ規模が小さいと、テスト結果もアルゴリズムの性能に反応しないかもしれません. 試験の環境によっては試験結果にも影響があります.例えば同じコードをそれぞれi 3とi 7のプロセッサでテストすれば、i 7のテスト時間はi 3より短いはずです. したがって、正確なテスト結果ではなく、コードの実行時間を推定する方法が必要です.これは複雑度分析です.
大O複雑度表示法
一例で開始します.以下のコードの実行時間を見積もってください.
上記の分析方法に従って、下記のコードの実行時間を見積もってください.
数学的な観点から,コードの全実行時間T(n)は各ラインのコードの実行回数に比例するという法則を導き出すことができる.
T(n)=O(f(n))
この式では、T(n)はコードの実行時間を表します.nはデータ規模の大きさを表します.f(n)は、行コード毎に実行される回数の総和を表します.Oはコードの実行時間T(n)がf(n)式に比例することを示している.
したがって、上記の2つの関数の実行時間をT(n)=O(2 n+1)とT(n)=O(2 n 2+n+1)と表記することができる.これは大きいO時間の複雑さの表現法で、コードの本当の実行時間を代表しないで、コードがデータの規模の増加の変化の成り行きに従うことを表して、時間の複雑さを略称します.
またnが大きいときは定数項を無視して最大級だけを残してもいいです.上のコードの実行時間はT(n)=O(n)とT(n)=O(n 2)と簡単に表記できます.
時間の複雑さの分析
コードの時間の複雑さをどう分析すればいいですか?次の方法を利用できます.
1.循環実行回数が一番多いコードだけに注目してください.
私たちはコードの時間の複雑さを分析する時、循環回数が一番多いコードに注目すればいいです.例えば、第一段のコードの中で
2.足し算の法則:総複雑度は最大級のコードの複雑さに等しい.
例えば、次のコードの時間の複雑さを見ます.
第1段forサイクルの時間複雑度はO(n 2)である.
第二段forサイクルは1000回実行しました.定数レベルです.コードの実行時間に影響がありますが、n無限大の場合は無視できます.それ自体は成長傾向に影響がないので、このコードの時間的複雑さは無視できます.
第三段forサイクルの時間複雑度はO(n)である.
総体的には最大級をとるため、全セグメントコードの時間複雑度はO(n 2)です.
3.乗算の法則:ネストコードの複雑さはネスト内外コードの複雑さの積に等しい.
例えば、次のコードの時間の複雑さを見てください.
いくつかのよくある時間の複雑さの分析
トップクラスの複雑さだけを見て、下の図の効率は逓減しています.上の図のように大まかに二つの種類に分けられます.
多項式級と
多項式級ではない.そのうち
非多項式級は二つしかありません.O(2)
n)O(n!)に対応する成長率を下図に示します.
データ規模nが増加すると、
非多項式級の執行時間は急激に増加します.
非多項式級のコードアルゴリズムは非常に非効率なアルゴリズムである.
1.O(1)
O(1)は、定数レベルの時間的複雑度表示法だけで、コードが1行しかないわけではありません.たとえば、次のようなコードです.
2.O(logn)、O(nlogn)
対数の複雑さの共通コードは以下の通りです.
20 21…2 k…2 x=n;
したがって、xの値を知ると、この2つの関数の実行回数が分かります.それは2 x=nからx=log 2 nを導出できるので、この2つの関数の時間複雑度はO(log 2 n)である.
次の二つの関数の時間の複雑さを見てください.
定数を無視できますし、対数の底数も無視できますので、対数の複雑さにおいては、O(logn)として統一的に表現されます.そのOの意味ははっきりしています.時間の複雑さはOのコードでn回も実行しました.
3.O(m+n)、O(m*n)
もう一つの特殊なコードの時間の複雑さを見てみます.例えば、
空間複雑度分析
空間の複雑さは時間の複雑さと似ていると推定すればいいです.空間複雑さとは、アルゴリズムの記憶空間とデータ規模との関係を表しています.
例えば、下記のコードの空間複雑度を分析します.
一般的な空間複雑度はO(1)、O(n)、O(n 2)のみである.他はあまり使われません.
問題を解く
今から私たちは最初の思考問題に戻ります.コードの実現は簡単です.
この時間は複雑度が高いと思いますが、O(1)の時間複雑度関数がこのアルゴリズムを実現してもいいですか?
はい、小数学神通Gauss教会は次のように教えてくれます.
締め括りをつける
複雑さも漸進複雑度といい、時間複雑さと空間複雑さを含み、実行の速度を表し、メモリの消費を表し、アルゴリズムの実行効率とデータ規模との成長関係を分析するために用いられ、高次複雑度のアルゴリズムほど、実行効率が低い.
複雑さの分析を学んだら、効率の低いコードを書くのは避けられますか?コードを分析してあげましょう.
重点
もし間違いや誤字があったら、メッセージで指摘してください.ありがとうございます.
また今度会いましょう.
まずみんなに思考問題を出して、テーマ:sum=1+2+3++n、sumの値を計算します.
なぜ複雑度分析が必要ですか?
大O複雑度表示法
一例で開始します.以下のコードの実行時間を見積もってください.
function total(n) { // 1
var sum = 0; // 2
for (var i = 0; i < n; i++) { // 3
sum += i; // 4
} //5
} //6
各行のコードが実行される時間が同じであると仮定して、tを記入すると、上の関数の2行目にはtの時間が必要であり、3行目と4行目にはそれぞれn個のtの時間が必要である.このコードの総実行時間は(2 n+1)*tである.上記の分析方法に従って、下記のコードの実行時間を見積もってください.
function total(n) { // 1
var sum = 0; // 2
for (var i = 0; i < n; i++) { // 3
for (var j = 0; j < n; j++) { // 4
sum = sum + i + j; // 5
}
}
}
2行目はtの時間が必要で、3行目はn個のtの時間が必要で、4行目と5行目はそれぞれn 2個の時間が必要である.このコードの総実行時間は(2 n 2+n+1)*tの時間である.数学的な観点から,コードの全実行時間T(n)は各ラインのコードの実行回数に比例するという法則を導き出すことができる.
T(n)=O(f(n))
この式では、T(n)はコードの実行時間を表します.nはデータ規模の大きさを表します.f(n)は、行コード毎に実行される回数の総和を表します.Oはコードの実行時間T(n)がf(n)式に比例することを示している.
したがって、上記の2つの関数の実行時間をT(n)=O(2 n+1)とT(n)=O(2 n 2+n+1)と表記することができる.これは大きいO時間の複雑さの表現法で、コードの本当の実行時間を代表しないで、コードがデータの規模の増加の変化の成り行きに従うことを表して、時間の複雑さを略称します.
またnが大きいときは定数項を無視して最大級だけを残してもいいです.上のコードの実行時間はT(n)=O(n)とT(n)=O(n 2)と簡単に表記できます.
時間の複雑さの分析
コードの時間の複雑さをどう分析すればいいですか?次の方法を利用できます.
1.循環実行回数が一番多いコードだけに注目してください.
私たちはコードの時間の複雑さを分析する時、循環回数が一番多いコードに注目すればいいです.例えば、第一段のコードの中で
function total(n) { // 1
var sum = 0; // 2
for (var i = 0; i < n; i++) { // 3
sum += i; // 4
} //5
} //6
3行目と4行目だけが実行回数が一番多く、それぞれn回実行すると定数項目を無視するので、このコードの時間的複雑度はO(n)です.2.足し算の法則:総複雑度は最大級のコードの複雑さに等しい.
例えば、次のコードの時間の複雑さを見ます.
function total(n) {
// for
var sum1 = 0;
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
sum1 = sum1 + i + j;
}
}
// for
var sum2 = 0;
for(var i=0;i<1000;i++) {
sum2 = sum2 + i;
}
// for
var sum3 = 0;
for (var i = 0; i < n; i++) {
sum3 = sum3 + i;
}
}
まずそれぞれのforサイクルの時間複雑さを分析して、その中の最大級を整理コードの時間複雑さとします.第1段forサイクルの時間複雑度はO(n 2)である.
第二段forサイクルは1000回実行しました.定数レベルです.コードの実行時間に影響がありますが、n無限大の場合は無視できます.それ自体は成長傾向に影響がないので、このコードの時間的複雑さは無視できます.
第三段forサイクルの時間複雑度はO(n)である.
総体的には最大級をとるため、全セグメントコードの時間複雑度はO(n 2)です.
3.乗算の法則:ネストコードの複雑さはネスト内外コードの複雑さの積に等しい.
例えば、次のコードの時間の複雑さを見てください.
function f(i) {
var sum = 0;
for (var j = 0; j < i; j++) {
sum += i;
}
return sum;
}
function total(n) {
var res = 0;
for (var i = 0; i < n; i++) {
res = res + f(i); // f
}
}
total関数を単独で見ると、時間の複雑さはT 1(n)=O(n)であるが、f関数を考慮した時間の複雑さもT 2(n)=O(n)である.したがって、全セグメントコードの時間複雑度はT(n)=T 1(n)*T 2(n)=O(n*n)=O(n 2)である.いくつかのよくある時間の複雑さの分析
トップクラスの複雑さだけを見て、下の図の効率は逓減しています.上の図のように大まかに二つの種類に分けられます.
多項式級と
多項式級ではない.そのうち
非多項式級は二つしかありません.O(2)
n)O(n!)に対応する成長率を下図に示します.
データ規模nが増加すると、
非多項式級の執行時間は急激に増加します.
非多項式級のコードアルゴリズムは非常に非効率なアルゴリズムである.
1.O(1)
O(1)は、定数レベルの時間的複雑度表示法だけで、コードが1行しかないわけではありません.たとえば、次のようなコードです.
function total() {
var sum = 0;
for(var i=0;i<100;i++) {
sum += i;
}
}
これだけ多くの行がありますが、forループが100回実行されても、コードの実行時間はnの増加に伴って増加しないので、このようなコードの複雑さはO(1)です.2.O(logn)、O(nlogn)
対数の複雑さの共通コードは以下の通りです.
function total1(n) {
var sum = 0;
var i = 1;
while (i <= n) {
sum += i;
i = i * 2;
}
}
function total2(n) {
var sum = 0;
for (var i = 1; i <= n; i = i * 2) {
sum += i;
}
}
上記の2つの関数は同じ点を持っています.変数iは1から値を取ります.1サイクルに2を掛けます.nより大きい場合はループが終了します.実際、iの取得値は等比数列で、次のようになります.20 21…2 k…2 x=n;
したがって、xの値を知ると、この2つの関数の実行回数が分かります.それは2 x=nからx=log 2 nを導出できるので、この2つの関数の時間複雑度はO(log 2 n)である.
次の二つの関数の時間の複雑さを見てください.
function total1(n) {
var sum = 0;
var i = 1;
while (i <= n) {
sum += i;
i = i * 3;
}
}
function total2(n) {
var sum = 0;
for (var i = 1; i <= n; i = i * 3) {
sum += i;
}
}
上から知ることができますが、この2つの関数の時間複雑さはO(log 3 n)です.定数を無視できますし、対数の底数も無視できますので、対数の複雑さにおいては、O(logn)として統一的に表現されます.そのOの意味ははっきりしています.時間の複雑さはOのコードでn回も実行しました.
3.O(m+n)、O(m*n)
もう一つの特殊なコードの時間の複雑さを見てみます.例えば、
function total(m,n) {
var sum1 = 0;
for (var i = 0; i < n; i++) {
sum1 += i;
}
var sum2 = 0;
for (var i = 0; i < m; i++) {
sum2 += i;
}
return sum1 + sum2;
}
私たちはmとnのサイズが大きいと評価できないので、その一つを無視することはできません.この関数の複雑さは2つのデータのレベルで決まるので、この関数の時間複雑さはO(m+n)です.じゃ、O(m*n)の時間の複雑さは似ています.空間複雑度分析
空間の複雑さは時間の複雑さと似ていると推定すればいいです.空間複雑さとは、アルゴリズムの記憶空間とデータ規模との関係を表しています.
例えば、下記のコードの空間複雑度を分析します.
function initArr(n) {
var arr = [];
for (var i = 0; i < n; i++) {
arr[i] = i;
}
}
時間の複雑さの推定によって、定数レベルを無視して、配列の割り当てごとに空間保存変数を申請しますので、この関数の空間複雑度はO(n)です.一般的な空間複雑度はO(1)、O(n)、O(n 2)のみである.他はあまり使われません.
問題を解く
今から私たちは最初の思考問題に戻ります.コードの実現は簡単です.
function total(n) {
var sum = 0;
for (var i = 1; i <= n; i++) {
sum += i;
}
return sum;
}
この関数の時間の複雑さは、あなたが今すぐにわかるはずです.O(n)です.この時間は複雑度が高いと思いますが、O(1)の時間複雑度関数がこのアルゴリズムを実現してもいいですか?
はい、小数学神通Gauss教会は次のように教えてくれます.
function total(n) {
var sum = n*(n+1)/2
return sum;
}
この関数の時間の複雑さはO(1)だけです.データの規模が大きい場合、下の関数は明らかに上の関数よりも演算効率が高いですか?締め括りをつける
複雑さも漸進複雑度といい、時間複雑さと空間複雑さを含み、実行の速度を表し、メモリの消費を表し、アルゴリズムの実行効率とデータ規模との成長関係を分析するために用いられ、高次複雑度のアルゴリズムほど、実行効率が低い.
複雑さの分析を学んだら、効率の低いコードを書くのは避けられますか?コードを分析してあげましょう.
重点
もし間違いや誤字があったら、メッセージで指摘してください.ありがとうございます.
また今度会いましょう.