一定時間での追加とランダム削除を可能にするRandomQueueを作成する必要があります(O(1)))。
配列はインデックスを介して常にアクセスできるため、私の最初の考えは、何らかの種類の配列(私はArrayListを選択しました)でそれをバックアップすることでした。
ただし、ドキュメントを調べたところ、基になる配列の再割り当て(O(n))が必要になる可能性があるため、ArrayListの追加はAmortized Constant Timeと見なされることがわかりました。
償却済みの一定の時間と一定の時間は実質的に同じですか、それとも、追加するたびに完全な再割り当てを必要としない構造を調べる必要がありますか?
配列ベースの構造は別として(私が知る限り常にAmortized Constant Timeの追加があるため)、要件を満たすものは何も考えられないので、これを求めています。
ここに完全な質問があります。私がいくつかの重要な詳細に気を配った場合:
RandomQueueを設計して実装します。これはQueueインターフェースの実装であり、remove()操作は、現在キューにあるすべての要素の中からランダムに一様に選択された要素を削除します。 (RandomQueueは、要素を追加するか、いくつかのランダムな要素を盲目的に削除するためのバッグと考えることができます。)RandomQueueのadd(x)およびremove()操作は、操作ごとに一定の時間で実行する必要があります。
償却済みの一定時間は、ほとんどの場合一定時間と同等と見なすことができます。アプリケーションの詳細とこのキューに対して行う予定の使用法のタイプを知らなければ、ほとんどの場合、カバーされる可能性があります。
配列リストには容量の概念があり、これは基本的に、これまでに必要とされたアイテムの最大サイズ/長さ/アイテムの数と同じです。したがって、何が起こるかというと、配列リストは最初にアイテムを追加し続けると、配列リスト自体を再割り当てして容量を増やしますが、ある時点で、単位時間あたりに追加されたアイテムの平均数は、必然的にアイテムの平均数と一致します単位時間ごとに削除されます(そうしないと、最終的にメモリが不足します)。その時点で、配列はそれ自体の再割り当てを停止し、すべての追加はO(1)の一定の時間で満たされます。
ただし、デフォルトでは、配列リストからのランダムな削除はO(1)ではなく、O(N)であることに注意してください。配列リストは、削除された項目の後のすべての項目を1つ下に移動して、削除された項目の位置を取得するためです。項目。 O(1)を達成するには、デフォルトの動作を上書きして、削除されたアイテムを配列リストの最後のアイテムのコピーで置き換え、最後のアイテムを削除する必要があります。アイテムは移動されませんが、そうすると、キューがなくなります。
質問は、一定の時間を具体的に要求するようであり、 一定の償却時間 ではありません。したがって、引用された質問に関しては、いいえ、それらは事実上同じではありません*。しかし、それらは実際のアプリケーションにありますか?
償却定数の一般的な問題は、累積された借金を時々支払う必要があることです。そのため、挿入は一般的に一定ですが、新しいブロックが割り当てられたときに、すべてを再度挿入するオーバーヘッドが発生することがあります。
一定の時間と償却された一定時間の差がアプリケーションに関連する場合は、この時々起こる非常に遅い速度が許容できるかどうかによって異なります。非常に多数のドメインの場合、これは通常は問題ありません。特にコンテナーに有効な最大サイズ(キャッシュ、一時バッファー、作業コンテナーなど)がある場合、実行中に一度だけコストを支払うことができます。
クリティカルアプリケーションへの対応として、これらの時間は許容できない場合があります。短時間のターンアラウンド保証を満たす必要がある場合は、それを超える場合があるアルゴリズムに依存することはできません。私は以前にそのようなプロジェクトに取り組みましたが、それらは非常にまれです。
また、このコストが実際にどれほど高いかに依存します。ベクトルは、再割り当てコストが比較的低いため、パフォーマンスがよくなる傾向があります。ただし、ハッシュマップに移動すると、再割り当てが大幅に増える可能性があります。繰り返しますが、ほとんどのアプリケーションではおそらく問題ありません。特に、コンテナ内のアイテムに上限がある、より長寿命のサーバーです。
*ただし、ここには少し問題があります。汎用コンテナを一定の時間挿入するためには、次の2つのいずれかを保持する必要があります。
それは、スループットを最適化するか、遅延を最適化するかによって異なります。
1つのシステムに、異なる分類が必要な異なるコンポーネントを含めることができることに注意してください。例えば。最新のテキストプロセッサには、待ち時間に敏感なUIスレッドがありますが、スペルチェックやPDF exportsなどの他のタスク用にスループットが最適化されたスレッドです。
また、アルゴリズムの複雑さは、多くの場合、私たちが考えるほど重要ではありません。問題が特定の数に制限されている場合、実際の測定されたパフォーマンス特性は、「非常に大きいnの動作」よりも重要です。 =」。
「定額償却」アルゴリズムを求められた場合、アルゴリズムがときどき時間がかかることがあります。たとえば、C++でstd :: vectorを使用する場合、そのようなベクターは10個のオブジェクトにスペースを割り当てている可能性があり、11番目のオブジェクトを割り当てると、20個のオブジェクトのスペースが割り当てられ、10個のオブジェクトがコピーされ、11番目が追加されます。かなり時間がかかります。ただし、100万個のオブジェクトを追加すると、999,980の高速操作と20の低速操作があり、平均時間が高速になる場合があります。
「一定時間」アルゴリズムを要求された場合、アルゴリズムはすべての単一の操作でalwaysである必要があります。これは、各単一操作がalways高速であることが保証される必要があるリアルタイムシステムでは重要です。 「一定時間」はほとんどの場合必要ありませんが、それは間違いなくnotは「償却一定時間」と同じです。