web-dev-qa-db-ja.com

これは技術的には「Hello World」のO(1)アルゴリズムですか?

これは、「Hello、World!」のO(1)アルゴリズムとして分類されますか?

public class Hello1
{
   public static void Main()
   {
      DateTime TwentyYearsLater = new DateTime(2035,01,01);
      while ( DateTime.Now < TwentyYearsLater )
      { 
          System.Console.WriteLine("It's still not time to print the hello ...");
      }
      System.Console.WriteLine("Hello, World!");
   }
}

私は使用することを考えています

DateTime TwentyYearsLater = new DateTime(2035,01,01);
while ( DateTime.Now < TwentyYearsLater )
{ 
   // ... 
}

誰かが特定の複雑さのアルゴリズムを要求するたびに冗談として入れるためのビジーループとしてのコードスニペット。これは正しいでしょうか?

117
Subpar Web Dev

このコンテキストでのBig O表記は、関数の入力のサイズと、その入力の結果を計算するために実行する必要がある操作の数との関係を記述するために使用されています。

操作には出力を関連付けることができる入力がないため、Big O表記の使用は無意味です。操作にかかる時間は、操作の入力の独立です(...なし)。 is入力と実行される操作の数との間に関係がないため、Big Oを使用してその存在しない関係を記述することはできません

403
Servy

Big-O表記とは、おおよそ「作業量Nに対して操作を与えた場合、アルゴリズムはNに比例して計算時間をどれだけ取るか」を意味します。たとえば、サイズNの配列のソートには、N ^ 2、Nlog(N)などを使用できます。

これには、処理する入力データがありません。したがって、O(anything)ではありません。

さらに悪いことです。これは技術的にはアルゴリズムではありません。アルゴリズムは、数学関数の値を計算する方法です。数学関数は、1つの入力から出力へのマッピングです。これは入力を受け取らず、何も返さないため、数学的な意味では関数ではありません。ウィキペディアから:

アルゴリズムは、有限量の空間と時間内で、関数を計算するための明確に定義された形式言語で表現できる効果的な方法です。初期状態と初期入力(おそらく空)から始まり、命令は、実行時に有限数の明確に定義された連続状態を進み、最終的に「出力」を生成し、最終終了状態で終了する計算を記述します。

技術的には、これは制御システムです。ウィキペディアから;

制御システムは、他のデバイスまたはシステムの動作を管理、コマンド、指示、または規制するデバイスまたはデバイスのセットです。

数学関数とアルゴリズムの違い、およびコンソール出力、グラフィックスの表示、ロボットの制御などの副作用を行うコンピューターのより強力な能力について、より詳細な回答が必要な場合は、 read of強い教会チューリング仮説に関するこの論文

要約

入力(有理数または有限文字列)から出力への閉ボックス変換としての位置計算の古典的な考え方。コンピューティングの対話型ビューによると、計算は、入力から出力への関数ベースの変換ではなく、進行中の対話型プロセスです。具体的には、外の世界との通信は、計算の前後ではなく計算中に行われます。このアプローチは、計算とは何か、モデル化される方法についての理解を根本的に変えます。

新しいパラダイムとしての相互作用の受け入れは、チューリングマシン(TM)がすべての計算をキャプチャするという広範な信念である強い教会チューリングテーゼ(SCT)によって妨げられているため、TMよりも表現力のある計算モデルは不可能です。このホワイトペーパーでは、SCTが元の教会チューリングテーゼ(CTT)を、チューリングが意図していない方法で再解釈することを示します。その一般的に想定されているオリジナルと同等のものは神話です。 SCTが広く信じられている歴史的な理由を特定し、分析します。それが偽であることを受け入れることによってのみ、計算の代替パラダイムとして相互作用を採用し始めることができます。

88
Steve Cooper

いいえ、コードにはO(2^|<DeltaTime>|)という時間の複雑さがあります。

現在時刻を適切にコーディングするため。
最初に私の英語について謝罪させてください。

CSでのBig Oの機能と仕組み

ビッグO表記プログラムの入力を実行時間と関連付けるために使用されません
Big O表記は、厳密さを残して、2つの量の漸近比を表現する方法です。

