「nの値が小さい場合、O(n)はあたかもO(1)であるかのように扱うことができます」


26

私は、nの十分に小さい値に対して、O(n)がO(1)であるかのように考えられたり、扱われたりすることを何度か聞いたことがあります。

そうする動機は、O(1)は常にO(lg n)よりも優れており、常にO(n)よりも優れているという誤った考えに基づいています。操作の漸近的順序は、現実的な条件下で問題のサイズが実際に大きくなる場合にのみ関係します。nが小さいままであれば、すべての問題はO(1)です!

十分に小さいのは何ですか?10?100?1,000?どの時点で「これをもはや無料の操作のように扱うことはできません」と言いますか?経験則はありますか?

これはドメイン固有またはケース固有の可能性があるように見えますが、これについて考える方法に関する一般的な経験則はありますか?


4
経験則は、解決する問題によって異なります。組み込みシステムに高速であるn100?複雑性理論で公開しますか?
ラファエル

3
さらに考えると、パフォーマンス要件はドメインとそのビジネス要件によって決定されるため、1つの経験則を考え出すことは基本的に不可能だと感じています。リソースに制約のない環境では、nは非常に大きくなる可能性があります。厳しい制約のある環境では、かなり小さい場合があります。後知恵で今それは明白なようです。
rianjs 14

12
@rianjsあなたは勘違いしているように見えるO(1)ため無料。最初のいくつかの文章の背後にある理由は、つまりO(1)ある一定の時々めちゃくちゃ遅くなることがあります。入力に関係なく千億年かかる計算はO(1)計算です。
Mooingダック14

1
そもそも漸近性を使用する理由に関する関連質問
ラファエル

