8

class Personデータ メンバー ' ' に基づいてのオブジェクトの配列を並べ替えたいと考えていますage。オブジェクトを に保存しますvector<Person> v

私が理解している限り、このアクションを実行するには少なくとも 4 つの方法がある可能性があり、以下に記載されている方法に基づいて次の質問があります。

  1. operator()クラス内での定義はどのように機能しますか? ここでも「<」演算子をオーバーロードしないでください。どうして '()' ?

  2. 方法1では第3引数にオブジェクトを送ったのですが、方法2では関数名を送ってしまいました。なぜそうなのですか?

  3. 4つの方法のうち、どれが最適ですか? 方法3が一番簡単だと感じました。

方法 1

class cmp
{
public:
    bool operator() (  Person const &a,  Person const &b )
    {
        return a.age < b.age ;
    }
};

sort( v.begin(), v.end(), cmp());

方法 2

bool cmp( const Person a, const Person b ) 
{
    return a.age < b.age ;
}

sort( v.begin(), v.end(), cmp );

方法 3

bool operator < ( const Person a, const Person b )
{
    return a.age < b.age ;
}

sort( v.begin(), v.end());

方法 4

//using lambda expression
sort( v.begin(), v.end(), [](const Person &a, const Person &b){return a.age < b.age;});
4

4 に答える 4

9

(またはそのことについては任意の関数)を使用して範囲を並べ替えるには、範囲内std::sortの 2 つの要素がどのように比較されるかを知る必要があります。

標準ライブラリ関数std::sortには2 つの種類があります。1 つは を使用しoperator<、もう1 つは比較関数/ファンクターを使用します。コードでそれらの両方を使用しました。特に、例の 3 番目のものは使用<し、残りは比較関数/ファンクターを使用しています。

どちらが最良のアプローチですか?

まあ、それは依存します。を使用するものは固定されているため柔軟性operator<が低くなりますが、タイピングも少なくて済みます。十分な場合に使用してください。

もう 1 つは、任意の比較関数を渡して、それに応じて要素を並べ替えることができるため、より柔軟です。物足りない時に使いますoperator<。また、このフレーバーを選択すると、他の選択肢もあります。比較子は、functionfunctor、またはlambdaである可能性があります — 関数または functor (名前空間レベルで定義されている) を使用する場合、それらを再利用できます。一方、ラムダは通常関数スコープで定義されるため、名前空間スコープで定義しない限り、再利用可能ではありません。その場合、関数とほとんど同じです。

intたとえば、 のベクトルを昇順で並べ替えたいとします。

 std::vector<int>  v{10, 3, 12, -26};
 std::sort(v.begin(), v.end());
 print(v);

出力: -26,3,10,12. 仕事もそうoperator<です。

しかし、大きさだけを考慮して要素をソートしたい場合(つまり、符号を無視する場合) は、別のフレーバーを使用する必要があります。

 std::vector<int>  v{10, 3, 12, -26};
 auto abs_cmp = [](int a, int b) { return std::abs(a) < std::abs(b); };
 std::sort(v.begin(), v.end(), abs_cmp);
 print(v);

出力: 3,10,12,-26. これが、この場合に期待される出力です。

それが役立つことを願っています。

于 2013-11-10T09:12:35.320 に答える
4

sort 関数には 2 つのオーバーロードがあります

私。 void sort( RandomIt first, RandomIt last );比較機能を受け入れません。アイテムがoperator<定義されていることを期待しています。方法 3 では、このオーバーロードを使用しています。

template< class RandomIt >
void sort( RandomIt first, RandomIt last )
{
    ...

    if (*i < *j)
      ....

    ...
}

 

ii. 比較機能を受け入れます。項目が定義されvoid sort( RandomIt first, RandomIt last, Compare comp );ていない場合に役立ちます。operator<

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp )
{
    ...

    if (comp(*i, *j))
      ....

    ...
}

メソッド 1、2、4 はこのオーバーロードを使用します。渡された 3 番目の引数はすべて、 で呼び出すことができます()。方法 1、 によってオブジェクトを送信しますcmp()。このオブジェクトはオーバーロードされてoperator()おり、上記のコードはそれを呼び出します。方法 2 および 4 は、関数へのポインターを送信し、関数へのポインターは によって呼び出すことができます()

于 2013-11-10T09:12:04.010 に答える
2

クラス内で定義された operator() はどのように機能しますか? ここでも「<」演算子をオーバーロードしないでください。どうして '()' ?

operator()関数呼び出し演算子です。クラスのインスタンスはcmp、関数が呼び出し可能であるのと同じ方法で呼び出し可能です。呼び出しはsort、必要な比較を実行するために必要です。

方法1では第3引数にオブジェクトを送ったのですが、方法2では関数名を送ってしまいました。なぜそうなのですか?

のインスタンスcmpは呼び出し可能です。関数名は呼び出し可能です。

4つの方法のうち、どれが最適ですか? 方法3が一番簡単だと感じました。

3 の主な短所は、年齢に応じて、ある Person が別の Person よりも小さいか大きいかを定義したことです。他の場所で名前で並べ替えたい場合はどうしますか? 既に Person を定義operator<しているため、同じトリックを再度実行することはできません。他の 3 つのメソッドはすべて、比較の一般的な意味を定義するのではなく、特定の並べ替えで使用するための比較を定義しますPerson

2 の主な欠点は、コンパイラが 1 または 4 よりもインライン化するのがやや難しいことです。実際には 1 よりも利点はありませんが、完全を期すsortために、関数ポインターを使用できることは素晴らしいことです。

sort4 の主な利点は、比較を 1 回だけ使用する場合、ファイル内の別の場所ではなく、を呼び出す同じコード行にある方がよい場合が多いことです。

1 の主な利点は、(4 とは異なり) C++03 で動作することです。4 は多かれ少なかれ 1 の新しい構文です。1 には、コンパレーターを他のコードで同じ名前で使用できるようにするという利点もあります。必要に応じて、ラムダを使用してそれを実現することもできます (auto変数に割り当てることでラムダに名前を付けます)。

于 2013-11-10T09:28:05.393 に答える
1
  1. operator() を持ち、オブジェクトの比較中に使用されるfunctorオブジェクトを提供するだけです。
  2. 私の知る限り、sort はファンクタ、関数、およびラムダ式を受け入れて、それらを使用してオブジェクトを比較します。
  3. 方法 3 では、比較するファンクタ、関数、またはラムダ式を提供しないため、デフォルトで標準の operator< を使用してソートされます。あなたが望むように、明らかにそれはあなたの Person オブジェクトを年齢でソートしません。私の意見では、ラムダ式を使用した方法 4 が最もクリーンな形式です。
于 2013-11-10T09:13:14.153 に答える