アルゴリズム分析の場合、これらの2つの量はnot入力(最初に「測定」機能が必要)と実行時間です。
これらは問題のインスタンスのコーディングの長さです1 および対象のメトリック。

一般的に使用されるメトリックは次のとおりです。

  1. 特定の計算モデルでアルゴリズムを完了するために必要なステップの数。
  2. そのような概念が存在する場合、計算モデルに必要なスペース。

暗黙的にモデルとしてTMが想定されているため、最初のポイントは遷移の数のアプリケーションに変換されます。2 function、つまり「ステップ」、2番目は少なくとも1回書き込まれた異なるテープセルの数を変換します

また、元のエンコーディングの代わりに多項式関連のエンコーディングを使用できると暗黙的に想定されていることもよくあります。たとえば、そのようなインスタンスのコーディングが複雑であるにもかかわらず、最初から最後まで配列を検索する関数はO(n)複雑です配列の長さはn*b+(n-1)である必要があります。ここで、bは、各要素のシンボルの(一定の)数です。これは、bは計算モデルの定数と見なされるため、上記の式とnは漸近的に同じであるためです。

また、これは、 Trial Division のようなアルゴリズムが、本質的にfor(i=2; i<=sqr(N); i++)のようなアルゴリズムであるにもかかわらずexponentialアルゴリズムである理由を説明します。3

this を参照してください。

これはまた、いくつかのアルゴリズムにkパラメーターがあることは珍しいことではないので、大きなO表記が問題を説明するのに必要な多くのパラメーターを使用できることを意味します。

したがって、これは「入力」または「入力がない」ことについてではないです。

スタディケース

Big O表記はアルゴリズムに疑問を投げかけるものではなく、自分が何をしているのかを知っていることを前提としています。それは本質的にどこでも適用可能なツールであり、意図的にトリッキーな(あなたのような)アルゴリズムにもです。

問題を解決するには、現在の日付と将来の日付を使用したため、それらは何らかの形で問題の一部である必要があります。簡単に言えば、それらは問題のインスタンスの一部です。

具体的には、インスタンスは次のとおりです。

<DeltaTime>

<>は、任意の、非病理学的な選択のコーディングを意味します。

非常に重要の説明については、以下を参照してください。

したがって、大きなOの複雑さの時間はO(2^|<DeltaTime>|)に過ぎません。これは、現在の時間の値に依存する多数の反復を行うためです。漸近表記法は定数を排除するので便利なので、他の数値定数を置くことには意味がありません(たとえば、O(10^|<DeltaTime>|*any_time_unit)の使用は無意味です)。

トリッキーな部分は

上記の1つの重要な仮定を行いました:計算のモデルは5 時間であり、時間によって私は(本当の?)物理的な時間を意味します。標準的な計算モデルにはそのような概念はありません。TMは時間を認識しません。これが私たちの現実の仕組みであるため、時間をステップの数とリンクします。4

ただし、モデルでは時間は計算の一部です。Mainは純粋ではないが概念は同じであると言うことで、機能的な人々の用語を使用できます。

これを理解するには、フレームワークが物理時間の2、5、10倍速く実行される偽の時間を使用することを妨げるものは何もないことに注意する必要があります。このようにして、コードは「時間」の「半分」、「1/5」、「1/10」で実行されます。

このリフレクションは、<DeltaTime>のエンコーディングを選択するために重要です。これは、本質的に<(CurrentTime、TimeInFuture)>を記述する簡潔な方法です。優先順位には時間が存在しないため、CurrentTimeのコーディングはWordNow(または他の選択肢)である可能性が高く、前日はYesterday、物理的な時間が進むにつれて(そしてDeltaTimeの1つが減少するにつれて)コーディングの長さincreaseという仮定を破ることにより、

有用なことを行うには、計算モデルで時間を適切にモデル化する必要があります。

私たちができる唯一の安全な選択は、物理的な時間が進むにつれて、長さを増してタイムスタンプをエンコードすることです(ただし、単項は使用しません)。これは、必要な時間の唯一の真のプロパティであり、エンコーディングがキャッチする必要があるプロパティです。アルゴリズムに時間の複雑さが与えられるのは、このタイプのエンコーディングのみです。