3
@rianjs:「5の十分に大きい値に対して、五角形はほぼ円形です」という線に沿ったジョークに注意してください。あなたが尋ねている文は重要ですが、混乱を引き起こしているので、この正確なフレージングの選択がユーモラスな効果のためにどの程度であったかをEric Lippertに尋ねる価値があるかもしれません。「上限がある場合、すべての問題はO 1 )です」と言っても、数学的には正しかったでしょう。「小」は数学の一部ではありません。nO(1
スティーブジェソップ14

回答:


21

すべての桁は定数含み、実際にはそれらのいくつかが含まれます。アイテムの数が十分に大きいため、定数は無関係です。問題は、アイテムの数がその定数を支配できるほど小さいかどうかです。C

これを視覚的に考えてみましょう。

ここに画像の説明を入力してください

すべてに、Y軸上の開始点を決定する開始定数があります。それぞれには、どれだけ速く増加するかを支配する重要な定数もあります。C

  • 以下のためにCは時間を決定します。O(1)C
  • は実際には C × nです。ここで、 Cは角度を決定します。O(n)C×nC
  • は実際にはC × n 2です。ここで、 Cは曲線のシャープネスを決定します。O(n2)(C×n)2C

使用するアルゴリズムを決定するには、ランタイムが交差するスポットを推定する必要があります。たとえば、起動時間が長いまたはCが高いソリューションは、かなり多数のアイテムで起動時間が短く、Cが低いO n ソリューションに失われます。O(1)CO(n)C

これが実世界の例です。あなたは庭を横切ってたくさんのレンガを移動しなければなりません。手でそれらを一度にいくつか動かすか、巨大で遅いバックホウを手に取り、1回の旅行で持ち上げて運転することができます。レンガが3つある場合の答えは何ですか?3000ある場合、あなたの答えは何ですか?

これがCSの例です。常にソートされたリストが必要だとしましょう。順序で自身を保持するツリーを使用できます。または、ソートされていないリストを使用し、O n log nで挿入または削除するたびに再ソートすることもできます。ツリーの操作は複雑(定数が高い)で、ソートは非常に単純(定数が低い)であるため、リストは数百または数千のアイテムに勝つ可能性があります。O(logn)O(nlogn)

この種のことを目で確認できますが、最終的にはベンチマークがそれを行うものです。また、通常持っているアイテムの数を目で確認し、さらに手渡されるリスクを軽減する必要があります。また、「アイテムを超えるとパフォーマンスが急速に低下する」または「Xの最大セットサイズを想定する」などの仮定を文書化することもできます。Xバツ

これらの要件は変更される可能性があるため、これらの種類の決定をインターフェイスの背後に置くことが重要です。上記のツリー/リストの例では、ツリーまたはリストを公開しないでください。そうすれば、仮定が間違っていることが判明した場合、またはより良いアルゴリズムを見つけた場合、考えを変えることができます。アイテムの数が増えると、ハイブリッドを実行してアルゴリズムを動的に切り替えることもできます。


と言うのは無意味です。あなたが本当に平均することである実行している時間がある場合は、T = O 1 (多くの場合)、その後T C。もしT = O N 、次いで多くの場合T C 、N、またはより正式T = C N + O N 。等々。ただし、他の場合、定数Cは次のように変化することに注意してください。O1=OCT=O1TCT=O(n)TCnT=Cn+o(n)C、特定の範囲内。n
ユヴァルフィルマス14

@YuvalFilmusこれが、グラフが好きな理由です。
シュヴェルン14

これが断然最良の答えであり、ポイントは機能がどれだけ速く成長するかです。
リカルド14

1
素敵なグラフですが、軸には「速度」ではなく「時間」というラベルを付けてください。y
イルマリカロネン14

1
あるの行は、実際に放物線がありますか?nが小さい場合は非常に平坦になり、nが大きい場合は非常に急になります。On2nn
デビッドリチャービー14

44

これは、すでに投稿された回答に大きく依存していますが、異なる視点を提供するかもしれません。

質問が「nの十分に小さい値」について議論していることが明らかになっています。Big-Oの全体的なポイントは、処理対象の関数として処理がどのように成長するかを説明することです。処理中のデータが小さいままであれば、Big-Oについて議論することは無関係です。なぜなら、あなたは成長に関心がないからです(それは起こっていない)。

別の言い方をすれば、通りを非常に短い距離で移動している場合、歩いたり、自転車を使ったり、運転したりするのも同じくらい速いかもしれません。車のキーを見つけるのに時間がかかる場合や、車にガソリンが必要な場合などは、歩いたほうが速いかもしれません。

nが小さい場合は、便利なものを使用してください。

クロスカントリー旅行をしている場合は、運転、燃費などを最適化する方法を検討する必要があります。


5
「nが小さい場合は、便利なものを使用してください。」-操作を頻繁に実行する場合は、最速を選択します()。こちらもご覧くださいn
ラファエル

4
素晴らしい比phor!
エヴォラー14

1
純粋に数学的な観点から見ると、漸近的な複雑さはを何も伝えませんn < infinity
ゴードンガスタフソン14

15

引用はかなり曖昧で不正確です。少なくとも3つの関連する解釈方法があります。

その背後にある文字通りの数学的なポイントは、ある程度のサイズまでのサイズのインスタンスにのみ関心がある場合、可能性のあるインスタンスの数は限られているということです。たとえば、最大100個の頂点に有限数のグラフしかありません。インスタンスの数が限られている場合、原則として、可能なすべてのインスタンスに対するすべての回答のルックアップテーブルを作成するだけで問題を解決できます。ここで、最初に入力が大きすぎないことを確認することで答えを見つけることができます(一定の時間がかかります:入力がkより長い場合 k、それは無効です)、テーブルで回答を検索します(一定の時間がかかります:テーブルには一定数のエントリがあります)。ただし、テーブルの実際のサイズはおそらく実行不可能なほど大きいことに注意してください。私は、100の頂点に有限数のグラフしかないと言いました、それは本当です。観測可能な宇宙の原子数よりも有限数が大きいだけです。

より実用的なポイントは、アルゴリズムの実行時間がであると言うとき、それ はある定数Cに対して漸近的にc n 2ステップで  あることを意味するだけです。すなわち、いくつかの定数がありますN 0全てについて、そのようなN N 0、アルゴリズムは、大きく取るC N 2ステップを。しかし、おそらくN 0 = 100 000 000Θ(n2) cn2Cn0nn0cn2n0=100,000,000そして、あなたはそれよりずっと小さいサイズのインスタンスにのみ興味があります。漸近2次境界は、小さなインスタンスにも適用されない場合があります。あなたは幸運かもしれませんし、小さな入力では速くなるかもしれません(あるいは、あなたは不運で遅くなるかもしれません)。たとえば、nが小さい  n 2 < 1000 nであるため、定数が悪い線形アルゴリズムよりも定数が良い2次アルゴリズムを実行した方がよいでしょう。これの実際の例では、漸近的に最も効率的な行列の乗算アルゴリズム(の変種ということである銅細工・ウィノグラード時に実行されている、O nは2.3729がので)あまり、実際に使用されていないストラッセンのOnn2<1000nO(n2.3729) 行列が本当に大きくない限り、アルゴリズムは高速です。O(n2.8074)

3番目のポイントは、  が小さい場合、n 2とさらにn 3  が小さいことです。たとえば、数千のデータ項目を並べ替える必要があり、それらを一度だけ並べ替える必要がある場合、並べ替えアルゴリズムで十分です:n 2nn2n3Θ(n2)アルゴリズムは、データをソートするのにおそらく数千万の命令を必要とするだけです。これは、1秒あたり数十億の命令を実行できるCPUではまったく時間がかかりません。メモリアクセスもありますが、遅いアルゴリズムでも1秒未満で済むため、複雑で高速なアルゴリズムを使用して超高速であることを確認するよりも、単純で低速なアルゴリズムを使用して適切に処理する方がおそらく良いでしょうしかし、バグが多く、実際にデータを適切にソートしません。


4
完全に正しい有効なポイントですが、ポイントを逃したと思います。それらは、を使用したアルゴリズムがO 1 )を使用したアルゴリズムよりも十分に小さいnの場合、パフォーマンスが向上することを意味するようです。これは、たとえば、前者の実行時間が10 n + 50で、後者の実行時間が100000の場合に発生します。次に、nが十分小さい場合、実際にはO n プロトコルを使用する方が高速です。O(n)O(1)n10n+50100000nOn
ランG. 14

