私が行ったすべてのインタビューで、big-O表記法を含む複雑さの数学的分析についてクイズを受けました。
Big-O分析は、業界の開発にどの程度関連していますか?どのくらいの頻度で実際にそれを使用しますか?また、問題に対して研ぎ澄まされた考え方を持つためにどれほど必要ですか?
私の質問は、このテストは業界の発展にどの程度関連があるのでしょうか。
スケーラブルなアルゴリズム、アプリケーション、システムを設計するには、計算の複雑さの理論(Big O表記など)をしっかりと理解することが不可欠です。スケーラビリティは業界のコンピューティングに非常に関連しているため、ビッグO表記も重要です。
どのくらいの頻度でそれを使用しますか、そして問題に対して研ぎ澄まされた考え方を持つためにどれほど必要ですか?
「実際に使用する」という意味に依存します。一方で、私は自分が書いたソフトウェアの計算の複雑さを正式に証明することはありません。一方、ほとんどの場合、スケーラビリティが潜在的に懸念されるアプリケーションを扱う必要があり、設計の決定には、(たとえば)複雑さの特性に基づく適切なコレクションタイプの選択が含まれます。
(スケーラブルなシステムを一貫して実装できるかどうかはわかりませんなし複雑さの理論をしっかりと理解しています。そうではないと思いがちです。)
これは、スケーラビリティを示しているためです。
O(n ^ 2)のプロセスは、O(n log n)のプロセスよりもスケーリングが低くなりますが、O(n ^ 3)またはO(n!)のプロセスよりも優れています。
違いがわからない場合、いつ適用されるかは、機能の適切な実装を選択したり、テストパフォーマンスを本番パフォーマンスに外挿したりするのにはあまり適していません。
編集: http://www.codinghorror.com/blog/2007/09/everything-is-fast-for-small-n.html の48nとn ^ 3の比較==(ターンはプログラミング真珠からです)
それはあなたが何をしているかに依存します。
Web開発者(私など)にとって、これは通常非常に重要です。 Webアプリをスケーリングしたい。アプリにO(n ^ 2)でスケーリングするボトルネックがあり、サーバーが1000人の同時ユーザーを処理できるため、これで問題ないと思われる場合は、気にする必要はないようです。重要なのは、2倍の数(これは一晩だけ発生する可能性が高い)を処理するには、4倍の計算能力が必要になるということです。ハードウェアはユーザーとサーバーの比率が一定であり、安価であるため、理想的にはWebアプリをO(n)でスケーリングする必要があります。
一般に、1万個のオブジェクトがあるアプリでは、大きなOが来てあなたを食べます。あなたはピークに対して非常に脆弱です。たとえば、私は現在、データのロードを処理するアプリである3Dゲームに取り組んでいます。レンダリングとは別に、衝突チェック、ナビゲーションなどがあります。明らかな方法で進むだけでは余裕がありません。あなたは効率的なアルゴリズムを必要とし、多くのキャッシュを必要とするので、効率の悪いものは償却します。等々。
もちろん、インターフェイスデザイナでGUIを1つにまとめてモバイルアプリを作成するようなものであれば、それをいくつかのWebサービスに接続すれば、複雑さの問題は発生しません。呼び出すWebサービスがすでに処理しているためです。
私は実際に仕事の生活の中でルールを正式に適用したことはありません。
ただし、その概念に精通し、アルゴリズムを設計するたびに直感的に適用する必要があります。
ルールは:
特定のタスクについて、正式に計算する必要があるか、それを直感的に評価するか、または完全にスキップできるかを判断できるように、O表記について十分に理解している必要があります。他の多くの基本的な数学の概念と同じように。
さて、多分少しの物語はそれがなぜDEFINITELY IS必要であるかをあなたに啓発します:
私が取り組んでいるプロジェクトでは、あらゆる種類のドキュメント(ラベル、ピッキングリストなど)を印刷するプログラムがありました。このプログラムは2つの部分で構成され、1つはデータベースから必要なすべてのデータを読み取り、それを.iniスタイルファイル、およびそれらのファイルを読み取り、テンプレートに入力する別の部分。これは、ラベルと少数のフィールド(数フィールドのみ)に対しては適切に機能しましたが、約20ページの「大きな」リストを印刷する必要があったときに、ほぼ10分間実行されました。これらのiniファイルにアクセスするとO(n²)アクセス時間が発生するため、nは印刷するフィールドの数です。
このプログラムの最初のプログラマーがO表記法を理解していたら、彼らはそのようにしたことはなかっただろう。その愚かさをハッシュテーブルで置き換えると、すごく速くなった。
Big-Oのパフォーマンスは重要ですが、大部分は内部化されています。
ソートと検索のBig-Oパフォーマンスは重要ではありません。これは、一般にシステム提供のものを使用し、それらは可能な限り優れているためです(一般的に有用である必要がある場合)。さまざまな事柄に対してより効率的なデータ構造がありますが、それらは通常、一般原則に基づいて選択できます(通常、現代の言語に組み込まれています)。スケーリングする、またはしないアルゴリズムの感覚があります。
その結果、正式な問題が実際に生じることはほとんどありませんが、実際は同じ原則に基づいて構築されています。
私見多くのコンピューターサイエンスプログラムでは、多くの学生が雑草の中をさまよっています。これらのプログラムは、計算の科学が何であるかについての全体像を完全に伝えることは決してありません。学生たちは業界に参入し、実際の世界とどのように関連しているかについてほとんど洞察することなく、学んだ概念の適用方法に取り組んでいます。
計算科学の核心は、計算を推論する能力だと思います。そして、これを行うためのさまざまな方法と手法を学び、それらを抽象化された問題に適用します。これは、多くの現実世界の問題で見られる典型的なプリミティブです。トリックは、これらのプロトタイプのプリミティブを現実の世界で見つけ、次に正確さ、複雑さ、時間などの事柄について推論することです。パーツの動作に関する洞察により、全体の動作に関する洞察が頻繁に得られます。また、同じ一般的な方法とテクニックを全体に適用することもできますが、より小さく、抽象化され、明確に定義されたパーツに提供されるのと同じ厳密さではありません。しかし、結局のところ、計算の科学は、さまざまな条件下での計算の実際の洞察とともに、計算の調整方法について合理的な決定を行う能力をあなたに与えます。
自己紹介!:
私や他の多くの人がこの質問を定期的に自問しています。
私たちがこれを尋ねる本当の理由は、怠惰になったためだと思います。
この知識は決して古くなったり、古くなったりすることはありません。日常的に直接適用することはできませんが、無意識のうちに使用し、設計上の決定にプラスの影響を与えます。ある日、あなたや他の人のコーディングの時間と日を節約できます。
より多くの問題がサードパーティのライブラリとツールによってカプセル化され、より多くの開発者が利用できるようになると、この知識を知って自分を他の人と区別し、新しい問題を解決する必要があります。
あんまり。基本的に私がこれについて考えるのは、データベースにアクセスするときだけです。私は通常、コードを見て「n + 1クエリを実行しているので、1または2だけに変更する必要があります」と言います。
すべてのデータがデータベースから読み取られてユーザーに表示されるため、線形データとO(n ^ 2)アルゴリズムの違いがかなりわかる程度まで、処理しているデータの量を最小限に抑えるようにしています無視できる。
問題がある場合は、後でプロファイリングして修正します。
あなたが置いた3つの質問と私は、短い形式の答えがこれまでに与えられたより長い議論を助けることができると思います。
このテストは業界の開発にどの程度関連していますか?
業界によって異なります。
コードスピードやコードスペースが問題となるところはどこでも、関係する業界に完全に関連しています。多くの場合、ルーチンにかかる時間、またはルーチンに必要なメモリ(オンライン/オフライン)の量を知る必要があります。
どのくらいの頻度で使用していますか?
業界によって異なります。
パフォーマンスとスケーリングが目前のジョブにほとんど関係がない場合、まれに、深刻なパフォーマンス不足が発生した場合のみです。頻繁に使用される重要なシステムのエンジニアであれば、おそらく毎日です。
問題に対して研ぎ澄まされた考え方を持つことはどの程度必要ですか?
完全に必要です。
あなたはそれを毎日、または悲惨な状況でのみ使用する必要があるかもしれません。しかし、時にはそれが必要になります。望ましくは、窒息システムを必死にプロファイリングするよりも、問題が到着する前の設計中に。
それは非常に頻繁です。私たちは一般的に証明何かが特定のビッグOを持っていることを証明しませんが、アイデアを内部化し、ビッグOの保証を覚えています特定のデータ構造とアルゴリズムのために、特定の用途のために最速のものを選びます。 Javaコレクションライブラリ、またはC++ STLなど)のすべてのオプションが満載のライブラリを用意すると便利です。暗黙的かつ自然にbig-Oを使用します毎日 = _Java.util.HashMap
_(O(1)
lookup)の代わりに_Java.util.TreeMap
_(O(lg n)
lookup)を使用することを選択し、線形検索を実行しないことを選択した場合_Java.util.LinkedList
_(O(n)
lookup)ソートされたアクセスを必要としない何かのために。
誰かが次善の実装を選択し、よりよく知っている誰かがやって来て、彼らのコードを見るとき、それらを修正することはボキャブラリーの一部です。この方法ではなく、英語を使用してピザを注文するのと同じくらい自然かつ自動的に。
はい
正式な分析を行う必要はないかもしれませんが、少なくともアルゴリズムの複雑さの順序、およびその周りの2つのアルゴリズムを比較する方法を直感的に理解することは、重要な作業を行い、それをうまく理解させたい場合に重要です。
開発の初期段階では問題ないように思えた2つの異なるシステムで作業しましたが、誰かがO(n ^ 2)アルゴリズムを使用したため、ハードウェアを本番環境のテストで苦労させました。どちらの場合も、修正はO(n)アルゴリズムへのささいな変更でした。
消費用のAPIを開発している場所でおそらく使用されます。 C++ STLは、アルゴリズムに複雑さの制限が課されている数少ないAPIの1つです。しかし、日常のプログラマー/シニアプログラマー/デザイナー/アーキテクトにとって、それは彼らの心をあまり交差させません。
アイデアを伝えること以外はそれほど重要ではないので、パフォーマンスが重要なフィールド(レイトレーシング、画像とメッシュの処理、パーティクルシステム、物理エンジンなど)で作業し、独自のアルゴリズムやデータ構造を数多く考案する必要がありました。研究開発で働くとき。これらの領域では、多くの場合、非常に効率的なデータ構造とアルゴリズムのほんの一握りでまったく新しい最先端の製品を生み出すことができますが、昨日のアルゴリズムは既存の製品を時代遅れにするので、常により効率的に物事を行うことの追求があります。ただし、注意点として、私が考案したアルゴリズムに関する論文を公開したことはありません。それらはすべて独自のものでした。もしそうなら、証明を定式化するために数学者の助けが必要でしょう。
しかし、私の意見では、アルゴリズムのスケーリングが実際に不十分でない限り、反復ごとの計算作業量は、アルゴリズムのスケーラビリティよりも多くの場合より直接的な関心事です。誰かがレイトレーシングのための最先端の手法を思いついた場合、合理的なスケーラビリティがこの競争力のある革新的なシナリオですでに提供されているため、アルゴリズムの複雑さよりも、データの表現方法やデータへのアクセス方法などの計算手法に興味があります。スケーリングしないアルゴリズムを考え出すことはできません。
もちろん、2次の複雑さを線形計算と比較する場合、それは大きな違いです。しかし、私の分野のほとんどの人は、叙事詩の入力に2次複雑度アルゴリズムを適用することを避けるのに十分な能力があります。したがって、スケーラビリティはしばしば深く暗示され、より有意義で興味深い質問は次のようになります「GPGPUを使用しましたか?SIMD?並列で実行しますか?データをどのように表現しましたか?キャッシュに適するように再編成しましたか?アクセスパターン?どれだけのメモリが必要ですか?このケースを確実に処理できますか?特定の処理を延期するか、それをすべて一度に実行しますか? "
前者がより最適なパターンでメモリにアクセスする場合、または、たとえばマルチスレッディングやSIMDに適している場合、線形演算アルゴリズムでも線形時間アルゴリズムよりも優れたパフォーマンスを発揮できます。これらの理由により、線形アルゴリズムでさえ対数アルゴリズムより優れている場合があり、当然、線形時間アルゴリズムは10進数の入力で対数アルゴリズムよりも優れています。
したがって、私にとってより重要なのは、データ表現(メモリレイアウト、ホット/コールドフィールド分割によるアクセスパターンなど)、マルチスレッディング、SIMD、そしてときどきGPGPUなど、「マイクロ最適化」と呼ばれる人もいます。誰もがすでに新しい論文が常に公開されており、すべてに適切な最先端のアルゴリズムを使用するのに十分な能力がある分野では、アルゴリズムウィザードを打ち負かす競争力のあるエッジは、アルゴリズムの複雑さの改善から直接的ではありません。計算効率。
私の分野は優秀な数学者に支配されていますが、彼らがしていることの計算コストや、コードを高速化するための多くの低レベルのトリックを知っている人は必ずしもそうではありません。私のエッジは、私がはるかに洗練されていないにも関わらず、より高速でよりタイトなアルゴリズムとデータ構造を考案する上で、通常は私のエッジです。私はハードウェアの好みに合わせて、ビットとバイトに向かって取り組んでおり、実際に洗練されたアルゴリズムよりも数回多く作業を繰り返しても、作業の各反復をはるかに安くしています-私の場合の作業は大幅に安価です。私が書いたコードも、ずっと単純になる傾向があります。単純化されたアルゴリズムとデータ構造のマイクロ最適化バージョンを理解および維持するのが難しいと思われる場合は、業界でこれまで見られなかったエキゾチックなメッシュ関連のアルゴリズムとデータ構造のコレクションを理解して維持してみてください。 。
基本的な例として、単純なグリッド構造を思いつきました。これは、衝突検出と冗長ポイントの削除に関して、当社のKDツリーよりも優れたものになりました。私のばかげた粗雑なグリッドはアルゴリズム的にはそれほど洗練されておらず、中央値を見つける彼の斬新な方法でKD-treeを実装した人よりも数学的にもアルゴリズム的にも気難しいですが、グリッドのメモリ使用量とアクセスパターンを調整しただけで、これは、はるかに洗練されたものを凌ぐのに十分でした。
同じ方法で開発したソフトウェアを使用しているので、私よりもはるかに賢い人々が支配する分野で生き残るためのもう1つのエッジは、ユーザーの作業方法を本当に理解していることです。これにより、ユーザーの興味にすぐに一致するアルゴリズムのアイデアが得られます。そこでの基本的な例として、ほとんどの人は空間インデックスを使用して衝突検出のようなものを加速しようとします。たとえば、キャラクターが顔に手を置いた場合、空間インデックス構造がノードを分割し、キャラクターがそれから顔から手を離した。代わりに、頂点位置ではなく接続性データに基づいてパーティション分割すると、非常に迅速に更新され、ツリーを分割または再調整する必要がない安定した階層構造になる可能性があります(アニメーションのすべてのフレームのバウンディングボックスを更新するだけで済みます)。 ..このようなもの-基本的な概念を理解していれば、数学的な背景のない子供が思いつくかもしれませんが、数学者がユーザーのやり方にあまり近い方法で考えていなかったために、数学者を無視したアルゴリズムが機能し、ジオメトリのプロパティについて考えすぎ、ジオメトリの一般的な使用方法については考えていませんでした。私は、アルゴリズムウィザードよりも一般的な計算の知識とユーザーエンドの知識に頼ることで、十分にうまくいきます。とにかく、アルゴリズムの複雑さに焦点を当てることがそれほど重要であることに私は本当に気づいていません。
数学の観点からビッグOについて考えたことはありません。求められない限り、ビッグOについて考えたことはありません。私は頭の中にアルゴリズムを見て、それがNごとにメモリを介して複数のループを実行するのでそれが悪いのか、それとも分割統治するのか、そのようなものなのかを見分けることができます。必要に応じて、数秒でそれを大きなO表記に変換できますが、アルゴリズム/コンテナがメモリでどのように機能するかを知ることは、数学的観点について考えるよりも簡単です。
はい、業界では複雑さが重要です。クリティカルパスがN-2乗としてスケーリングするようなものを設計することになった場合(何かの数を2倍にすると、システムは4倍の負荷になります)、Nでスケーリングするものよりもはるかに速くスケーリングのボトルネックに到達します。
ただし、これは通常、何かが特定の複雑さであることの適切で正式な証明として行われないため、操作のパターンがどのような複雑さであるかを直感することから始めるのが適切です。