もしあれば、あなたの混乱は、「timeの複雑さは何ですか?」というフレーズの中の単語timeから生じるそして「どれくらいtimeかかりますか?」非常に異なることを意味します

悲しいかな、用語は同じ単語を使用していますが、頭の中で「ステップの複雑さ」を使用して質問を再試行してみてください。


1 また、各インスタンスの長さは異なるが、任意ではないため、漸近的アプローチの必要性についても説明しています。
2 ここで正しい英語の用語を使用していると思います。
3 また、これが数学でlog(log(n))用語を見つける理由です。
4 同じように、ステップは有限の時間を占める必要がありますが、ヌルではなく、接続されていない時間間隔も必要です。
5 これは、その中の物理時間の知識としての計算モード、つまりその用語で表現できることを意味します。類推は、ジェネリックが.NETフレームワークでどのように機能するかです。

41
Yuni Mj

ここにはたくさんの素晴らしい答えがありますが、それらすべてを少し言い換えてみましょう。

functionsを記述するBig-O表記が存在します。アルゴリズムの分析に適用する場合、このアルゴリズムの特性をfunctionで定義する必要があります。一般的な選択は、ステップ数入力サイズの関数として考慮することです。他の回答で述べたように、明確に定義された「入力」がないため、あなたのケースでそのような関数を思い付くのは奇妙に思えます。それでも私たちはそれを試みることができます:

  • アルゴリズムは、任意のサイズの入力を受け取り、それを無視し、一定時間待機して終了する定数関数と見なすことができます。この場合、ランタイムはf(n const)==であり、O(1)-timeアルゴリズムです。これはあなたが聞くことを期待したことですよね? はい、技術的にはO(1)-アルゴリズムです。
  • TwentyYearsLaterは、関心のある「入力サイズ」のようなパラメーターと見なすことができます。この場合、ランタイムはf(n(n-x))==です。ここでxは、呼び出し時の「現在の時刻」です。このように見えるとき、それはO(n)時間アルゴリズムです。 技術的にO(1)-algorithmを他の人に見せに行くときはいつでも、この反論を期待してください。
  • ああ、でも待って、もしk =TwentyYearsLaterが入力なら、そのsizenは実際にはビット数つまり、n = log(k)を表すために必要です。したがって、入力のサイズnとランタイムの依存関係はf(n 2 ^ n-x)==です。アルゴリズムが指数関数的に遅くなったようです! うーん
  • プログラムへの別の入力は、実際には回答のストリームループ内のDateTime.Now呼び出しのシーケンスにOSによって与えられます。実際、このシーケンス全体がプログラムを実行する瞬間に入力として提供されることを想像できます。ランタイムは、このシーケンスのプロパティ、つまり最初のTwentyYearsLater要素までの長さに依存すると考えることができます。この場合、ランタイムは再びf(n n)==になり、アルゴリズムはO(n)になります。

しかし、繰り返しますが、あなたの質問では、ランタイムに興味があるとさえ言わなかったのです。メモリ使用を意味する場合はどうなりますか?状況をどのようにモデル化するかに応じて、アルゴリズムはO(1)メモリまたはおそらくO(n)メモリであると言うことができます(DateTime.Nowの実装が呼び出しシーケンス全体を追跡する必要がある場合) 。

そして、あなたの目標がばかげたものを思いつくことであったなら、画面にピクセル単位のアルゴリズムのコードのサイズが選択されたズームレベルに依存することに興味があると言ってみませんか。これはf(zoom 1/zoom)==のようになり、アルゴリズムをO(1/n)-pixel sizeと宣言できます!

29
KT.

私は少しだけセルビーに反対しなければなりません。明らかではない場合でも、このプログラムへの入力があり、それがシステムの時間です。これは意図していない技術かもしれませんが、TwentyYearsFromNow変数はシステムの現在から20年ではなく、2035年1月1日に静的に割り当てられています。

したがって、このコードを取得して、1970年1月1日のシステム時刻を持つマシンで実行すると、コンピューターの速度に関係なく、完了するのに65年かかります(クロックに問題がある場合は、多少のばらつきがある場合があります) )。このコードを取得して、システム時刻が2035年1月2日のマシンで実行すると、ほぼ瞬時に完了します。

入力nJanuary 1st, 2035 - DateTime.Nowで、O(n)です。