@RanG。それは私の2番目のケースに該当しませんか?(I編集はそれがより多くのような何か「良い定数とA線形アルゴリズムが悪い定数の定数/対数アルゴリズムを打つかもしれない」と言っている場合は特に?)
デヴィッド・Richerby

1
nが小さい場合、定数の重要性を明示的に言及しておくとよいでしょう。これは、これまで聞いたことがない人にはおそらく起こらないことです。
ロブ・ワット

9

Big-O表記は、実際には、任意の大きなnの動作についてのみ述べています。たとえば、は、すべてのn > n 0に対してf n < c n 2なるような定数c> 0および整数n 0があることを意味しますfn=On2n0fn<cn2n>n0

多くの場合、定数cを見つけて、「n> 0ごとに、f(n)は約」と言うことができます。役に立つ情報です。しかし、場合によっては、これは正しくありません。f(n)= n 2 + 10 18の場合、これはまったく誤解を招きます。したがって、何かがO(n ^ 2)であるからといって、脳のスイッチを切って実際の機能を無視できるわけではありません。cn2n2+1018

一方、値n = 1、2、および3にしか遭遇しない場合、実際にはn≥4の場合にf(n)が何をするかに違いはないので、f( n)= O(1)、c = max(f(1)、f(2)、f(3))そして、それは十分に小さいことを意味します:遭遇するf(n)の値が「十分に小さい」場合、f(n)= O(1)であるという主張が誤解しない場合。


5

大きくならない場合は、O(1)です

著者の声明は少し公理的です。

成長の順序は、N増加するにつれて行う必要がある作業量に何が起こるかを示します。N増加しないことがわかっている場合、問題は事実上O(1)です。

それO(1)は「速い」という意味ではないことを忘れないでください。常に1兆ステップを完了する必要があるアルゴリズムはO(1)です。1〜200ステップの範囲で、それ以上のアルゴリズムはありませんO(1)。[1]

アルゴリズムが正確にN ^ 3ステップを実行し、5を超えることはできないことがわかっているN場合、125を超えるステップを実行することはできないため、効果的O(1)です。

