C++: Strict Weak Ordering


想講講C++ STL中各種算法都用到的一個概念,Strict Weak Ordering。

舉個例子,來說明為什么寫C++要知道這個東西。

假如你定義了一個類型 MyType ,而且這個類型是可比的(comparable,定義了 <  這個operator):

struct MyType {
    int first;
    int second;
MyType(int f,int s):first(f),second(s){} MyType(){ .... }
bool operator < (const MyType &b){ return a.first < b.first; } };

 

現在一個 vector 里裝着很多這種類型的對象,你想對這個 vector 排序:

vector<MyType>  vec { obj1,obj2,obj3 };
std::sort(vec.begin(),vec.end());

之所以能用 std::sort() 來對任意類型排序,而不用給 std::sort() 傳遞規則,是因為 std::sort() 是默認采用  < 這個operator來排序的。

現在問題來了,只有   <  這個operator怎么知道兩個對象是否相等?

簡單來說就是,假如  !(a<b) && !(b<a) ,那么 a==b 

 

但是,假如我沒有為MyType定義   <  這個 operator,我想在 std::sort() 的時候用 lambda 來給出比較規則,那么,怎么才能知道兩個對象是否相等? 這樣:

std::sort(vec.begin(),vec.end(), [](MyType a, MyType b){ a.second < b.second ; });

可以看到,這個 lambda 就等同於上面的 operator < () 。

 

可以看到,這里,只需要給 std::sort() 一個比較規則即可。這個比較規則不一定是要  <  ,可以是  >  或者其他:

 std::sort(vec.begin(),vec.end(),[](MyType a ,MyType b){ a.second > b.first; }); 

 

(術語上,這個比較規則就是離散數學里面講的Relation,用來描述兩個object之間的關系)

 

但是,並不是任何比較規則都是可以的,這個比較規則一定要滿足 Strict Weak Ordering 的要求。比如,你不能用  <=  或  >=   號這個比較規則:

std::sort(vec.begin(),vec.end(),[](MyType a, MyType b){ a.first <= b.first; });

為什么?因為,如果  a  確實等於  b ,當你用  !(a<=b)&&!(b<=a)  去看兩者相不相等,會發現返回的是 false。這當然是不對的

(有人問我為什么不直接用  ==  去比較  a  和   b 是否相等,因為我們並沒有給 MyType 定義   ==  這個 operator)

 

那么,什么是 Strict Weak Ordering 呢?

下面是由WikiPedia上抄來的定義

strict weak ordering is a binary relation < on a set S that is a strict partial order (a transitive relation that is irreflexive, or equivalently,[5] that is asymmetric) in which the relation "neither a < b nor b < a" is transitive.[1] Therefore, a strict weak ordering has the following properties:

  • For all x in S, it is not the case that x < x (irreflexivity).
  • For all xy in S, if x < y then it is not the case that y < x (asymmetry).
  • For all xyz in S, if x < y and y < z then x < z (transitivity).
  • For all xyz in S, if x is incomparable with y (neither x < y nor y < x hold), and y is incomparable with z, then x is incomparable with z (transitivity of incomparability).

This list of properties is somewhat redundant, as asymmetry follows readily from irreflexivity and transitivity.

注意定義中所說的relation就是我們上面說的“比較規則”(數學上叫relation。relation是一個更加廣的概念,不一定是比較規則)

而且,定義中用到的  <  並不是小學數學中的小於號,它只是代表一個relation(當然,普通的小於號 < 是最簡單的滿足Strict Weak Ordering的relation了)。

容易看出,小於等於號  <=  和大於等於號  >=  並不滿足 irreflexivity 的要求。

 

可以看到,我們上面說的相等,就是這個定義里說的 "the relation 'neither a<b nor b<a' ",也就是,incomparable

這里的一個比較細微的地方是,“相等”的概念。在這里,"相等"( equivelant )並不意味着  a  和 b  是一樣( identical ) 的東西,而只是  !(a<b) && !(b<a) (incomparable)(注意 <  只是一個relation,並不一定是我們常說的小於號)

也就是說,“相等”在這里已經變成了  !(a<b) && !(b<a) ,而不是  ==  號(而且我們根本就沒有定義  ==  這個operator,你根本沒法用這個運算符來看  a  和  b  是否相等)

