web-dev-qa-db-ja.com

ベクトルとデックの項目を削除する時間の複雑さ

_std::vector_の末尾に項目を追加する時間の複雑さは償却定数であり、_std::deque_の最上部と最下部に項目を挿入することは定数であるということを読んだことがあります。これらの両方のコンテナにランダムアクセスイテレータがあるため、任意のインデックスの要素は定数です。これらの事実に誤りがある場合はお知らせください._std::vector_または_std::deque_の要素へのアクセスが一定である場合、erase O(n )。答えの1つ ここ ここでは、消去による要素の削除がO(n)であると述べています。 eraseは開始イテレータと終了イテレータの間の要素を削除するので、答えは基本的にO(n)が2つのイテレータ間の要素の数に依存し、ベクトルから単一の要素を削除することを意味します/インデックスの両端キューはゼロになりますか?

16
Rajeshwar

_std::vector_と_std::deque_の場合は少し異なり、C++ 98とC++ 11の場合も異なります。

std :: vector

std::vector::erase()の複雑さは、消去される範囲の長さと、範囲の終わりとコンテナーの終わりの間の要素数の両方に対して線形です(したがって、要素を最後から消去すると、一定の時間がかかります)。 。

C++ 2003 _[lib.vector.modifiers]_読み取り:

_iterator erase(iterator position);
iterator erase(iterator first, iterator last);`
_

...

複雑さ:Tのデストラクタは、消去された要素の数に等しい回数呼び出されますが、割り当てTの演算子は、消去された要素の後のベクトル内の要素の数に等しい回数呼び出されます。

C++ 14ドラフトN4140 _[vector.modifiers]_読み取り:

複雑さ:Tのデストラクタは、消去された要素の数と同じ回数呼び出されますが、移動Tの代入演算子は、消去された要素の後のベクトル内の要素の数に等しい回数呼び出されます。

したがって、C++ 11/14の実装は、コピーの割り当てではなく移動の割り当てを実行するため、一般的にはより効率的ですが、複雑さは同じままです。

std :: deque

std::deque::erase()の複雑さは、消去された範囲の長さと2つの数値のminimumの両方に対して線形です:残りの要素の数範囲の開始前、および範囲の終了後の残りの要素数。したがって、要素を最初からまたは最後から消去するには、一定の時間がかかります。

C++ 2003 _[lib.deque.modifiers]_:

_iterator erase(iterator position);
iterator erase(iterator first, iterator last);
_

複雑さ:デストラクタへの呼び出しの数は消去された要素の数と同じですが、代入演算子の呼び出しの数はatですmostは、消去された要素の前の要素数と消去された要素の後の要素数の最小値に等しくなります。

C++ 14ドラフトN4140 _[deque.modifiers]/5_:

複雑さ:デストラクタへの呼び出しの数は消去された要素の数と同じですが、代入演算子の呼び出しの数はです消去された要素の前の要素数と消去された要素の後の要素数のうち、小さい方の数。

したがって、C++ 98とC++ 11/14でも同じですが、C++ 11は移動割り当てとコピー割り当てのどちらかを選択できる点が異なります(ここでは、表現に移動についての記述がないため、規格に不整合が見られます。 _std::vector_のような割り当て-別の質問の理由かもしれません)。

また、文言の「最大」と「これ以上」には注意してください。これにより、実装は線形よりも効率的になりますが、実際には線形です( [〜#〜] demo [〜#〜] )。

8
Anton Savin

要素の削除は確かにO(n)です。削除する要素を見つけるために行う必要があるためではなく、すべての要素に対して行う必要があるためですafterそれ。これらの要素は、空のスロットを満たすために下にスライドする必要があります。

したがって、平均して、eraseはベクトルの約半分の要素を取得するため、要素の約半分をシフトする必要があります。したがって、O(n)です。最良の場合、最後の要素を消去します-スライドは必要ありません。最悪の場合、最初の要素を削除します。次に移動する必要がありますevery他の要素。

5
Barry

ベクトルの要素を消去することは、O(n)です。これは、要素を削除した後も、作成されたギャップを満たすためにすべての連続する要素をシフトする必要があるためです。ベクトルにn個の要素がある場合、最悪の場合、n-1個の要素をシフトする必要があるため、複雑度はO(n)です。

4
shimonb89

この方法を使用すると、時間の複雑さ=範囲の長さ+シフトの長さ(n-範囲の終わり)

    vector<int> it = (vector<int>::iterator) &vec[pos];
    vec.erase(it, it+length);
0
R.hatam