しかし、繰り返しますが、O(1)必ずしも「十分に速い」という意味ではありません。それはあなたのコンテキストに依存する別の質問です。何かを完了するのに1週間かかる場合、おそらく技術的には気にしませんO(1)


[1]たとえば、ハッシュ内のO(1)アイテムの数に厳しい制限がある限り、ハッシュの衝突により1つのバケット内の複数のアイテムを調べる必要がある場合でも、ハッシュ内のルックアップはです。


1
これを除き、すべてが有効に聞こえます:「アルゴリズムが正確にN ^ 3ステップかかる場合、Nが5を超えることはできないことがわかっている場合、125ステップを超えることはできないため、O(1)です。」 。繰り返しますが、アルゴリズムが整数を取り、最大整数サポートが32767の場合、それはO(1)ですか?明らかにそうではありません。Big-Oは、パラメーターの制限に基づいて変更されません。n = 2はn = 1の2倍の時間がかかるため、0 <n <3であることを知っていてもO(n)です。
JSobell 14

3
@JSobellしかし、それはO(1)です。f(n)のnを制限する制限がある場合、それは無限に成長できないことを意味します。nが2 ^ 15に制限されている場合、実際の素晴らしいn ^ 2関数はg(n) = min(f(2^15), f(n))-O(1)にあります。それは実際には定数は非常に重要であり、明らかにnは漸近解析が有用であるほど十分に大きくなる可能性があることを意味します。
VOO

2
@JSobellこれは、コンピューターが技術的に無限の記憶領域を持つことができないことを考えると、コンピューターが本当に「チューリング完了」であるかどうかの質問に似ています。技術的に、数学的に、コンピューターは「真の」チューリングマシンではありません。実際には、「無限のテープ」というものはありませんが、ハードドライブは十分に近づいています。
カイルストランド14

数年前に、n ^ 5のマトリックス操作を含む金融リスクシステムを作成したため、リソースが問題になる前にn = 20の実用的な制限がありました。
JSobell 14

申し訳ありませんが、Enterキーを押します。私は数年前にn ^ 5の行列操作を伴う金融リスクシステムを書いたので、リソースが問題になる前にn = 20の実用的な制限がありました。この欠陥ロジックによると、作成された関数は20の境界があるためO(1)です。クライアントが「うーん、おそらく制限として40に移動する必要があります...」 )それで問題ありません」...これが、入力の境界が無意味な理由です。この関数はO(1)ではなくO(n ^ 5)であり、これはBig-Oが境界に依存しない理由の実用的な例です。
JSobell 14

2

これで、ハッシュテーブルを使用して、O(1)ルックアップを行うことができます(ハッシュテーブルの特定の実装は別として)が、たとえばリストがあれば、O(n)ルックアップができます。この公理を考えると、コレクションが十分に小さければ、これら2つは同じです。しかし、ある時点で彼らは分岐します...その点は何ですか?

実際には、改善されたルックアップから得られる利点よりも、ハッシュテーブルの構築にかかる点が多くなります。これは、ルックアップを行う頻度と他のことを行う頻度に基づいて大きく異なります。O(1)対O(10)は一度やれば大した問題ではありません。1秒間に数千回実行すると、それでも問題になります(ただし、少なくとも直線的に増加する速度で問題になります)。


確認したい場合は、いくつかの実験を行って、どのデータ構造がパラメーターに適しているかを確認してください。
ユヴァルフィルマス14

本当に確認したい場合は、@ Telastyn Yuval Filmusが正しいです。私はジムという名前を知っています。彼のパラメーターは大丈夫です。しかし、彼はユヴァルのようなアドバイスを聞いていませんでした。確実かつ安全にするために、あなたは本当にYuvalに耳を傾けるべきです。
情報14

2

引用は真実ですが(あいまいですが)危険もあります。Imoでは、アプリケーションのあらゆる段階で複雑さを調べる必要があります。

言うのはとても簡単です。ちょっとしたリストしかありません。アイテムAがリストに含まれているかどうかを確認したい場合は、リストを走査してアイテムを比較する簡単なループを作成します。

次に、buddyprogrammerはリストを使用する必要があり、関数を確認します。リストに重複を追加したくないので、リストに追加されたすべての項目に関数を使用します。

