分析の複雑さは、アルゴリズム全体の本質はあなたがそれをしたら、データ構造とアルゴリズムの内容は基本的に半分をマスターし、学ぶことです。
1.分析の複雑さとは何ですか?
解決するために、データ構造とアルゴリズム「の問題を解決するには、コンピュータの時間短縮、省スペースなどを作成する方法」です。
このようなデータ構造とアルゴリズムの性能を評価するための2つの次元からの実行時間と空間のために。
パフォーマンスの問題のそれぞれの時間の複雑さと空間の複雑さは、二つの概念を説明し、両方まとめ複雑と呼びます。
アルゴリズムの複雑さは、実行時間(または空間)とデータサイズとの間の関係の成長を記述する。
2.なぜ分析の複雑でしたか?
そして、分析の複雑さと比較して、パフォーマンステストでは、実行環境に依存しない、低コスト、高効率、簡単な操作、指導と強い機能。
分析の複雑さを持ち、我々は、システム開発・保守コストの削減、より良いコードのパフォーマンスを書くことができるようになります。
3.どのように複雑な分析を実行するには?
3.1ランダウの記号
そして、アルゴリズムの実行時間の数がT(N)= O(F(N))、T(n)は、アルゴリズムの総実行時間を表し、F(n)はコードの各行の合計を表すとともに、コードの各行に比例します。数、およびnは、しばしばスケールデータを表現しています。これは大きなO時間の複雑さの表記です。
3.2時間計算
1)定義
アルゴリズムの時間の尺度であるアルゴリズムの時間複雑。
大きなO時間複雑表記は、実際には実時間を示す特定のコードを実行しない、むしろデータにおける成長傾向の尺度とコードの実行時間、それはまた呼ばれるプログレッシブ時間計算、短い時間の複雑性(漸近的時間計算) 。
例1:
function aFun() {
console.log("Hello, World!"); // 需要执行 1 次
return 0; // 需要执行 1 次
}
そして、この操作方法は、二回実行する必要があります。
例2:
function bFun(n) {
for(let i = 0; i < n; i++) { // 需要执行 (n + 1) 次
console.log("Hello, World!"); // 需要执行 n 次
}
return 0; // 需要执行 1 次
}
このアプローチは、(N + 1 + N + 1)= 2N +2計算時間を必要とします。
例3:
function cal(n) {
let sum = 0; // 1 次
let i = 1; // 1 次
let j = 1; // 1 次
for (; i <= n; ++i) { // n 次
j = 1; // n 次
for (; j <= n; ++j) { // n * n ,也即是 n平方次
sum = sum + i * j; // n * n ,也即是 n平方次
}
}
}
これは、2-forループ、第2の層は* = N-N-N-実行されることに注意してください2回、そしてサイクルはここで++ iは、2及び実施例I ++はれる、異なって、加算後の最初の増加違い。
このアプローチは、必要(N 2 + N- 2 + N-N- + + + +1。1. 1 +)を= 2N 2 + 2N +。3。
2)特徴
ので、時間の複雑さのために、例えば、時間の複雑さは、アルゴリズムの実行時間とデータサイズの説明成長傾向なので、一定の、低レベルの、係数が実際にこの成長傾向に決定的な影響力を持っているので、時間計算を行いません。分析時に無視これらのエントリを。
したがって、時間の上の例T(N)の複雑= O(1)、T(N)の例2複雑さの時間= O(N )、 T(N)の時間3複雑さの例= O (N- 2)。
3.3時間計算の解析
-
- コードの一部までを実行するサイクル数との関係のみ
参照するには、コードの単一周波数:ループなど。
function cal(n) {
let sum = 0;
let i = 1;
for (; i <= n; ++i) {
sum = sum + i;
}
return sum;
}
ほとんどの場合、ループ内のコードのために実行され、n回行われ、時間計算量はO(n)です。
-
- 追加ルール:のコードの大部分の大きさに等しい全体の複雑さの複雑さ
そのような単一サイクルとしてコードと、複数のサイクルが、複数のサイクルを取るの複雑さ:最大マルチセグメントのコードを取ります。
function cal(n) {
let sum_1 = 0;
let p = 1;
for (; p < 100; ++p) {
sum_1 = sum_1 + p;
}
let sum_2 = 0;
let q = 1;
for (; q < n; ++q) {
sum_2 = sum_2 + q;
}
let sum_3 = 0;
let i = 1;
let j = 1;
for (; i <= n; ++i) {
j = 1;
for (; j <= n; ++j) {
sum_3 = sum_3 + i * j;
}
}
return sum_1 + sum_2 + sum_3;
}
上記のコードは、サイクルの主要部分を参照して、sum_1、sum_2、sum_3を求めて、3つの分割されています。
sum_1を求める最初の部分は、知って正確に100回行い、そしてかかわらず、nの大きさの、実行時間は一定であり、反映していない成長傾向をので、時間計算量はO(1)です。
第二及び第三部分、及びnの大きさに関係するsum_2のsum_3、時間複雑さを求めるには、O(n)およびOではない(N 2)。
したがって、コードの三つのセクションの最大の大きさ、上記の最後の例を取って、時間計算量はO(Nである2)。
ループのための3つの層がある場合も同様に類推は、時間計算量はO(Nである3),. 4層は、O(N-である。4)。
したがって、合計時間の複雑性は、コードの大部分のための時間計算量と同等です。
-
- 乗算ルール:ネストされたタグの複雑さは、ネストされた内側及び外側コードの複雑さの積に等しいです。
ネストされたタグ製品の要件:このように再帰的なマルチサイクルなど。
function cal(n) {
let ret = 0;
let i = 1;
for (; i < n; ++i) {
ret = ret + f(i); // 重点为 f(i)
}
}
function f(n) {
let sum = 0;
let i = 1;
for (; i < n; ++i) {
sum = sum + i;
}
return sum;
}
Fの校正方法は、ループメソッド内部呼び出しが、メソッドfサイクルもあります。
したがって、全体の時間CAL()の複雑さの関数であり、T(N)= Tlの(N-)のT2 *(N)= O(N-N- *)= O(N 2)。
-
- 加算器の複数のスケールの2つのパラメータ、周波数制御方法としては、2サイクル、追加の、時間複雑性を有する方
function cal(m, n) {
let sum_1 = 0;
let i = 1;
for (; i < m; ++i) {
sum_1 = sum_1 + i;
}
let sum_2 = 0;
let j = 1;
for (; j < n; ++j) {
sum_2 = sum_2 + j;
}
return sum_1 + sum_2;
}
上記のコードは、合計である、sum_1データサイズが、sum_2用データ規模がN Mである、O(M + N)の時間計算量となるよう。
式:T1(M)+ T2(N)= O(F(M)+ G(N))。
-
- 乗算のためのスケールの複数:そのような方法は、2つのパラメータは、2サイクルの回数、両方の複雑さを乗算することにより時間を制御しました
function cal(m, n) {
let sum_3 = 0;
let i = 1;
let j = 1;
for (; i <= m; ++i) {
j = 1;
for (; j <= n; ++j) {
sum_3 = sum_3 + i * j;
}
}
}
上記のコードは2サイクル、要求sum_3のm及びnのデータサイズなので、Oの時間複雑度(M×n個)のために合計されます。
式:T1(M)* T2(N)= O(F(M)* G(N))。
3.4共通の時間複雑性分析
-
- 多項式オーダー:データサイズ、アルゴリズムの実行時間と空間の占有の増加に伴い、比例多項式で増加。
O(1)(一定の順序)、O(オーダー)(LOGN)、O(N)(線形順序)、O(nlogn)(線形対数オーダー)、O(N-挙げ2)(正方形の順序)を、 O(N 3)(立方順)。
O(LOGN)、O(nlogn)に加えて、他は上記の例から分かります。
以下に例示する(オーダー)O(LOGN) :
let i=1;
while (i <= n) {
i = i * 2;
}
スタートコードから1は、各ループを超えるN 2、乗算され、ループが終了します。
実際には、高校では、私は等比数列の値であり、幾何学的なシリーズを持っていました。数学では、次のようにあります:
2 0 2 1 2 2 ... 2 K ... 2 X = N
限り、我々は多くはxの値である方法を知っているように、我々は、と、Xの2倍= Nを解くことによって実行されるコードの行数は、x =ログ数学を解決したことを知っている2 N-を。したがって、上記のコードの時間複雑度はO(logです2 N-)を。
実際には、底部3のベース2、またはベース10に、我々は注文のすべての時間複雑さを置くことができるかどうかはO(LOGN)として記録されます。なぜ?
数が互いに、log3n間で変換することができるので=ログ。3 2 *ログ2 N-を、Oので(ログ3のN-)= O(C *ログ2 N-)=ログC、3 2は定数です。
以来、時間の複雑さは、アルゴリズムの実行時間とデータサイズの説明成長傾向なので、一定の、低レベルの、係数が実際にこの成長傾向に決定的な影響を与えることはありませんので、分析を行うための時間の複雑さは無視され、これらの項目を。
したがって、時間のオーダーの複雑さの表現では、我々は、O(logN個)としてまとめ、「底部」の対数を無視します。
以下に例示する(オーダー)O(nlogn) :
function aFun(n){
let i = 1;
while (i <= n) {
i = i * 2;
}
return i
}
function cal(n) {
let sum = 0;
for (let i = 1; i <= n; ++i) {
sum = sum + aFun(n);
}
return sum;
}
関数afun時間複雑度は、O(LOGN)であり、CAL時間複雑度はO(N)であり、T(N)= T1(LOGN)* T2(N)= O(LOGN *の複雑上記タイムコードようN)= O(nlogn)。
-
- 非多項式オーダー:データサイズ、実行時間と空間の占有の成長では、そのようなアルゴリズムパフォーマンスの低下をアルゴリズムを跳びました。
これは、O(2含まN-)(ステップインデックス)、O(N!)(注文階乗を)。
O(2 N - )(ステップインデックス)例:
aFunc( n ) {
if (n <= 1) {
return 1;
} else {
return aFunc(n - 1) + aFunc(n - 2);
}
}
答え:
明らか実行時間、T(0)= Tは、( 1)= 1、 T(N)=(N Tつつ - 1)+ Tは、(N - 2)+ 1、 ここで1回カウント付加であります実行。
明確T(n)が= Tが(N - 1)+ T(N - 2) されたフィボナッチ数、誘導によって示すことができることを証明するために、場合N> = 1 T(N)<( 5/3) N-、一方ときN> 4 T(N - )> =(3/2)N - 。
したがって、この方法の時間計算量はO((5/3)として表されてもよいN-)、後O(2に短縮しますN-)。
時間を実行しているこの方法のために必要な可視指数増殖率があります。
あなたが興味があるなら、あなたは次の入力サイズ1,10,100をテストするためのアルゴリズムの時間をされて実行してみることができ、私たちは、時間の複雑さの無限の魅力を感じるだろうと信じています。
3.5時間複雑カテゴリ
時間の複雑さを分けることができます:
- ベスト・ケースの時間計算量(最良のケースの時間計算):このコードの最良の場合の実行時間の複雑さ。
- 最悪の場合の時間複雑度(最悪の場合の時間の複雑性):このコードの実行時間の最悪の場合、複雑。
- ここで、平均時間複雑度(平均ケース時間複雑度は)、全ての場合においてコード実行の個数の加重平均として表しました。知られている加重平均時間計算または所望の時間複雑。
- 共有等しく時間の複雑さ(償却時間計算):複雑さとタイミング関係のハイレベルが発生したが、全ての場合において、コード実行の複雑さのほとんどの個々の高レベルの複雑さであることができる個々の場合の低レベルの複雑さであります複雑さの低いレベルに等しいシェア。低レベルに実質的に等しい結果が均等に複雑性を共有しました。
例えば:
// n 表示数组 array 的长度
function find(array, n, x) {
let i = 0;
let pos = -1;
for (; i < n; ++i) {
if (array[i] == x) {
pos = i;
break;
}
}
return pos;
}
関数は、xに等しいキー値の配列に見られる機能であり、それは-1を返す見つからない場合は、インデックス値を返し見つけます。
ベスト・ケースの時間計算量、最悪のケースの時間計算
配列内の最初の値がxに等しい場合、変数が配列xに存在しない場合、その後の時間複雑度は、O(1)であり、その後、我々はすべての(n)は、それが時間の複雑性Oなり再び配列全体をトラバースする必要があります。したがって、異なる状況下で、このコードの時間複雑度は同じではありません。
したがって、上記のコードは最好情况时间复杂度
O(1)、最坏情况时间复杂度
O(N)です。
平均的なケースの時間計算
平均時間の複雑さを分析する方法は?コードの複雑さの大きさの違いは、異なる状況で、コードの下で実行回数の加重平均は、すべての可能な場合に表示されます。
変数xは、アレイ内の位置を見つけるために、N + 1の場合があります:0〜N-1の配列の位置ではなく配列です。我々はアップ加え、次いでN + 1で割った横断するのに必要な要素の数を見つけ、それぞれの場合に、すなわち、要素の平均数が横断する必要が得ることができます:
簡略化された式の後、得られたように一定の省略因子、下位は、平均时间复杂度
O(N)です。
私たちは、あなたが、配列やない配列のいずれかで、変数xを探していることを知っています。どちらの場合も、トラブルの対応する確率と統計多くでは、我々は、確率は、アレイではなく、配列の両方が1/2であることを前提としています。さらに、0〜n-1のn個の位置の出現確率を見つけるためのデータが1 / nについても同様です。したがって、確率乗算の法則によれば、任意の位置で0〜N-1の発生確率を検索するデータは、1 /(2N)です。
したがって、最大の問題前の導出を考慮に様々な状況の発生のない可能性がないことです。私たちはそれぞれのケースの発生確率を置く場合も、考慮に平均時間の複雑さは、このなっ計算を取らされています。
この値は、確率論で加重平均とも呼ばれ、期待値、フルネームの平均時間計算量は呼ばれるべき加重平均時間計算量や時間の複雑期待を。
したがって、得られた上記に由来する結論は、平均时间复杂度
依然としてO(N)です。
償却時間複雑
償却時間の複雑さ(非常に限られ、非常に特別なシナリオが、ここでは言っていない)の平均時間の特別な種類の複雑さです。
3.6時間計算の概要
小から大まで取られ、共通の時間計算時間は以下のとおりです。
O(1)<O(LOGN)<(N)<O(nlogn)<O(N 2)<O(N 3)<O(2 N)<O(N!)<O(N N)
共通の時間の複雑さ:
空間分析の3.7複雑
複雑さの時間の略プログレッシブ時間複雑さを表し、アルゴリズムの実行時間とデータサイズとの間の関係の成長を。
空間複雑約類推は、フルネームであるプログレッシブ空間の複雑さ(漸近空間複雑さ)は、それが表すアルゴリズムとデータ記憶空間スケールの関係の成長を。
定義:必要な記憶容量を計算することによって実行されるアルゴリズムの空間の複雑さ、式と呼ばれるアルゴリズムの空間の複雑さ:S(N)= O(F(N))、Fであり、nは、スケール問題の(n)は、n個の文の関数としてのストレージスペースを占有。
function print(n) {
const newArr = []; // 第 2 行
newArr.length = n; // 第 3 行
for (let i = 0; i <n; ++i) {
newArr[i] = i * i;
}
for (let j = n-1; j >= 0; --j) {
console.log(newArr[i])
}
}
時間複雑分析と同様に、我々は、コードの2行目は、我々は変数newArr、空の配列を格納する領域に適用することを見ることができます。ライン3 newArr長さは、配列の長さがnである変化値の各々は、他に、未定義であるコードの複雑さの空間全体がOであるように、コードの残りの部分は、(より多くのスペースを占有しませんN)。
我々の共通の空間の複雑さはO(1)、O(N)、O(N 2)、O(LOGN)のように、O(nlogn ) 複雑さのこのような順序は、より通常小さいです。
4.どのように複雑な分析を習得するには?
キーは、よりトレーニングの複雑さを分析することで、いわゆる習うより慣れろ。
通常、私たちはコードを書くときには、時間やスペースのための時間のためのスペースを使用することです、それは時間の複雑さと空間の複雑度に基づいて測定することができます。
5.最後に
あなたが賞賛か私に星を与えるためにインスピレーションを得ているこの記事やアイテムを考える場合は、右、親指美徳である、あなたに感謝。
Iしばしばより多くの記事のアドレス:GitHubの
参考記事:
(上)分析の複雑さは:どのようなアルゴリズムと資源消費統計の効率を分析するには?
(データ構造)10分は、アルゴリズムの時間の複雑さを取得します