使用指针和比较器C ++的优先级队列

时间:2014-06-02 14:36:33

标签: c++ pointers priority-queue comparator

我刚开始学习C ++,有一半时间我不知道自己在做什么,花几个小时在Google上搜索并盲目地将代码放入我的项目中,这可能是一个基本问题,但我可以似乎做对了。

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

Edge类中的

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

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

我在声明priority_queue时遇到问题。详情:

如果我直接使用这些,边类会给我一个错误“必须有一个类的参数”,我明白我不能将两个指针重载到bool运算符中,所以这就是我的意思尝试过:

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

^我甚至不确定将struct放在类中是否正确,另外在这个原因我不知道该放在我的Edge.h文件中。

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

至于Graph类是真正的问题所在,我甚至无法通过声明优先级队列而不会出现错误。

Graph.h中的

#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

我不知道为什么第一个错误,但第二个错误我清楚地理解它,但我不知道如何解决它,我应该在CompareWeight面前放一些东西吗?我尝试过很多东西,没什么用。

任何帮助将不胜感激!否则我可能会失败这个课程。 第一次询问stackoverflow,如果我做错了请告诉我。

2 个答案:

答案 0 :(得分:9)

您可以将bool operator()(Edge*, Edge*)作为类Edge的常规成员实施,但很少这样做。

标准库算法的比较器有以下惯用语,所有必须提供对正在处理的序列中所包含对象的严格弱排序:

  1. 独立的仿函数类
  2. 独立operator <重载
  3. 对象级成员operator <重载。
  4. 独立功能
  5. 静态类功能
  6. 静态类仿函数类
  7. 其他一些......
  8. 此列表中的第五个(5)是最接近他们指示尝试的内容,但从未实现为{{1} }。作为operator()的成员,可能执行(1),但为此,Edge类型必须支持默认构造。我将在一分钟内解释如何做到这一点。在上面列出的选项中,对于这种特定情况,性能(内联的可能性)和实现容易度的最佳候选者是(1)和(6)。如果您的队列中包含实际的Edge 对象而不是Edge 指针(3),那么这将非常适合,并提供良好的性能。

    有序容器和容器适配器(如优先级队列)的比较器的要点是比较两个符合严格弱排序的项目。如果你不知道那是什么,see this link。在实现中,它归结为:if,且仅当 Edge返回 true 时,否则返回 false 。这意味着必须执行以下内容:

    • x < y始终返回 false
    • 如果x < x返回 true ,则x < y 必须返回 false
    • 如果y < xx < y都返回false,那么y < x 等效x

    不小心编码比较器不遵守这些规则是一个常见的错误。防范这一点。

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

    班级边缘

    y

    Class CmpEdgePtrs

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

    类图

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

    老实说,这是对使用共享智能指针的尖叫,但我把它留给你。上面的代码很有可能在实现优先级队列逻辑的标准库算法中的整个使用位置内嵌比较器,因此在给定指针容器的约束下,性能将很有可能达到最优。 / p>


    履行指定要求

    这个可以完全在类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; }; 个对象的成员变量,而不是通过公共getter和setter或者去找朋友比较器。但它有一个缺点。除了容器适配器之外,没有什么能阻止容器适配器构建Edge对象而不指定源,目标和权重。

    简而言之,这样做有什么好处,以及使这项工作所需的代码使用不当的潜在问题,为此,我建议改为使用第一个选项。

    祝你好运

答案 1 :(得分:0)

您失踪的内容称为前瞻性声明。在Edge.h中,您可以单独在一行上编写class Vertex;。在这一行之后,C ++知道有这样一个类,因此Vertex *是一个指针(而不是乘法的前半部分)。

[编辑] 此前向声明替换Edge.h中的#include "Vertex.h"