(注意してください、それはまだ小さなリストのシナリオです。)

3年後、私はやって来て、私のボスは大売り出しをしました。私たちのソフトウェアは、大手の全国的な小売業者によって使用される予定です。小さなお店だけにサービスを提供する前。そして今、私のボスは私に宣誓し、叫びます。なぜ今では常に「うまく機能している」ソフトウェアが非常に遅いのか。

結局、そのリストはクライアントのリストであり、私たちの顧客はたぶん100人のクライアントしかいなかったので、誰も気づきませんでした。リストにデータを入力する操作は基本的にO(1)操作でした。これは、1ミリ秒もかからなかったためです。まあ、それに追加される10.000クライアントがあるときはそれほどではありません。

そして、当初の悪いO(1)の決定から数年後、同社は大企業をほとんど失いました。すべては、数年前に1つの小さな設計/仮定エラーのために発生しました。


しかし、それはまた、多くの現実世界のシステムの重要な特徴を示しています。学部生として学ぶ「アルゴリズム」は、実際に「アルゴリズム」が作成される部分です。これは通常、示唆されています。たとえば、ほとんどの人は、パーティションが十分に小さくなったときにクイックソートが挿入ソートにフォールバックするように書かれていることと、バイナリ検索が線形サーチにフォールバックするように書かれていることを知っています。しかし、マージソートがバイナリ検索の恩恵を受けることを理解している人は多くありません。
仮名14

1

そうする動機は、O(1)が常にO(lg n)よりも優れており、常にO(n)よりも優れているという誤った考えに基づいています。操作の漸近的順序は、現実的な条件下で問題のサイズが実際に大きくなる場合にのみ関係します。

これらの時間に2つのアルゴリズムがある場合:

  • log(n)+10000
  • n + 1

そして、それらが交差する点がいくつかあります。それnより小さい場合、「線形」アルゴリズムはより高速であり、nそれより大きい場合、「対数」アルゴリズムはより高速です。多くの人々は、対数アルゴリズムがより高速であると仮定する間違いを犯しますが、小さいn場合はそうではありません。

nが小さいままであれば、すべての問題はO(1)です!

ここでの意味は、制限されている場合、すべての問題はO(1)であると推測しますn。たとえば、整数をソートする場合、クイックソートを使用することを選択できます。 O(n*log(n))明らかに。しかし、2^64=1.8446744e+19整数を超えることはできないと判断した場合、n*log(n)<= 1.8446744e+19*log(1.8446744e+19)<=であることがわかり1.1805916e+21ます。したがって、アルゴリズムは常に1.1805916e+21「単位時間」よりも短くなります。それは一定時間であるため、アルゴリズムは常にその一定時間で実行できると言えます-> O(1)。(これらの時間の単位がナノ秒であっても、それは合計で37411年を超えることに注意してください)。しかし、まだO(1)


0

これらの答えの多くには基本的な概念が欠けていると思います。O(1):O(n)はf(1):f(n)と同じではありません。ここで、fは同じ関数です。Oは単一の関数を表さないためです。Schwernのすてきなグラフでさえ、すべての線に同じY軸があるため、有効ではありません。すべてが同じ軸を使用するには、ラインはfn1、fn2およびfn3である必要があります。各ラインは、他のラインとパフォーマンスを直接比較できる関数でした。

私は、nの十分に小さい値に対して、O(n)がO(1)

さて、n = 1の場合、それらはまったく同じですか?いいえ。可変回数の反復を許可する関数は、反復しないものとは何の共通点もありません。big-O表記は気にしません。

Big-O表記は、反復プロセスがあるときに何が起こるか、および「n」が増加するにつれてパフォーマンス(時間またはリソース)がどのように低下​​するかを表すためにあります。

実際の質問に答えるために...私はその主張をする人はBig-O表記法を正しく理解していないと言うでしょう。なぜならそれは非論理的な比較だからです。

同様の質問があります:文字列をループして、一般に私の文字列が10文字未満になることを知っている場合、それはO(1)と同等であると言えますか? 「O(n)」と言ったでしょうか?

いいえ、10文字の文字列は1文字の文字列の10倍の時間がかかりますが、1000文字の文字列よりも100倍少ないからです!O(n)です。