次に、操作の数の問題もあります。一部の人々は、より高速なコンピューターがより速くループをヒットし、より多くの操作を引き起こすことに気づきましたが、それは無関係です。 big-O表記を使用する場合、プロセッサの速度や操作の正確な数は考慮しません。このアルゴリズムを使用してコンピューターで実行し、その後同じコンピューターで10倍長く実行した場合、操作の数は同じ10倍になると予想されます。

これに関して:

[編集済みのコード]スニペットを、誰かが特定の複雑さのアルゴリズムを求めるたびに冗談として入れるためのビジーループとして使用することを考えています。これは正しいでしょうか?

いいえ、そうでもありません。他の答えがこれをカバーしているので、私はそれを言及したかっただけです。一般的に、長年の実行をbig-O表記に関連付けることはできません。例えば。実行の20年= O(n ^ 87)またはそれ以外のことを言う方法はありません。あなたが与えたアルゴリズムでさえ、TwentyYearsFromNowを20110年、75699436年、または123456789年に変更できましたが、big-OはまだO(n)です。

21
Shaz

Big-O分析では、処理されるデータ量が無制限に増加するため、処理量が処理されます。

ここでは、固定サイズの単一オブジェクトのみを処理しています。そのため、big-O分析の適用は、用語の定義方法に大きく依存しています(主に?)。

たとえば、一般的に出力を印刷し、妥当な量のデータが正確に同じ期間に印刷されるように長い間待機することを意味します。また、非常に遠くまで到達するために、多少変わった(まったく間違っていない場合)定義の方法でもう少し追加する必要があります-特に、big-O分析は通常の数で定義されます特定のタスクを実行するために必要な基本的な操作(ただし、実行されるCPUの使用/操作だけでなく、メモリの使用などの観点から複雑さも考慮できることに注意してください)。

しかし、基本的な操作の数は通常、かなりの時間を要すると解釈されるため、この2つを同義語として扱うのは大したことではありません。ただし、残念ながら、処理中のデータ量は無制限に増加します。その場合、課すことができる固定遅延は実際には機能しません。 O(1)をO(N)と同等にするには、無限量のデータを印刷するのと同じように、一定量のデータが印刷に永遠にかかるように無限遅延を課す必要があります。

13
Jerry Coffin

何に関連するビッグO?

twentyYearsLaterが「入力」であることを直感しているようです。実際に関数を次のように書いた場合

void helloWorld(int years) {
   // ...
}

それはO(N)で、N =年(または単にO(years)と言う)です。

あなたのアルゴリズムは、twentyYearsLater =で始まるコード行にたまたま書いた数字に関連するO(N)であると言います。しかし、人々は通常、実際のソースコードの数字を入力と見なしません。コマンドライン入力を入力として、または関数シグネチャ入力を入力とみなす場合がありますが、ほとんどの場合ソースコード自体は考慮しません。それはあなたがあなたの友人と論争していることです-これは「入力」ですか?直感的に入力のように見えるようにコードを設定し、プログラムの6行目の数値Nに関して大きなO実行時間を確実に求めることができますが、そのようなデフォルト以外の選択を使用する場合入力として、あなたは本当にそれについて明示する必要があります。

ただし、コマンドラインや関数への入力など、入力をより一般的なものにすると、出力はまったくなく、関数はO(1)になります。 20年かかりますが、big-Oは定数倍まで変化しないため、O(1) = O(20年)です。

同様の質問-のランタイムは何ですか:

void sortArrayOfSizeTenMillion(int[] array)

それが言っていることを実行し、入力が有効であり、アルゴリズムがクイックソートまたはバブルソートまたは妥当なものを利用すると仮定すると、それはO(1)です。

10
djechlin

この「アルゴリズム」は、O(1)または一定時間として正しく記述されます。このプログラムへの入力がないと主張されているため、ビッグオーに関して分析するNはありません。入力がないことに同意しません。これを実行可能ファイルにコンパイルして起動すると、ユーザーは任意の長さの入力を指定できます。その入力長はNです。

プログラムは入力を無視します(長さは問いません)。そのため、所要時間(または実行されるマシン命令の数)は、入力の長さに関係なく同じです(固定環境=開始時間+ハードウェアの場合)。したがって、O(1 )。

