ディレクトリ
私たちはしばしば、実際には、我々はそのような機会うちアクティブまたは無意識のうちにフィルタされ、それは決してかなり作業データ構造とアルゴリズム言います。
四概念的な複雑さ
焦点を当てる4つの分析の複雑さの知識。
最好情况时间复杂度
(最良の場合の時間
複雑さ):時間の理想的な場合に、コードの複雑さ。最坏情况时间复杂度
(最悪のケースの時間計算):最悪の場合の複雑さのコードの実行;平均情况时间复杂度
(平均ケース時間計算):すべての場合において発現実行コードの時間の加重平均数を有します。均摊时间复杂度
(償却時間複雑度):ほとんどの低レベルの複雑さのすべての場合においてコード実行の複雑さが、高レベルの個々の状況は、タイミング関係を有する複雑で、個々の高レベルの複雑さは、ローレベルと発生の程度にも同様に共有することができ複雑。低レベルに実質的に等しい結果が等しく複雑共用しました。
あなたはこれらの概念を把握することができるならば、それは、あなたのため、このセクションがない大きな問題の分析の複雑さです。
なぜ導入
- 同じコードの時間複雑さは、これら四つの概念を導入して、より包括的にするため、時間計算コードのより正確な説明では、異なる状況の違いの順に表示されます。
- 違いコードの複雑さの大きさが異なる状況で表示されたとき、私たちは4つの複雑さを区別する必要があります。ほとんどの場合、分析は、それらを区別する必要はありません。
どのように分析するには
最高、最悪時間計算量
- コード例:
// n 表示数组 array 的长度
int find(int[] array, int n, int x) {
int i = 0;
int pos = -1;
for (; i < n; ++i) {
if (array[i] == x) pos = i;
}
return pos;
}
このコード機能を実装することである、無秩序アレイ(配列)において、可変検索
x
位置が現れます。見つからない場合は、返品-1
。分析方法は、クラス会話によれば、このコードの複雑さがあるO(n)
れ、n
配列の長さを表します。
先のサイクルの終わりになるための方法を見つけることが可能であるので、私たちは、すべての繰り返し配列全体を横断するたびに必要としない配列内のデータを検索します。
- 上記のコードを最適化して下さい
// n 表示数组 array 的长度
int find(int[] array, int n, int x) {
int i = 0;
int pos = -1;
for (; i < n; ++i) {
if (array[i] == x) {
pos = i;
break;
}
}
return pos;
}
問題が来ます。我々は、このコードの時間の複雑さを最適化し終えるか後
O(n)
か?もちろん、話の分析は、この問題を解決することはできません。
- 検索したい変数があるため
x
、アレイ内の任意の場所に表示されることがあります。配列の最初の要素は変数を探すことだけであればx
、残りのトラバースを継続する必要はありませんn-1
データが、それは時間の複雑さですO(1)
。 - 変数が配列に存在しない場合は、
x
、その後、我々は再び配列全体を横断する持っている必要があり、時間の複雑さとなっていますO(n)
。
したがって、異なる状況下で、このコードの時間複雑度は同じではありません
- 上記
O(1)
すなわち、最良の時間複雑さ、O(n)
即ち、最悪の場合の時間複雑。
平均時間の複雑さ
時間の複雑性を、対応する最良ケースおよび最悪のケースの時間複雑度が極端なケースの場合のコードの複雑さ、発生確率は大きくありません。
より良い平均的なケースの複雑さを表現するために、我々は別の概念を導入する必要があります。状況の平均時間の複雑さは、私はに戻って言及平均時間複雑。
- 上記の変数で見つけるために
x
あなたにそれを説明するための例を。変数見つけるにはx
、配列内の位置を、そこにあるn+1
:状況の種類の配列で0~n-1
の位置や配列ではないが。我々は要素の数を探し、それぞれの場合に横断するために必要な累積アップ、そして分割をn+1
使用すると、要素の数を取得することができ、横断するのに必要な平均値を、すなわち、:
2.私たちは、時間の複雑さということを知っているランダウの記号は、私達はちょうどこの式、複雑さが得られた平均時間を簡素化入れた後、そう、率、低レベル、定数を省略することができますO(n)
。
- この結論は正しいのですが、計算は少し問題を処理しますが。何が問題でしょうか?私達はちょうどこのについて話した
n+1
場合、確率は同じではありません。
ここでは少し使い
概率论
知識のを、非常に単純で、心配しないでください。)
-
私たちは、変数を検索したいことを知っている
x
配列の配列にかのいずれか、。どちらの場合も、対応する確率統計トラブルの多くは、あなたの理解を容易にするために、我々は確率が配列されておらず、配列があることを前提と1/2
。加えて、データは、見ているように見える0~n-1
n個の位置の確率と同じです1/n
。したがって、確率乗算の法則によると、データを見ているように見える0~n-1
ことのどこ確率1/(2n)
。 -
したがって、最大の問題前の導出を考慮に様々な状況の発生のない可能性がないことです。私たちはそれぞれのケースの発生確率を置く場合も考慮し、ということさの平均時間計算量演算処理は、このようになります。
この値は、確率論で加重平均とも呼ばれ、期待値、フルネームの平均時間計算量は呼ばれるべき加重平均時間計算や時間計算の期待。
- 確率、コードの前部の加重平均の導入後
(3n+1)/4
。O表記大で表され、定数係数、このコードが残っの加重平均時間複雑さを取り除きますO(n)
。
あなたは、良い複雑なああの平均時間複雑分析を言うだけでなく、確率論の知識を必要とするかもしれません。実際には、ほとんどの場合、我々は、最高と最悪の間で3例の平均場合の時間の複雑さを区別する必要はありません。移動中のそれらのような例は、のように、非常に多くの場合、我々は需要を満たすために複雑さを使用しています。
異なる状況におけるコードの唯一同じ部分、ギャップのオーダーの時間複雑さがあり、我々は区別するためにこれら三つの複雑さの表記を使用します。
概要:コードの複雑さの大きさの違いが異なる場合に発生可能なすべてのケースの実行コードの回数と、の加重平均図。
償却時間複雑
2つの条件が満たされたときに使用します:
- コードは、ほとんどの場合、低レベルの複雑さ、高レベルの複雑さの例はほんの一握りです。
- 低レベルと高レベルの複雑さは、タイミングルールが表示されます。
特定の分析参考ブログ:https://github.com/foreverZ133/Beauty-of-Data-Structure-and-Algorithms/issues/5
結果は等しく、一般的に共有されている複雑さの低いレベル、すなわちに等しい最良の場合の時間複雑。
実際の分析
コード:
// 全局变量,大小为 10 的数组 array,长度 len,下标 i。
int array[] = new int[10];
int len = 10;
int i = 0;
// 往数组中添加一个元素
void add(int element) {
if (i >= len) { // 数组空间不够了
// 重新申请一个 2 倍大小的数组空间
int new_array[] = new int[len*2];
// 把原来 array 数组中的数据依次 copy 到 new_array
for (int j = 0; j < len; ++j) {
new_array[j] = array[j];
}
// new_array 复制给 array,array 现在大小就是 2 倍 len 了
array = new_array;
len = 2 * len;
}
// 将 element 放到下标为 i 的位置,下标 i 加一
array[i] = element;
++i;
}
- ベストケースの時間計算
O(1)
- 最悪の場合の分析:
最悪の場合のコード数を用いて実行されたアレイの各々の長さに関連する
最初の呼び出しのインサートの実行回数Nであり、
インサートの第二の呼び出しの実行回数が2Nで、
インサートA第3コール実行回数は2 ^ 2 * nは
、インサートのk番目のコールの実行回数2 ^(K-1)*は N
最悪時間計算量ですO(n)
。 - 平均的なケースの分析
それぞれに発生する最悪の場合の配列をするときに実行される2倍扩容
原稿が新しい配列の配列に導入された配列の長さが増加するが、しかし、挿入部の落下が同じ長さを、それぞれ0 ~ len-1
、len ~ (2len-1)
、...。
インサートケースはまだlen+1
種類:0~len-1
と突き後O(len)
、各インサートの確率があるので。 、
そして最終的に加重平均時間計算量を取得し1*p + 2*p+ ... + len*p + len * p = O(1)
、 - 償却時間複雑さ
O(1)
と等しく、それぞれの複雑さに起因共有O(len)
発生が続いlen
倍O(1)
、コヒーレントであるためであろうO(len)
と株式を等しく
フロントlen
償却複雑である描く、第二にO(1)
。