ホームページ > 記事 > ウェブフロントエンド > アルゴリズムの時間計算量と空間計算量について説明する記事
この記事ではアルゴリズムについて学び、アルゴリズムの時間計算量と空間計算量について紹介します。
アルゴリズムとは、データを操作してプログラムの問題を解決するために使用される一連のメソッドを指します。同じ問題に対して、異なるアルゴリズムを使用すると、最終結果は同じになる可能性がありますが、プロセスで消費されるリソースと時間は大きく異なります。
それでは、さまざまなアルゴリズムの長所と短所をどのように測定すればよいのでしょうか?
主にアルゴリズムが占める「時間」と「空間」の2つの次元から考えます。
時間ディメンション: 現在のアルゴリズムの実行にかかる時間を指します。通常、これを説明するために「時間計算量」を使用します。
空間次元: 現在のアルゴリズムを実行するために必要なメモリ空間の量を指します。通常、これを説明するために「空間複雑さ」を使用します。
したがって、アルゴリズムの効率の評価は、主に時間計算量と空間計算量に依存します。ただし、時間と空間が「ケーキを食べながらも食べる」場合があり、両方を同時に持つことはできないため、バランス ポイントを見つける必要があります。
「時間計算量」と「空間計算量」の計算方法をそれぞれ紹介します。
アルゴリズムの「時間計算量」を知りたいです。多くの人が最初に考える方法は、アルゴリズム プログラムを 1 回実行することです。次に、それにかかる時間計算量を計算します。時間は自然にやってきます。
この方法は可能ですか?もちろんそれは可能ですが、多くのデメリットもあります。
この方法は動作環境の影響を非常に受けやすいため、高性能のマシンで実行した結果と、低パフォーマンスのマシンで実行した結果は大きく異なります。また、テストで使用されるデータの規模にも大きく関係します。さらに、アルゴリズムを作成した時点では、それを完全に実行する方法はまだありませんでした。
したがって、別のより一般的な方法が登場します。「 Big O notation」、つまり、T(n) = O(f(n))
としましょう。まず例を見てみましょう:
for(i=1; i<=n; ++i) { j = i; j++; }
「Big O notation」を使用すると、このコードの時間計算量は次のようになります: O(n)、なぜですか?
In Big O 表記の時間計算量の公式は次のとおりです: T(n) = O( f(n) )、ここで f(n) はコードの各行の実行回数の合計を表し、O は比例関係、つまり完全な値を表します。この式の名前は次のとおりです: アルゴリズムの漸近時間計算量。
引き続き上記の例を見てみましょう。コードの各行の実行時間が同じであると仮定します。それを表すために 1 パーティクル時間を使用します。この例の最初の行には 1 パーティクル時間がかかります。コードの 3 行目は 1 粒子時間かかります。行の実行時間は n 粒度時間で、4 行目の実行時間も n 粒度時間です (2 行目と 5 行目はシンボルなので、今のところ無視してください)。この場合、合計時間は 1 粒度時間 n 粒度時間 n 粒度時間、つまり (1 2n) 粒子時間、つまり: T(n) = (1 2n)*粒子時間 この結果から、このアルゴリズムの消費時間は n の変化とともに変化します。したがって、このアルゴリズムの時間計算量は次のように簡略化できます: T(n) = O(n)
なぜこのように簡略化できるのでしょうか?ビッグ O 表記は、コード実行時間の増加傾向を表すために使用される、アルゴリズムの実行時間を実際に表すために使用されないためです。
したがって、上記の例では、n が無限大の場合、T(n) = time(1 2n) の定数 1 は意味がなく、倍数 2 も意味がありません。したがって、T(n) = O(n) に単純化できます。
一般的な時間計算量のメトリクスは次のとおりです。
定数次数 O(1)
対数次数 O(logN )
線形次数 O(n)
線形対数次数 O(nlogN)
二乗次数 O (n²)
3 次 O(n³)
定数順序 O(1)
int i = 1; int j = 2; ++i; j++; int m = i + j;上記のコードが実行されると、特定の変数が増加してもその消費量は増加しません。そのため、このタイプのコードがどれだけ長くても、たとえ数万個のコードがあったとしても、または数十万行の場合、O(1) を使用して時間計算量を表現できます。
#線形順序 O(n)
for(i=1; i<=n; ++i) { j = i; j++; }
このコードでは、for ループ内のコードが n 回実行されるため、n が変化すると消費時間が変化するため、このタイプのコードは次のようになります。時間計算量を表すために O(n) を使用しました。
最初にコードを見てみましょう:
int i = 1; while(i<n) { i = i * 2; }
从上面代码可以看到,在while循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。我们试着求解一下,假设循环x次之后,i 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2^n
也就是说当循环 log2^n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(logn)
线性对数阶O(nlogN)
线性对数阶O(nlogN) 其实非常容易理解,将时间复杂度为O(logn)的代码循环N遍的话,那么它的时间复杂度就是 n * O(logN),也就是了O(nlogN)。
就拿上面的代码加一点修改来举例:
for(m=1; m<n; m++) { i = 1; while(i<n) { i = i * 2; } }
平方阶O(n²)
平方阶O(n²) 就更容易理解了,如果把 O(n) 的代码再嵌套循环一遍,它的时间复杂度就是 O(n²) 了。
举例:
for(x=1; i<=n; x++) { for(i=1; i<=n; i++) { j = i; j++; } }
这段代码其实就是嵌套了2层n循环,它的时间复杂度就是 O(n*n),即 O(n²)
如果将其中一层循环的n改成m,即:
for(x=1; i<=m; x++) { for(i=1; i<=n; i++) { j = i; j++; } }
那它的时间复杂度就变成了 O(m*n)
立方阶O(n³)、K次方阶O(n^k)
参考上面的O(n²) 去理解就好了,O(n³)相当于三层n循环,其它的类似。
除此之外,其实还有 平均时间复杂度、均摊时间复杂度、最坏时间复杂度、最好时间复杂度 的分析方法,有点复杂,这里就不展开了。
既然时间复杂度不是用来计算程序具体耗时的,那么我也应该明白,空间复杂度也不是用来计算程序实际占用的空间的。
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度,同样反映的是一个趋势,我们用 S(n) 来定义。
空间复杂度比较常用的有:O(1)、O(n)、O(n²),我们下面来看看:
空间复杂度 O(1)
如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
举例:
int i = 1; int j = 2; ++i; j++; int m = i + j;
代码中的 i、j、m 所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)
空间复杂度 O(n)
我们先看一个代码:
int[] m = new int[n] for(i=1; i<=n; ++i) { j = i; j++; }
这段代码中,第一行new了一个数组出来,这个数据占用的大小为n,这段代码的2-6行,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)
以上,就是对算法的时间复杂度与空间复杂度基础的分析,欢迎大家一起交流。
更多算法相关知识,请访问:编程入门!!
以上がアルゴリズムの時間計算量と空間計算量について説明する記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。