クリア関数の時間計算量は std::map ですか?
それが O(1) であると言うのは正しいでしょうか?
4 に答える
標準は[associative.reqmts]/8 表 102で次のように述べています。
a.clear()
<=>a.erase(a.begin(), a.end())
線形a.size()
したがって、実際には O(N) であることが義務付けられています。
EDIT:さまざまなビットをまとめます。
ノードを削除するには、次のmap
2 つの操作を行います。
- アロケータ
destroy
メソッドを呼び出して要素を破棄する - allocator
deallocate
メソッドを呼び出して、ノードが占有しているメモリの割り当てを解除します
前者はコードで省略できます( をチェックしますis_trivially_destructible
)。実際には、一般的vector
に例で行われます。後者は残念ながらよりトリッキーであり、trait が存在しないため、オプティマイザーに依存する必要があります。
destroy
残念ながら、オプティマイザーがインライン化によってノードとノードを完全に削除deallocate
できたとしても、ツリー トラバーサルが役に立たなくなったことに気づき、それを最適化することもできないのではないかと心配しています。したがって、ツリーの Θ(N) トラバーサルになってしまい、各ステップで何も行われません...
cplusplusリファレンスサイトは、各要素のデストラクタを呼び出す必要があるため、コンテナのサイズが直線的に複雑であると主張しています。
これはテンプレートであるため、コンパイル時に型 (例: std::map<int>
) のノーオペレーションで破棄されることがわかっている可能性があるため、メンバーを破棄する必要性は、必要な最悪の場合のパフォーマンスを推測するための適切な根拠にはなりません。それでも、コンパイラはバイナリ ツリーのすべてのノードにアクセスしてヒープ メモリを解放する必要があり、ノードの数は要素の数に直線的に関係します (erase()
消去された要素へのイテレータ/参照/ポインタのみを無効にし、insert()
その他は無効にしません)。 . すべてが 1:1 の関係を証明しています)。
したがって、線形ですが、要素のデストラクタが必要ない場合でもヒープの使用をクリーンアップする必要があるため....
(興味深いことに、これは、すべてのメモリが専用のメモリ プールから割り当てられた場合、自明な no-op デストラクタを持つ要素に対して、 のstd::map<>
ような連想コンテナ、またはおそらくstd::map<>
それ自体が巧妙なカスタム アロケータを使用して O(1) になる可能性があることを意味します。 O(1)で「捨てられた」)
私が知っているように、これらのオブジェクトを 1 つずつ破棄する必要があるため、クリーン操作の複雑さはすべて O(n) です。