比如,假如:

MyType a(1,100);

MyType b(1,99);

那么,在 std::sort(vec.begin(),vec.end()); 中, std::sort() 去判斷  a   和  b  是否“相等”的時候,會把 a  和  b 當做是相等的,即使 a  和 b  這個兩個對象的 second不一樣 (因此  , b  也不一樣)。這是因為我們用了  <  這個運算符,而  <   這個運算符並不去比較 second,只關心 first 

 

在數學上,這個“相等”的其實就是一個 equivalent relation(看下文定義)

明白這個概念很重要,不然,看文檔會比較痛苦(我在看Matthew H. Austern那本《Generic Programming and the STL》的時候,就是沒能明白這個概念,糊塗了很久......)

 

我想講的已經講完,最后,來捋一捋邏輯。

###  C++ 語言中為什么要默認采用 < 來作為std::sort()和其他與排序相關的函數的比較符號呢?

     第一,必須定義一個默認的比較運算符,否則每次排序都要提供一個運算子,太麻煩了。

###  為什么不用其他運算符?

    可以用其他運算符號,比如,可以用 > 。只要這個運算符能滿足strict weak ordering即可。

###  為什么一定要滿足strict weak ordering?

    因為,滿足strict weak ordering的運算符能夠表達其他所有的邏輯運算符(logical operator):

  • <(a, b)  : (a < b)
  • <=(a, b): !(b < a)
  • ==(a, b): !(a < b) && !(b < a)
  • !=(a, b) : (a < b) || (b < a)
  • >(a, b)  : (b < a)
  • >=(a, b): !(a < b)

    但是,不滿足strict weak ordering的就不一行。比如上文中所講的 <= 號和 >= 號,當a==b時,!(a<=b)&&!(b<=a)並不為真。

 

再次重申,這里所說的”運算符“,“相等”,“小於”等詞匯,都應該與C++中的范型編程聯系起來。

也就是說,“運算符”這個詞,不僅僅是 < 號,> 號這些簡單的數學運算符,同時應該包括C++中的functor,lamda等。說白了,能用來比較兩個元素,並且返回true或false的東西。< 號和 > 號這些是最簡單的的”運算符“了,但是你也可以寫一個一千行的函數,接受兩個參數,然后返回一個布爾值。

同樣道理,”小於“,”大於“這些詞匯也不單是 < 和 > 。

假如你定義了一個 < ,那么

  • a > b, 即 b < a
  • a == b,即 !(a < b) && !(b < a)
  • ...

也就是,用一個運算符表示其他所有的運算符。

 

 

 

 

最后在這里補一補離散數學的坑。關於 relationordering

關於reflexive,symmetry,transitivity這些術語的一個總結(摘自這里):

Given a function (which models a binary relation) over a domain D, and a∈ D:

  • Reflexivity: f (a, a) is true.
  • Asymmetry: For a ≠ b, if f(a, b) is true, f(b,a) is false
  • Anti-symmetry: If f(a, b) and f(b, a) are both true iff a ≡ b
  • Transitivity: If f(a, b) and f(b, c) are true, then f(a, c) is true
  • Incomparability: Neither f(a, b) nor f(b, a) is true
  • Transitivity of incomparability: If a and b are incomparable, and so are b and c, then a and c are incomparable.

 

首先是最常見的Partial Ordering 和 poset:

  A (non-strict) partial order R is a binary relation "≤" over a set S which is reflexiveantisymmetric, and transitive

       ( A set S together with a patial order R is called a patially ordered set, or poset, and is denoted by (S,R) )

        這個定義里面說的是non-strict partial ordering。最常見的non-strict partial ordering就是數學上的小於等於號 ≤ 了。這也是為什么定義中都使用 ≤ 來表示npn-strict partial odering。注意,如果沒有特殊提示,一般人說的partial ordering 就是指 non-strict partial ordering。

如果要加上 strict 的限制,則是:

A relation < is a strict order on a set S if it is

1. Irreflexivea<a does not hold for any a in S.

2. Asymmetric: if a<b, then b<a does not hold.

3. Transitivea<b and b<c implies a<c.

Note that transitivity and irreflexivity combined imply asymmetric.

最常見的strict partial order是 < 號了,這也是為什么常用 < 來表示strict partial ordering。