O1f最大{f0f10}。それは定数ですO1
デビッドリチャービー14

はい、これはBig-O表記が一般的に誤解されている例です。あなたの議論によると、nの最大値が1,000,000であることがわかっている場合、私の関数はO(1)です。実際、私の関数はせいぜいO(1)とせいぜいO(n)です。この表記法は、具体的な実装ではなく、アルゴリズムの複雑さを記述するために使用され、常に最も高価なものを使用してシナリオを記述しますが、最良ではありません。実際、あなたの議論では、n <2を許可するすべての関数はO(1)です!:)
JSobell 14

いいえ。Big-O表記は、関数の成長率を表すために使用されます。これらの関数は、何でも測定するために使用できます。そして、私は最も確かになかったではない可能にする「すべての機能を主張しますn<2 [それが意味するものは何でも] O1」私は実際に、そのプロパティを持つすべての関数が fnf10 すべてのために nO1、そうです。
デビッドリチャービー14

申し訳ありませんが、nの上限を知ると関数O(1)になると言うなら、表記法はnの値に直接関係していると言っていますが、そうではありません。あなたが言及する他のすべては正しいですが、nが境界を持っているのでO(1)だと示唆するのは正しくありません。実際には、あなたが説明するものが観察できる場所がありますが、ここでは、機能的なコーディングではなく、Big-O表記を検討しています。繰り返しになりますが、なぜnの最大値が10になるとO(1)になると示唆しますか?なぜ10ですか?なぜ65535、または2 ^ 64ではありませんか?
JSobell 14

そうは言っても、文字列を10文字にパディングする関数を作成し、常に文字列をループする場合、nは常に10であるため、O(1)です:)
JSobell 14

0

引用したテキストは非常に不正確であると思います(コンテキストを提供しない限り、通常、「より良い」という言葉を使用しても意味がありません。時間、スペースなどの点で)。

入力のサイズに応じて実行時間が長くなる場合、間違いなくそうではありません O1 そしてそれは明確でなければなりません。 O1速いという意味ではありません。(時間の複雑さの観点から)実行時間が一定の上限を持っていることを意味します。

次に、10個の要素の比較的小さなセットを使用し、それをソートするためのいくつかのアルゴリズムを使用します(ほんの一例)。一定の時間で要素をソートできるアルゴリズムも提供する構造に要素を保持すると仮定しましょう。ソートアルゴリズムが次の複雑さを持つ可能性があるとしましょう(big-O表記):

  1. O1
  2. On
  3. Onlogn
  4. On2

どのアルゴリズムを選択しますか?頭に浮かぶ最初の答えは、「もちろん、私はO11!」が、これは必ずしも正しくない。そのような考え方があることであるとき、あなたは忘れてどのような一定の係数ビッグO記法の皮あなたのセットはかなり小さいと知っていれば。そして、この一定の係数がかもしれずっとよりも重要漸近的な複雑さ。

次に、上記のソートアルゴリズムの真の複雑さを「明らかに」しましょう(「true」は定数を非表示にしないことを意味します)。これは、終了に必要なステップ数で表されます(すべてのステップに同じ時間がかかると仮定します)。

  1. 200 歩数
  2. 11n 歩数
  3. 4nlogn 手順(基数2のログ)
  4. 1n2 歩数

入力のサイズが10の場合、これらは上記のすべてのアルゴリズムの正確なステップ数です。

  1. 200 歩数
  2. 11×10=110 歩数
  3. 4×10×3.32134 歩数
  4. 1×100=100 歩数

ご覧のとおり、この場合、漸近的な複雑さを持つ明らかに最悪のアルゴリズム On2 最速のアルゴリズムで、アルゴリズムを破ります O1On そして Onlogn漸近的複雑さ。ここでは、big-O表記に隠されている一定の要因が重要です。私の意見で治療できるという意味はありませんOn2 より良い O1 (とにかくどういう意味でしょうか?)これは、十分に小さな入力(例で見たような)に対して On2 それでもより速いかもしれません O1隠された定数のため。また、定数が入力のサイズと比較して比較的大きい場合、漸近的な複雑さよりも重要な場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.