带有指针和比较器的优先级队列

Priority queue with Pointers and Comparator C++

本文关键字:优先级 队列 比较器 指针      更新时间:2023-10-16

我刚开始学习c++,一半的时间我不知道我在做什么,花了几个小时在谷歌上搜索,盲目地把代码放在我的项目中,这可能是一个基本的问题,但我似乎不能得到它的权利。

这是我的作业的要求,我需要有这些:

public:
bool operator()(Edge*, Edge*)
图类中的

private:
priority_queue<Edge*, vector<Edge*>, Edge> edges

我在声明priority_queue时有问题。细节:

如果我直接使用这些,边缘类会给我一个"必须有类的参数"的错误,我知道我不能将两个指针重载到bool操作符中,所以这就是我所尝试的:

in the Edge.cpp:

#include "Edge.h"
using namespace std;
Edge::Edge(Vertex* s, Vertex* d, double w)
{
    source = s;
    destination = d;
    weight = w;
}
double Edge::getWeight()
{
    return weight;
}
struct CompareWeight : public std::binary_function<Edge*, Edge*, bool>
{
    bool operator()(Edge* e1,Edge* e2)
    {
        double w1 = e1->getWeight();
        double w2 = e2->getWeight();
        if(w1>w2){
            return true;
        }
        else {
            return false;
        }
    }
};

^我甚至不确定在类中放入结构是否正确,加上在这个原因中我不知道在我的Edge.h文件中放入什么。

in the Edge.h:

#include "Vertex.h"
class Edge
{
    public:
        Edge(Vertex*, Vertex*, double);
        double getWeight();
        friend struct CompareWeight; // ??? does not seems right
    private:
        Vertex* source;
        Vertex* destination;
        double weight;
}

至于图形类是真正的问题所在,我甚至不能通过声明优先级队列而不得到一个错误。

图中

#include "Vertex.h"
#include "Edge.h"
#include <vector>
#include <queue>
class Graph
{
    public:
        ...
    private:
        priority_queue<Edge*, vector<Edge*>, Edge> edges
        // This give pointer error: no match for call to '(Edge) (Edge*&, Edge*&)'
}

第二次尝试:

// same as above
private:
    priority_queue<Edge*, vector<Edge*>, CompareWeight> edges
    // This give error: 'CompareWeight' not declared in this scope

我不知道为什么第一个错误,但第二个错误我明白它很清楚,但我不知道如何修复它,我应该把一些东西在前面的比较重量?我试了很多方法,都没用。

任何帮助将非常感激!否则我这门课可能会不及格。第一次问在stackoverflow,如果我做错了什么,请告诉我。

您要求将bool operator()(Edge*, Edge*)实现为Edge类的常规成员是可能的,但很少这样做。

标准库算法的

比较器有以下习惯风格,所有必须为所处理的序列中包含的对象提供严格的弱排序:

  1. 独立函子类
  2. 单机operator <过载
  3. 对象类成员operator <过载。
  4. <
  5. 独立函数/gh>静态类函数
  6. 静态类函子类

这个列表上的第五个(5)是最接近的事情,看起来像他们的指令是试图做的,但它是从来没有实现为operator()。作为Edge的成员,可以执行(1),但是要这样做,Edge类型必须支持默认构造。我将在一分钟内解释如何做到这一点。在上面列出的选项中,对于这个特定情况,性能(内联的可能性)和实现便利性的最佳候选选项是(1)和(6)。如果您的队列保存实际的Edge 对象而不是Edge 指针(3)将是一个自然的适合,并提供良好的性能。

对于有序容器和容器适配器(如优先级队列),比较器的作用是比较符合严格弱排序的两个项。如果你不知道那是什么,请看这个链接。在实现中,它归结为:if, 且仅当 x < y返回true,否则返回false。这意味着必须执行以下内容:

  • x < x总是返回false
  • 如果x < y返回true,则y < x 必须返回false
  • 如果x < yy < x都返回false,则x 等于y
这是一个常见的错误,不小心编写一个比较器不遵守这些规则。要提防这种情况。

不管怎样,我离题了。在给定类定义并使用上面列表中的(1)的情况下,正确执行的一种方法是:

<

类边缘/strong>

class Edge
{
public:
    Edge(Vertex* src, Vertex* dst, double w)
        : source(src), destination(dst), weight(w)
    {
    };
    // note: const-ness
    double getWeight() const { return weight; }
    Vertex const* getSource() const { return source; }
    Vertex* getSource() { return source; }
    Vertex const* getDestination() const { return destination; }
    Vertex* getDestination() { return destination; }
private:
    Vertex* source;
    Vertex* destination;
    double weight;
};

类CmpEdgePtrs

struct CmpEdgePtrs
{
    bool operator()(const Edge* lhs, const Edge* rhs) const
    {
        return lhs->getWeight() < rhs->getWeight();
    }
};

class Graph
{
    // rest of class stuff
private:
    priority_queue<Edge*, vector<Edge*>, CmpEdgePtrs> edges;
};

老实说,这是对共享智能指针使用的尖叫,但我把它留给你。上面的代码很有可能在实现优先级队列逻辑的标准库算法的整个使用位置内联比较器,并且在给定指针容器的约束条件下,这样的性能很有可能是最优的。


完成分配的需求

这个可以完全在类Edge中完成,因为它毕竟只是一个类类型。作为优先级队列适配器的模板参数传递的第三种类型是公开bool operator()的类型,没有什么可以阻止您让Edge的实例为您做这件事。这很奇怪,但它仍然可以通过一些修改来工作:

首先,将bool operator()(const Edge*, const Edge*) const移动到声明为public的Edge类中。其次,为Edge提供默认构造函数,因为在创建函子来执行比较时,优先级队列的内部算法将需要它。

class Edge
{
public:
    // regular parameterized construction
    Edge(Vertex* src, Vertex* dst, double w)
        : source(src), destination(dst), weight(w)
    {
    };
    // ADDED: allows parameterless initialization
    Edge() 
        : source(), designation(), weight() 
    {}
    // note: const-ness
    double getWeight() const { return weight; }
    Vertex const* getSource() const { return source; }
    Vertex* getSource() { return source; }
    Vertex const* getDestination() const { return destination; }
    Vertex* getDestination() { return destination; }
    // ADDED: used when an instance of `Edge` is used as comparator functor
    bool operator ()(const Edge* lhs, const Edge* rhs) const
    {
        return lhs->weight < rhs->weight;
    }
private:
    Vertex* source;
    Vertex* destination;
    double weight;
};

class Graph
{
    // rest of class stuff
private:
    // NOTE: uses Edge-type as the functor type that will
    //  deliver the comparison of Edge pointers.
    priority_queue<Edge*, vector<Edge*>, Edge> edges;
};

这是非常不寻常的,但它的好处是允许函子直接访问被比较的Edge对象的成员变量,而不是通过公共getter和setter或必须将比较器添加为友。但它也有缺点。除了容器适配器,没有什么可以阻止某人在不指定源、目标和权重的情况下构造Edge对象。

简而言之,这样做几乎没有什么好处,并且在不正确使用所需代码时存在潜在问题,因此,我建议使用第一个选项。

祝你好运

你错过的东西叫做前向声明。在Edge.h中,只允许在一行中单独写class Vertex;。在这行之后,c++知道存在这样一个类,因此Vertex *是一个指针(而不是乘法的前半部分)。

[编辑]这个前向声明取代了Edge.h中的#include "Vertex.h"