(non-strict partial ordering 和 strict partial ordering的定義從這里這里都可以找到)

 

為了弄清楚 non-strict 和 strict 一詞的含義,仔細看上面兩個定義。

兩者的區別在於,non-strict ordering 是 irreflexive 和 asymmetric的,而 strict ordering 是 reflexive和asymmetric的。

irreflexive 和 reflexive 是相反的概念,這個很好理解。但是 anti-symmetric 和 asymmetric 的概念卻貌似沒有交集,這個怎么理解?

首先看symmetric、asymmetric以及anti-symmetric的定義:

symmetric:

A binary relation R on a set S is symmetric when :

a,b(aRbbRa)

asymmetric:

A binary relation R on a set S is asymmetric when :

a,bS (aRb¬(bRa))

anti-symmetric:

A binary relation R on a set S is antisymmetric if there is no pair of distinct elements of S each of which is related by R to the other; i.e. :

a,bS (aR∧ bRa→ a=b)

The difference between asymmetric and anti-symmetric is that

Antisymmetric means that the only way for both aRb and bRa to hold is if a=b. It can be reflexive, but it can't be symmetric for two distinct elements. Think <=.

Asymmetric is the same except it also can't be reflexive. An asymmetric relation never has both aRb and bRa, even if a=b. Think <.

So an asymmetric relation is just one that is both antisymmetric and irreflexive.

也就是說,anti-symmetric + irreflexive -> aymmetric

所以,strict partial ordering 中的 asymmetric可以換成 anti-symmetric + irreflexive(雖然數學上這樣的替換是不正確的,但是這好理解一點),也就是說,non-strict 和 strict 的差別就在於 reflexive 和 irreflexive了。這樣就好理解了。

 

多說一句,

Every (non-strict)partial order <= induces a strict partial order

 a<b:a<=b ^ a!=b.

Similarly, every strict partial order < induces a (non-strict)partial order

 a<=b:a<b v a=b.

加減一個條件就可以在兩者之間轉換了。

 

 

Total ordering:

If (S,<) is a poset and every two elements of S are comparable, S is called a totally ordered or linearly ordered set, and < is called a total order or a linear order. A totally ordered set is also called a chain.

這里,total 的概念怎么理解呢?這樣:

A strict order is total if, for any a,b in S, either a<bb<a, or a=b

也就是說,total 要求一個絕對的可比關系。

 

 

 

The notion of incomparable:

Let < denote the relation in set S. The elements a and b of a poset (S,<) are called comparable if either a<b or b<a. When a and b are elements of S such that neither a<b nor b<aa and b are called incomparable.

 

 

Well order:

(S,<) is a well-ordered set if it is a poset such that < is a total ordering and every nonempty subset of S has a least element

 

 

 

那么,可以看出,C++中的 strict weak ordering 和 strict partial ordering想比,就是差一個weak了,這個weak,就差在 transitivity of incomparablity上(對比一下定義看看)。

值得注意的是,transitivity of incomparablity 並不是說這個集合一定是 incomparable 的,只是說,如果有incomparable的元素,那么這些incomparable的關系是可傳遞的(transitive)

 

 

 

 

 

Reference:

  • https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings
  • https://en.wikipedia.org/wiki/Partially_ordered_set
  • https://en.wikipedia.org/wiki/Total_order
  • http://sidd-reddy.blogspot.com/2011/01/i-was-going-over-c-stl-when-i-noticed.html
  • http://math.stackexchange.com/questions/585396/what-is-meaning-of-strict-weak-ordering-in-laymans-term 
  • http://www.sgi.com/tech/stl/StrictWeakOrdering.html
  • https://www.quora.com/What-is-strict-weak-ordering-in-C++-sort
  • https://en.wikipedia.org/wiki/Equivalence_relation
  • http://stackoverflow.com/questions/979759/operator-and-strict-weak-ordering
  • http://stackoverflow.com/questions/14938163/total-weak-partial-orderings-complete-definition
  • http://math.stackexchange.com/questions/778164/is-an-anti-symmetric-and-asymmetric-relation-the-same-are-irreflexive-and-anti
  • http://mathworld.wolfram.com/StrictOrder.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 Last Edit: 2016-07-31, 12:03

:)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM