web-dev-qa-db-ja.com

STLにソートされたコンテナはありますか?

STLにソートされたコンテナはありますか?

つまり、std::vector<Foo>があります。Fooはカスタムメイドのクラスです。クラスFooのフィールドを比較する何らかのコンパレーターもあります。

今、私のコードのどこかでやっています:

std::sort( myvec.begin(), myvec.end(), comparator );

コンパレータで定義したルールに従ってベクトルをソートします。

次に、クラスFooの要素をそのベクターに挿入します。できれば、ただ書きたいと思います。

 mysortedvector.Push_back( Foo() );

そして何が起こるかというと、ベクターはコンパレーターに従ってこの新しい要素をその場所に配置します。

代わりに、今私は書く必要があります:

myvec.Push_back( Foo() );
std::sort( myvec.begin(), myvec.end(), comparator );

ベクトルは既にソートされており、必要なのは新しい要素を適切に配置するだけなので、これは時間の無駄です。

私のプログラムの性質上、キーと値のペアがなく、単純なベクターだけなので、std::map<>は使用できません。

stl::listを使用する場合、挿入するたびにsortを再度呼び出す必要があります。

23
Igor

はい、 - std::setstd::multisetstd::map 、および std::multimap はすべて std::less はデフォルトの比較操作として。使用される基本的なデータ構造は、通常、赤黒木などのバランスの取れた二分探索木です。したがって、これらのデータ構造に要素を追加してから、含まれている要素を反復処理すると、出力はソートされた順序になります。データ構造にN個の要素を追加する複雑さはO(N log N)、または一般的なO(log N)複雑さの並べ替えを使用してN要素のベクトルを並べ替えることと同じです。

特定のシナリオでは、キー/値のペアがないため、std::setまたはstd::multisetがおそらく最善の策です。

46
Jason

Jasonの answer を拡張したいと思います。 _std::set_ または _std::multiset_ のいずれかが特定のシナリオに最適な選択肢であることに、Jasonに同意します。選択肢をさらに絞り込むための例を提供したいと思います。

次のクラスFooがあると仮定します。

_class Foo {
public:
    Foo(int v1, int v2) : val1(v1), val2(v2) {};
    bool operator<(const Foo &foo) const { return val2 < foo.val2; }
    int val1;
    int val2;
};
_

ここで、Fooは_<_演算子をオーバーロードします。このように、明示的なコンパレータ関数を指定する必要はありません。その結果、次の方法で_std::multiset_の代わりに_std::vector_を使用できます。 Push_back()insert()に置き換えるだけです:

_int main()
{
    std::multiset<Foo> ms;
    ms.insert(Foo(1, 6));
    ms.insert(Foo(2, 5));
    ms.insert(Foo(3, 4));
    ms.insert(Foo(1, 4));

    for (auto const &foo : ms)
        std::cout << foo.val1 << " " << foo.val2 << std::endl;

    return 0;
}
_

出力:

3 4
2 4
1 5
1 6

ご覧のとおり、コンテナは_val2_演算子に基づいて、クラスFooのメンバー_<_でソートされます。ただし、_std::set_の代わりに_std::multiset_を使用すると、異なる出力が得られます。

_int main()
{
    std::set<Foo> s;
    s.insert(Foo(1, 6));
    s.insert(Foo(1, 5));
    s.insert(Foo(3, 4));
    s.insert(Foo(2, 4));

    for (auto const &foo : s)
        std::cout << foo.val1 << " " << foo.val2 << std::endl;

    return 0;
}
_

出力:

3 4
1 5
1 6

ここでは、_val2_が4である2番目のFooオブジェクトが欠落しています。これは、_std::set_が一意のエントリのみを許可するためです。エントリが一意かどうかは、提供された_<_演算子に基づいて決定されます。この例では、_<_演算子は_val2_メンバーを相互に比較します。したがって、2つのFooオブジェクトは、それらの_val2_メンバーが同じ値を持つ場合、等しくなります。

したがって、選択は_<_演算子に基づいて等しい可能性のあるFooオブジェクトを保存するかどうかによって異なります。

イデオンのコード

9
honk