ほとんどの場合、時間の複雑性はスペースの複雑性に関連しており、逆もまた同様です。たとえば、配列トラバーサルの場合:
for i=1 to length(v)
print (v[i])
endfor
ここでは、時間に関するアルゴリズムの複雑さはO(n)であることが簡単にわかりますが、スペースの複雑さもn(O(n)?で表される)のように見えます。
私の質問:アルゴリズムは時間の複雑さと空間の複雑さが異なる可能性はありますか?
time と space の複雑さは互いに関連していません。これらは、入力に基づいてアルゴリズムが使用するスペース/時間を記述するために使用されます。
たとえば、アルゴリズムにspace複雑性がある場合:
O(1)
-定数-アルゴリズムは、入力に依存しない固定(少量)のスペースを使用します。入力のサイズごとに、アルゴリズムは同じ(一定の)スペースを使用します。これは、入力が考慮されておらず、重要なのはprint
コマンドの時間/空間であるため、この例の場合です。O(n)
、O(n^2)
、O(log(n))
...-入力の長さに基づいて追加のオブジェクトを作成することを示します。たとえば、v
の各オブジェクトのコピーを作成して配列に保存し、その後印刷する場合は、n
追加オブジェクトを作成するときにO(n)
スペースが必要です。対照的に、timeの複雑さは、入力の長さに基づいてアルゴリズムが消費する時間を表します。再び:
O(1)
-入力の大きさに関係なく、常に一定の時間がかかります-たとえば、1つの命令のみ。好む
function(list l) {
print("i got a list");
}
O(n)
、O(n^2)
、O(log(n))
-これも入力の長さに基づいています。例えば
function(list l) {
for (node in l) {
print(node);
}
}
最後の例は両方ともO(1)
スペースを使用するため、何も作成しないことに注意してください。それらを比較する
function(list l) {
list c;
for (node in l) {
c.add(node);
}
}
サイズが入力のサイズに線形に依存する新しいリストを作成するため、O(n)
スペースを使用します。
あなたの例は、時間とスペースの複雑さが異なる場合があることを示しています。すべての要素を印刷するには、v.length * print.time
が必要です。ただし、スペースは常に同じです。追加のオブジェクトを作成しないため、O(1)
です。そのため、はい、アルゴリズムは互いに依存していないため、時間と空間の複雑さが異なる可能性があります。
時間と空間の複雑さは、アルゴリズムの効率を計算するさまざまな側面です。
時間の複雑さは、入力のサイズの変化によってアルゴリズムの計算時間がどのように変化するかを調べることを扱います。
一方、空間の複雑さは、入力サイズを変更した場合にアルゴリズムに必要な(余分な)空間の量を見つけることを扱います。
アルゴリズムの時間の複雑さを計算する最良の方法は、入力のサイズが増加するかどうかを確認することです。比較(または計算ステップ)の数も増加します。スペースの複雑さを計算するには、アルゴリズムは、入力のサイズが変わると変わります。
良い例は Bubble sort です。
5つの要素の配列をソートしようとしたとしましょう。最初のパスでは、最初の要素と次の4つの要素を比較します。 2番目のパスでは、2番目の要素と次の3つの要素を比較し、リストが完全になくなるまでこの手順を続けます。
10個の要素をソートしようとするとどうなりますか。この場合、最初の要素を次の9個の要素と比較し、次に2番目の要素を次の8個の要素と比較することから始めます。つまり、N要素の配列がある場合、最初の要素をN-1個の要素と比較し、次に2番目の要素をN-2個の要素と比較することから始めます。これにより、O(N^2)
時間の複雑さが生じます。
しかし、サイズはどうですか。 5要素または10要素の配列をソートしたときに、追加のバッファまたはメモリスペースを使用しました。あなたははいと言うかもしれませんが、一時変数を使用してスワップを行いました。ただし、配列のサイズを5から10に増やしたときに変数の数は変更されました。いいえ、入力のサイズに関係なく、常に1つの変数を使用してスワップを行います。これは、入力のサイズがO(1)
または一定のスペースの複雑さをもたらす必要がある追加のスペースとは無関係であることを意味します。
ここで、演習として、 merge sort の時間と空間の複雑さについて調査します
まず、このループのスペースの複雑さはO(1)
です(アルゴリズムが必要とするストレージの量を計算するとき、入力は通常含まれません)。
だから私が持っている問題は、アルゴリズムが空間の複雑さと異なる時間の複雑さを持っている可能性があるということですか?
はい、そうです。一般に、アルゴリズムの時間と空間の複雑さは互いに関連していません。
場合によっては、一方を他方を犠牲にして増やすことができます。これは 時空間トレードオフ と呼ばれます。
時間と空間の複雑さの間にはよく知られた関係があります。
まず、時間は明らかにスペース消費の限界です。時間tでは、O(t)のメモリセルを超えることはできません。これは通常、包含によって表現されます
DTime(f) ⊆ DSpace(f)
ここで、DTime(f)とDSpace(f)は、時間(それぞれ、スペース)O(f)の決定論的チューリングマシンによって認識可能な言語のセットです。つまり、問題が時間O(f)で解決できる場合、空間O(f)でも解決できるということです。
あまり明らかではないのは、空間が時間に縛られているという事実です。サイズnの入力で、レジスタ、キャッシュ、すべてを含むf(n)メモリセルを自由に使用できると仮定します。これらのセルをallpossiblewaysで記述した後、最終的に計算を停止することができます。ループします。バイナリアルファベットでは、f(n)セルを2 ^ f(n)の異なる方法で記述できます。これにより、時間の上限が与えられます。この境界内で計算が停止するか、計算は停止しないため、強制終了します。
これは通常、インクルージョンで表現されます
DSpace(f) ⊆ Dtime(2^(cf))
一定の場合c。定数cの理由は、LがDSpace(f)にある場合、それがSpace O(f)で認識されることだけを知っているのに対し、前の推論では、fは実際の境界であったためです。
上記の関係は、非決定論的な計算モデルを含むより強力なバージョンに包含されています。これは、教科書で頻繁に述べられている方法です(例えば、Papadimitriouによる計算複雑性の定理7.4を参照)。
はい、これは間違いなく可能です。たとえば、n
実数のソートにはO(n)
スペースが必要ですが、O(n log n)
時間は必要です。スペースを初期化する時間が実行時間に含まれるため、スペースの複雑さは常に時間の複雑さで下限になるのは事実です。
時にははい、それらは関連しており、時には関連していない、実際には動的プログラミングのように、より高速なアルゴリズムを取得するためにより多くのスペースを使用することがあります https://www.codechef.com/wiki/tutorial-dynamic-programming 動的プログラミングはメモ化またはボトムアップを使用します。最初の手法はメモリを使用して繰り返し解を記憶するため、アルゴリズムは解のリストからそれらを取得するのではなく、再計算する必要がありません。ボトムアップアプローチは小さなソリューションから始まり、最終的なソリューションに到達するために構築されます。次の2つの簡単な例では、1つは時間と空間の関係を示し、もう1つは関係を示していません。1から特定のn整数までのすべての整数の合計を求めたいとします。
sum=0
for i=1 to n
sum=sum+1
print sum
このコードはメモリi => 2、n => 2およびsum => 2バイトから6バイトのみを使用したため、時間の複雑さはO(n)であり、スペースの複雑さはO(1) code2です。
array a[n]
a[1]=1
for i=2 to n
a[i]=a[i-1]+i
print a[n]
このコードは、配列のメモリから少なくともn * 2バイトを使用したため、スペースの複雑さはO(n)であり、時間の複雑さもO(n)です。
アルゴリズムが必要とするストレージスペースの量は、解決する問題のサイズによって異なります。スペースの複雑さは通常、桁数で表されます。 O(N ^ 2)は、問題のサイズ(N)が2倍になると、4倍の作業用ストレージが必要になることを意味します。