简体   繁体   English

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

[英]Priority queue with Pointers and Comparator C++

I just started to learn C++, Half of the time I don't know what am I doing, spend hours and hours searching on Google and blindly put codes inside my project, this might be a basic question, but I just can't seems to get it right. 我刚刚开始学习C ++,有一半时间我不知道自己在做什么,花几个小时在Google上搜索并盲目地将代码放入我的项目中,这可能是一个基本问题,但我似乎无法忍受把它弄好。

This is the requirement of my assignment, I need to have these: 这是我的任务要求 ,我需要这些:

in the Edge class: 在Edge类中:

public:
bool operator()(Edge*, Edge*)

in the Graph class: 在Graph类中:

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

I have problem declaring the priority_queue. 我有问题声明priority_queue。 Details: 细节:

If I directly use these, the edge class will give me an error of "must have an argument of class", I understand that I can't overload two pointers into the bool operator, so this is what I have tried: 如果我直接使用这些,边类会给我一个“必须有一个类的参数”的错误,我明白我不能将两个指针重载到bool运算符中,所以这就是我试过的:

in the Edge.cpp: 在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;
        }
    }
};

^ I am not even sure about putting struct inside the class is correct or not, Plus in this cause I don't know what to put inside my Edge.h file. ^我甚至不确定将struct放在类中是否正确,另外在这个原因我不知道要放在我的Edge.h文件中。

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

As for the Graph class is where the real problem is, I can't even get pass declaring the priority queue without getting an error. 至于Graph类是真正的问题所在,我甚至无法通过声明优先级队列而不会出现错误。

in the Graph.h 在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*&)'
}

second attempt: 第二次尝试:

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

I don't know why for the first error, but the second error I understood it clearly, but I don't know how to fix it, should I put something in front of CompareWeight? 我不知道为什么第一个错误,但第二个错误我清楚地理解它,但我不知道如何解决它,我应该在CompareWeight面前放一些东西? I tried many things, nothing work. 我尝试过很多东西,没什么用。

Any help will be greatly appreciated! 任何帮助将不胜感激! otherwise I would probably just fail this course. 否则我可能会失败这个课程。 First time asking in stackoverflow, if I did anything wrong please tell me. 第一次询问stackoverflow,如果我做错了请告诉我。

Your requirement of implementing bool operator()(Edge*, Edge*) as a regular member of class Edge is possible, but rarely is it done that way. 您需要将bool operator()(Edge*, Edge*)为类Edge的常规成员 ,但很少这样做。

Comparators for standard library algorithms come in the following idiomatic flavors, all of which must provide a strict weak ordering of the contained objects within the sequence being worked over: 标准库算法的比较器具有以下惯用语, 所有这些都必须在正在处理的序列中提供所包含对象的严格弱排序:

  1. Stand-alone functor class 独立的仿函数类
  2. Stand-alone operator < overload 独立operator <过载
  3. Object-class member operator < overload. 对象类成员operator < overload。
  4. Stand-alone function 独立功能
  5. Static class function 静态类函数
  6. Static class functor class 静态类仿函数类
  7. A few others... 其他几个......

The fifth (5) on this list is the closest thing that looks like what they instruction was trying to do, but it is never implemented as operator() . 这个列表中的第五个(5)是最接近它们的指令试图做的事情,但它从未实现为operator() It is possible to do (1) as a member of Edge , but to do so the Edge type must support default construction . 可以作为Edge的成员执行(1),但是为此, Edge类型必须支持默认构造 I'll explain in a minute how this can be done. 我会在一分钟内解释如何做到这一点。 Of the options listed above, the best candidates for performance (likeliness of inlining) and implementation ease are (1) and (6) for this specific case. 在上面列出的选项中,对于这种特定情况,性能(内联的可能性)和实现容易度的最佳候选者是(1)和(6)。 If your queue held actual Edge objects rather than Edge pointers (3) would be a natural fit as well as offer decent performance. 如果你的队列持有实际的Edge 对象而不是Edge 指针 (3)将是一个自然的适合,并提供良好的性能。

