web-dev-qa-db-ja.com

演算子<および厳密な弱い順序付け

厳密な弱い順序付けの概念を満たすように、n-タプル(たとえば、3-タプル)にoperator<を定義する方法は? boostライブラリにoperator<が正しく定義されたタプルクラスがあることは知っていますが、何らかの理由で使用できません。

45
Konstantin
if (a1 < b1)
  return true;
if (b1 < a1)
  return false;

// a1==b1: continue with element 2
if (a2 < b2)
  return true;
if (b2 < a2)
  return false;

// a2 == b2: continue with element 3
if (a3 < b3)
  return true;
return false; // early out

これは、a1が最も重要でa3が最も重要でないことによって要素を並べ替えます。

これは無限に続けることができます。これをTのベクトルに適用し、a [i] <a [i + 1]/a [i + 1] <a [i]の比較を繰り返します。アルゴリズムの別の表現は、「等しいときにスキップしてから比較する」です。

while (i<count-1 && !(a[i] < a[i+1]) && !(a[i+1] < a[i])
  ++i;
return i < count-1 && a[i] < a[i+1];

もちろん、比較にコストがかかる場合は、比較結果をキャッシュすることをお勧めします。


[編集]間違ったコードを削除


[編集] operator<だけではない場合、パターンを使用する傾向があります

if (a1 != b1)
  return a1 < b1;

if (a2 != b2)
  return a2 < b2;

...
38
peterchen

厳密な弱い順序付け

これは、2つのオブジェクト間の関係を定義する数学用語です。
その定義は:

F(x、y)とf(y、x)の両方がfalseの場合、2つのオブジェクトxとyは同等です。オブジェクトは常に(非反射性不変量によって)それ自体と等価であることに注意してください。

C++に関しては、これは、特定のタイプの2つのオブジェクトがある場合、演算子<と比較すると、次の値を返す必要があることを意味します。

X    a;
X    b;

Condition:                  Test:     Result
a is equivalent to b:       a < b     false
a is equivalent to b        b < a     false

a is less than b            a < b     true
a is less than b            b < a     false

b is less than a            a < b     false
b is less than a            b < a     true

同等/少ないをどのように定義するかは、オブジェクトのタイプに完全に依存します。

正式な定義:
厳密な弱い順序付け

コンピュータサイエンス:
厳密な弱い順序付け

オペレーターとの関係:
コンパレータ

54
Martin York

...非常に古い質問に対する新しい回答ですが、既存の回答はC++ 11からの簡単な解決策を見逃しています...

C++ 11ソリューション

C++ 11以降では、データの保存に使用できる _std::Tuple<T...>_ が提供されます。 Tuplesには一致する _operator<_ があり、最初に左端の要素を比較し、結果が明確になるまでタプルに沿って機能します。 strict weak ordering を提供するのに適しています。 _std::set_ および _std::map_

他の変数(structのフィールドなど)にデータがある場合は、 std::tie() を使用してタプルof references。次に、別のタプルと比較できます。これにより、ユーザー定義のclass/structタイプの特定のメンバーデータフィールドに_operator<_を簡単に記述できます。

_struct My_Struct
{
    int a_;
    double b_;
    std::string c_;
};

bool operator<(const My_Struct& lhs, const My_Struct& rhs)
{
    return std::tie(lhs.a_, lhs.b_, lhs.c_) < std::tie(rhs.a_, rhs.b_, rhs.c_);
}
_
28
Tony Delroy

単に適切に定義されたoperator <()が既にある3要素ベクトルを使用するだけで済みます。これには、何もしなくてもN要素に拡張できるという利点があります。

6
anon

ブーストバージョンを使用できない場合でも、コードにニックを入れることができるはずです。私はこれをstd :: pairからニックネームを付けました-3タプルは私が推測するのと同様になります。

return (_Left.first < _Right.first ||
        !(_Right.first < _Left.first) && _Left.second < _Right.second);

編集:数人が指摘したように、コードで使用するために標準ライブラリからコードを盗む場合、これらの名前は予約されているので、アンダースコアが前面にあるものの名​​前を変更する必要があります。

2
markh44