8
waldol1

私が驚いたことの1つはまだ言及されていません:big-O表記は上限です!

誰もが気づいた問題は、アルゴリズムへの入力を記述するNがないため、big-O分析を行うことは何もないということです。ただし、これは、int nを受け入れ、「Hello World」n回を印刷するなど、いくつかの基本的なトリックで簡単に軽減できます。それはその苦情を回避し、そのDateTime怪物がどのように機能するかという本当の質問に戻ります。

Whileループが終了するという実際の保証はありません。 some timeにある必要があると思いますが、DateTime.nowsystem date and timeを返すと考えてください。実際には、これが単調に増加しているという保証はありません。誰かが猿に自動フィッティングシューズとホバーボードを与えるまで、システムの日付と時刻を2015年10月21日12:00:00 UTCに絶えず変更する病理学的に訓練された猿がいる可能性があります。このループは実際には無限の時間実行できます!

Big-O表記の数学的定義を実際に掘り下げると、それらは上限になります。それらは、どんなにありそうもない場合でも、最悪のシナリオを示しています。ここでの最悪のケース*のシナリオは無限ランタイムであるため、このアルゴリズムの実行時の複雑さを記述するためのビッグO表記はありません。それは存在しません。/0は存在しません。

*編集:KTとの議論から、big-O表記でモデリングしているシナリオが最悪のケースであると仮定することは必ずしも有効ではありません。ほとんどの場合、どのケースを使用しているかを特定できない場合、最悪のケースを調査することを意図しています。ただし、最適なランタイムでbig-O複雑度分析を実行できます。

6
Cort Ammon

複雑さは、時間/空間の観点から計算「馬力」を測定するために使用されます。 Big O表記は、どの問題が「計算可能」または「計算不可」であるかを比較し、どのソリューション(アルゴリズム)が他より優れているかを比較するために使用されます。そのため、任意のアルゴリズムを2つのカテゴリに分類できます。多項式時間で解決できるものとできないものです。

Erathosteneのふるいのような問題はO(n ^ exp)であるため、nの値が小さい場合に解決できます。それらは計算可能であり、多項式時間(NP)ではなく、したがって、与えられた数が素数であるかどうかを尋ねられたとき、答えの大きさに依存しますそのような数。さらに、複雑さはハードウェアに依存しないため、高速なコンピューターを使用しても何も変わりません。

Hello Worldはアルゴリズムではないため、その複雑さを判断しようとするのは無意味です。単純なアルゴリズムは次のようなものです。乱数を指定して、偶数か奇数かを判断します。さて、与えられた数が500桁であることは重要ですか?いいえ。最後の桁が偶数か奇数かを確認するだけです。より複雑なアルゴリズムは、特定の数値が3で均等に分割されるかどうかを判断することです。一部の数値は計算が「簡単」ですが、他の数値は「困難」です。 1桁の数字と500桁の数字。

より複雑なケースは、テキストをデコードすることです。解読キーを持っている人にメッセージを伝えていることを知っている、明らかなランダムなシンボルの配列があります。送信者が左のキーを使用し、Hello WorldがGwkki Qieksを読んだとしましょう。 「大ハンマー、脳なし」ソリューションは、これらの文字のすべての組み合わせを生成します:AaaaからZzzzまで。次に、単語辞書を検索して、どの単語が有効かを特定し、同じ位置。この変換関数は、Big Oが測定するものです!

5
Turing

あなたはNを定義しないと正しく指摘されていますが、最も合理的な解釈では答えはありません。 Nが印刷する文字列の長さであり、「hello、world!」は単なる例です。これは「hello, world!、”の場合、アルゴリズムはO(N)になります。印刷に30年、40年または50年かかる出力文字列があり、一定の時間だけを追加しているためです。それ。 O(kN + c)∈O(N).

補遺:

驚いたことに、誰かがこれに異議を唱えています。大きなOと大きなΘの定義を思い出してください。一定時間待機するアルゴリズムがあるとしますcそして、長さNのメッセージを線形時間で出力します。 (これは元のコードサンプルを一般化したものです。)印刷を開始するまで20年待ち、1兆文字を印刷するのにさらに20年かかると任意に言いましょう。たとえば、c = 20およびk =10¹²としますが、正の実数であれば十分です。つまり、1文字あたりd = c/k(この場合は2×10⁻¹¹)年の割合なので、実行時間は- fN)は漸近的にdN + c年です。 N> kdN = c/kN> c。したがって、dN <dN + c = fN)< 2 dNすべてのN> k、およびfN =)∈Θ(N)。 Q.E.D。

