自定义排序函数实现时需要注意的问题

来源:互联网 发布:vb调用大漠插件 编辑:程序博客网 时间:2024/05/15 08:18

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;
}

原创粉丝点击