1

すべて、次の問題があります。

次のクラスを検討してください。

class A
{
public:
.....
private:
    int m_a, m_b;
    double m_c;
};

このクラスのオブジェクトのベクトルがあります。

このベクトルはグリッドに表示され、ユーザーは列ヘッダーをクリックしてグリッド (ベクトル) の要素を並べ替えることができます。この問題は、ユーザーが CTRL キーを押したまま行ヘッダーをクリックすると、グリッド (ベクトル) を 2 列 (クラスのメンバー) でソートする必要があるという事実から発生します。

1 つのメンバー (列) に基づいて並べ替えを行う単純なソーター クラスを作成できますが、2 番目の並べ替え列を選択して並べ替えを行う方法がよくわかりません。

誰か助けてくれませんか?

4

2 に答える 2

2

これを行う最も簡単な方法は、最も重要でない列から順番に各列で並べ替えることです。したがって、ユーザーが で並べ替えを選択した場合、a then b then c最初に で並べ替えc、次に で並べ替えb、最後に で並べ替えますa。最後の 2 つの並べ替え (bおよびa) は安定した並べ替え( std::stable_sort) である必要があります。これにより、それ以外の場合は等しい要素の既存の順序が保持されます。

それを行うもう 1 つの方法 (ほぼ確実に高速ですが、実用的ではない可能性があります) は、カスタムの比較関数を使用することです。しかし、独自の比較関数を考え出すのは簡単ではありません。あなたが提供する例では、変数が3つしかない場合、可能な比較関数は6つしかありません(a、b、cの順序ごとに1つ-指定されていない列を最後に配置できます)が、一般的には列挙するにはあまりにも多くの可能性があります。switch ステートメントの複雑なコレクションを使用して一般的なコンパレーターを作成することもできますが、そのコンパレーターのオーバーヘッドは、ベクトルを複数回ソートする以上のものになる可能性があります。

于 2013-11-04T06:52:22.933 に答える
1

適切な比較関数を動的に作成するコードを提供するように求められたため...

std::stable_sort免責事項: 次のコードは、安定した並べ替えアルゴリズムを使用してベクトルを複数回並べ替えることと、パフォーマンスの点ではおそらく比較できません。アイデアを説明するためだけのものです。次のコードはC++11、まだ利用できない機能を使用して記述されています。C++03ただし、たとえば、を使用して簡単に書き換えることができますboost

Aクラスと、メンバー変数ごとにいくつかのゲッター関数があると仮定しましょう。

class A
{
    public:
        float getA() const;
        int getB() const;
        // and so on.
};

-1の 1 つのインスタンスがA他のインスタンスよりも小さい場合は 、0等しい場合は 、そうでない場合は を返す関数を定義します1。これらの機能は、より簡単に組み合わせることができます。

using comparator = std::function<int (const A&, const A&)>;

template <class T>
comparator
make_comparator( T (A::*f)() const )
{
    return [f]( const A& lhs, const A& rhs ) -> int {
        if( (lhs.*f)() < (rhs.*f)() )
            return -1;
        else if( (lhs.*f)() == (rhs.*f)() )
            return 0;
        else
            return 1;
    };
}

ここで、メンバー関数ごとに を定義していcomparatorます:

std::vector<comparator> comparators = {
    make_comperator( &A::getA ), make_comparator( &A::getB )
};

比較機能を簡単に組み合わせることができます。

comparator
make_comparator(
    const std::vector<comparator> &comparators,
    std::deque<unsigned int> indices )
{
    if( indices.empty() )
    {
        return []( const A&, const A& ) -> int { return 0; };
    }
    unsigned int first = indices.front();
    indices.pop_front();
    return [first, &comparators, indices]( const A& lhs, const A& rhs ) -> int {
        int firstCompared = comparators[first]( lhs, rhs );
        if( firstCompared != 0 )
        {
            return firstCompared;
        }
        else
        {
            return make_comparator( comparators, indices )( lhs, rhs );
        }
    };
}

lessこれらの関数は、のようなファンクターに変換できます。

std::function<bool (const A&, const A&)>
to_less( std::function<int( const A&, const A& )> f )
{
    return [&f]( const A& lhs, const A& rhs ) -> bool {
        return f( lhs, rhs ) < 0;
    };
}

2 番目の列よりも 1 番目の後の並べ替え:

std::sort( instances.begin(), instances.end(),
            to_less( make_comparator( comparators, { 0, 1 } ) ) );
于 2013-11-04T09:33:28.783 に答える