4
Davislor

コードが従来のアルゴリズムのようにlookしないので、人々は捨てられていると思います。以下は、より適切な形式のコードの翻訳ですが、OPの質問の精神に忠実です。

void TrolloWorld(long currentUnixTime, long loopsPerMs){
    long laterUnixTime = 2051222400000;  //unix time of 01/01/2035, 00:00:00
    long numLoops = (laterUnixTime-currentUnixTime)*loopsPerMs;

    for (long i=0; i<numLoops; i++){
        print ("It's still not time to print the hello …");
    }
    print("Hello, World!");
}

入力は明示的ですが、コードが開始された時間とコードを実行するハードウェアの速度によって暗黙的に与えられる前です。コードは決定論的であり、特定の入力に対して明確に定義された出力を備えています。

提供できる入力に課せられる制限のため、実行される操作の数には上限があるため、このアルゴリズムは実際にはO(1)です。

4
Nathan FD

ほとんどの人は、2つの非常に重要なことを見逃しているようです。

  1. プログラムdoesには入力があります。システム時間と比較されるハードコードされた日付/時刻です。入力はアルゴリズムを実行している人の制御下にあり、システム時間はそうではありません。このプログラムを実行している人が制御できるのは、比較にハードコーディングされた日付/時刻だけです。

  2. プログラムは、入力に基づいて変化しますが、入力のサイズセットには依存しません。これは、big-O表記法が関係するものです。

したがって、これは不定であり、このプログラムの最適な「big-O」表記は、おそらくO(null)、またはおそらくO(NaN)です。

4
Theo Brinkman

この時点で、はい

このアルゴリズムには、暗黙的な入力、つまりプログラムが開始される時間があります。実行時間は線形に変化します1 いつ開始されるかによります。 2035年以降は、whileループが直ちに終了し、一定の操作の後にプログラムが終了します2。したがって、ランタイムはO(max(2035 - start year, 1))と言うことができます3。ただし、開始年には最小値があるため、アルゴリズムの実行に20年以上かかることはありません(つまり、一定の値)。

DateTime TwentyYearsLater = DateTime.Now + new TimeSpan(365*20,0,0,0);を定義することにより、意図に沿ってアルゴリズムをさらに作成できます4

1 これは、時間単位あたりの操作の最大数があるため、操作の数として測定される実行時間のより技術的な意味を保持します。
2 DateTime.Nowのフェッチが一定の操作であると仮定すると、これは合理的です。
3 これはstart yearに関して減少する関数であるため、ここではやや大きなO表記を乱用していますが、years prior to 2035で表現することで簡単に修正できます。
4 その場合、アルゴリズムは開始時間の暗黙的な入力に依存しなくなりますが、それは重要ではありません。

2
Nathan FD

これはO(n)であると主張します。 http://www.cforcoding.com/2009/07/plain-english-explanation-of-big-o.html を参照として使用します。

Big Oとは何ですか?

Big O表記は、キーファクターが無限に向かう傾向がある場合に、キーファクターに対する成長率を減らすことにより、アルゴリズムの相対的な複雑さを表現しようとします。

そして

私が考えることができるBig-Oの最良の例は、算術を行うことです。学校で学んだ基本的な算術演算は次のとおりです。

添加;減算;乗算;および部門。これらはそれぞれ、操作または問題です。これらを解決する方法は、アルゴリズムと呼ばれます。

あなたの例では、

n = 20(単位年)の入力が与えられた場合。

アルゴリズムは数学関数f()です。ここで、f()は、 'debug'文字列を挟んでn年間待機します。スケールファクターは1です。f()は、このスケールファクターを変更することにより、減少/増加できます。

この場合、出力も20です(入力を変更すると出力が線形に変更されます)。

基本的に機能は

f(n) = n*1 = n
    if  n = 20, then 
f(20) = 20 
1
Angel Koh