The point of a comparator for ordered containers and container adapters like a priority queue is to compare two items that are held within in compliance with a strict weak ordering . 有序容器和容器适配器(如优先级队列)的比较器的要点是比较两个符合严格弱顺序的项目 If you don't know what that is, see this link . 如果您不知道那是什么, 请参阅此链接 In implementation, it comes down to this: if, and only if x < y return true , otherwise return false . 在实现中,它归结为:if, 并且仅当 x < y返回true时 ,否则返回false That means the following must be enforced: 这意味着必须强制执行以下操作:

  • x < x always returns false x < x总是返回false
  • if x < y returns true , then y < x must return false 如果x < y返回true ,则y < x 必须返回false
  • if both x < y and y < x return false, then x is equivalent to y 如果x < yy < x返回false,则x 等于 y

It is a common mistake to accidentally code one's comparator to not abide by these rules. 意外编码一个比较器不遵守这些规则是一个常见的错误。 Guard against that. 防范这一点。

Anyway, I digress. 无论如何,我离题了。 One way of doing this correctly given your class definitions and using (1) from the list above is: 根据您的类定义并使用上面列表中的(1), 正确执行此操作的一种方法是:

Class Edge 班级边缘

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

Class CmpEdgePtrs CmpEdgePtrs类

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

Class Graph 类图

class Graph
{
    // rest of class stuff

private:
    priority_queue<Edge*, vector<Edge*>, CmpEdgePtrs> edges;
};

Honestly, this is screaming for usage of shared smart pointers, but I leave that to you. 老实说,这是使用共享智能指针的尖叫,但我留给你。 The code above stands a very strong chance of inlining the comparator throughout the usage locations within the standard library algorithms that implement the priority queue logic, and as such performance will stand a strong chance of being optimal given your constraints of a container of pointers. 上面的代码非常强大,可以在实现优先级队列逻辑的标准库算法中的整个使用位置内嵌比较器,因此,鉴于指针容器的约束,性能将很有可能达到最优。


Fulfilling Assigned Requirements 履行指定要求

This can be done entirely within class Edge , since it is after all just a class type. 可以完全在类Edge ,因为它毕竟只是一个类类型。 The third type passed as the template parameter for the priority queue adapter is something that exposes bool operator() , and there is nothing stopping you from just making an instance of Edge do that for you. 作为优先级队列适配器的模板参数传递的第三种类型是公开bool operator()东西,并且没有什么能阻止你只是让Edge的实例为你做这件事。 It is odd, but it will none-the-less work with a couple modifications: 这很奇怪,但通过几次修改,它将会毫不逊色:

First, move the bool operator()(const Edge*, const Edge*) const to the Edge class, declared as public. 首先,将bool operator()(const Edge*, const Edge*) constEdge类,声明为public。 Second, provide a default constructor for Edge , since it will be needed by the internal algorithms of the priority queue when creating the functor to perform the comparisons. 其次,为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;
};

This is highly unusual , but has the benefit of allowing the functor direct access to the member variables of Edge objects being compared rather than going through public getters and setters or having to friend a comparator. 这是非常不寻常的 ,但有一个好处是允许函子直接访问被比较的Edge对象的成员变量,而不是通过公共getter和setter或者不得不与比较器交朋友。 It has a downside though. 但它有一个缺点。 There is nothing stopping someone besides the container adapter from constructing Edge objects without specifying source, destination, and weight. 除了容器适配器之外 ,没有什么能阻止构建Edge对象而不指定源,目标和权重。

In short, there is little benefit to doing it like this, and potential problems in improper usage of the code required to make this work, and for that, I would recommend the first option instead. 简而言之,这样做有什么好处,以及不正确使用代码所需的潜在问题,为此,我建议使用第一个选项。

Best of luck 祝你好运

What you're missing is called a forward declaration. 你所缺少的是一种前瞻性声明。 In Edge.h, you are allowed to write just class Vertex; 在Edge.h中,您只能编写class Vertex; on a line by itself. 在一条线上。 After this line, C++ knows that there is such a class, and that Vertex * therefore is a pointer (and not an the first half of a multiplication). 在这一行之后,C ++知道有这样一个类,因此Vertex *是一个指针(而不是乘法的前半部分)。

[edit] This forward declaration replaces #include "Vertex.h" inside Edge.h. [edit]这个前向声明取代了#include "Vertex.h"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM