关于stl优先队列重载小于运算符的问题

来源:互联网 发布:淘宝买ps4哪家店好 编辑:程序博客网 时间:2024/05/29 14:34

class G
{
public:
    int step;
    int p;
};
bool operator<(const G &a,const G &b)
{
    if(a.step>b.step)
        return true;
    else
        if(a.p>b.p)
            return true;
        else
            return false;
}

主函数中使用优先队列
priority_queue<G> q;
这样的使用在vs2008下是会报错的。但貌似VC6下不会报错。

打断点跟了下,发现当a.step>b.step且b.p>a.p时就会报错。
也就是当输入为(a,b)时返回true,而输入为(b,a)时也返回true时就会报错~


在网上问了加上自己打断点跟到的说下这个优先队列

下面这段是csdn上qq120848369回答的
priority_queue一般就是用堆做的,记不清了,默认是用less比较实现的大根堆,比如当先维护堆,从父结点A开始下降整理堆,它会用A的孩子B与A调用less<>对象假设名字叫cmp,会这样传参,if(cmp(A,B)){那么调换A,B结点值} ,less里肯定是 return A<B; 所以我们想要实现小根堆,在传参次序为(A,B)的情况下,只能修改比较函数cmp,如果A<B,返回false,A>B才返回真。

qq120848369还给出了相关的代码:
class G
{
    friend struct cmp;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private:
    int step;
    int p;
};
~~~~~~~~
struct cmp
{
    bool operator()(const G&a,const G &b)
    {
        if(a.step > b.step)
            return true;
        else if(a.step < b.step)
            return false;
        else
            return a.p>b.p;
    }
};
int main()
{
    priority_queue<G,vector<G>,cmp> q;
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    return 0;
}
(代码被我删掉很多,这里只是相关的部分。)

还有ddc回答的
c++标准里,返回个bool 的函数/仿函数叫Predicates,但是有规定,行为必须是确定的(大概是这个意思,_Pred(Left,Rigth) 和 !_Pred(Right,Left)相等,具体原话我记不得了).你那个不是Predicates,所以运行出错,VC6估计没做这个判断,但行为是不确定的。
~~~~~~~~~~~~
计算机理解的并不一定是你要表达的,在范型算法里,大量while(),像这种比较、交换等算法,如果a<b,swap(a,b),下一个循环到此如果b<a,swap(b,a),就会构成死循环。我只是举个例子,估计现在没这种问题,而且以后也不一定会碰到,但是写STL那些人想到了,所以在那里加了行_DEBUG_ERROR2.
话说回来,(5,2),(6,5),(5,1)都插入队列,你认为该是什么顺序呢?反过来在插一遍呢,是你要的结果吗?总有一个(5,2)和(5,1)顺序和你的预期不一样吧
~~~~~~~~~~~~
 


下面说下自己的
打断点跟到了xutility里头的这段报错的代码
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);
    }
仔细看下发现这里头只对_Pred(_Left, _Right)返回true时做了_Pred是否等于!_Pred的判断,_Pred返回为false时没有做这个检查。不过返回个false对排序没有影响,返回为true时才做交换。于是和ddc说的一样,如果没有这样的判断很难保证当(a,b)==(b,a)==true时不会陷入死循环,a和b两个就一直交换下去。
不光是重载这个<运算符,在一些排序算法中这样的问题也是非常值得注意的。

同时打断点跟到的队列数据并非是有序的存储的,说明可能就是用的堆的方式来存储的。

在说下在c++ primer上看到的
栈和队列都是基于deque容器实现的,而优先队列则默认基于vector实现的。
同时可以覆盖其基础容器类型。
使用类似qq120848369给出的代码中的方式
priority_queue<G,vector<G>,cmp> q;
不过对使用的容器有一定的限制。
stack可以选用vector,list
queue需要容器提供push_front操作,所以只能选用list
priority_queue则需要提供随机访问的功能,因此只能建立在vector上。

这里附带一点关于vector的,vector使用的是一维数组的方式存储的。当存储的元素个数超出数组的大小时,vector将重新分配空间。

原创粉丝点击