自定義排序函數實現時需要注意的問題

stl範型算法中的sort可以根據自定義的函數進行排序,也可以用函數對象。我今天碰到一個關於錯誤地定義此函數的問題,運行時出現assert異常,檢查了好久以後,才發現是什麼原因。 

我要比較兩個CPoint *類型的對象,定義的函數如下:

bool compair_points(CPoint const* p1, CPoint const* p2)
{
    return p1->x-p2- >x;
}
我是要用這個函數按照每個點的x座標的大小來排序,所以直接用減法,看起來沒什麼問題,於是就對一個數組排序了,但是運行時老是在sort那句出現錯誤,反正是說小於符號的問題。就像下面這樣的信息:
Debug Assertion Failed!
Program: f:"My Cpp"mfc projects"FindCenter"debug"FindCenter.exe
File: d:"microsoft visual studio 8"vc"include"algorithm
Line: 2764
 
Expression: invalid operator<
 
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)

看樣子是說小於符號定義得不對。我跟蹤到出現異常的stl的源代碼的一個函數中,就是下面這個函數:
template<class _Pr, class _Ty1, class _Ty2> inline
    bool __CLRCALL_OR_CDECL _Debug_lt_pred(_Pr _Pred, _Ty1& _Left, _Ty2& _Right,
        const wchar_t *_Where, unsigned int _Line)
    {    // test if _Pred(_Left, _Right)  and _Pred is strict weak ordering
    if (!_Pred (_Left, _Right))
        return (false);
    else if (_Pred(_Right, _Left))
        _DEBUG_ERROR2("invalid operator<", _Where, _Line);
    return (true);
    }
看 了這個函數,我就知道錯誤了。這個函數要求對於調用的兩個參數交換位置時不能得到相同的結果,其實理論上也是這樣,如果a比b小,則b肯定不會比a小。如 果定義的函數既得出a比b小,又得出b比a小,那這個函數定義得肯定有問題。所以我定義的那個比較函數有問題,裏面只有一句return p1->x-p2->x;顯然,不管p1和p2的x爲何值,只要他們的x不同,那麼這個函數都回返回true,所以這樣定義是錯誤的。應該 爲:return (p1->x-p2->x)<0;

看來以後要嚴禁,該用邏輯類型的時候就嚴格地使用邏輯類型,而不要使用算數類型,否則容易出邏輯錯誤,這樣的錯誤很難檢查。stl的代碼中對於這樣的愚蠢錯誤進行了檢查,感覺還是很人性化的,雖然提示不太明確,但是對找錯很有幫助。

顯然,對於比較函數,sort方法要求的只是小於符號,當然如果要降序排列也可以定義成別的,只要不出現像上面那樣的衝突。定義返回值不要比 較<=或者>=,因爲中間有了等於,同樣會出現邏輯錯誤,如果a>=b,則當b==a時,b>=a也是成立的,所以同樣會出錯。 兩個元素相等不能考慮在這個裏面。實際上當兩個元素相等時誰排在前面或者後面根本就不重要。如果一定要排除個順序來,就還要根據別的條件來排,比如說,我 的這個根據x座標來排序的函數,假設數組中沒有重複的點,則當x相等時,再根據y來排序,可以這樣:
bool compair_points(CPoint const* p1, CPoint const* p2)
{
    if(p1->x!=p2->x)
        return (p1->x-p2->x)<0;
    else
        return (p1->y-p2->y)<0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章