在C ++中使用自定义比较器声明priority_queue


83

我试图声明一个priority_queue of nodesbool Compare(Node a, Node b)用作比较器函数(在节点类外部)。

我目前拥有的是:

priority_queue<Node, vector<Node>, Compare> openSet;

由于某种原因,我越来越 Error: "Compare" is not a type name

将声明更改为 priority_queue <Node, vector<Node>, bool Compare>

给我 Error: expected a '>'

我也尝试过:

priority_queue<Node, vector<Node>, Compare()> openSet;
priority_queue<Node, vector<Node>, bool Compare()> openSet;
priority_queue<Node, vector<Node>, Compare<Node, Node>> openSet; 

我应该如何正确声明我的身份priority_queue

Answers:


110

您应该声明一个类Compareoperator()为其重载,如下所示:

class Foo
{

};

class Compare
{
public:
    bool operator() (Foo, Foo)
    {
        return true;
    }
};

int main()
{
    std::priority_queue<Foo, std::vector<Foo>, Compare> pq;
    return 0;
}

或者,如果由于某种原因而无法将其设置为类,则可以使用std::function它:

class Foo
{

};

bool Compare(Foo, Foo)
{
    return true;
}

int main()
{
    std::priority_queue<Foo, std::vector<Foo>, std::function<bool(Foo, Foo)>> pq(Compare);
    return 0;
}

1
完美,正是我想要的。我从没想过要单独上课。是否将第一个示例视为更好的样式?
史蒂文·莫拉德

2
@StevenMorad,我更喜欢使用带有重载的类operator(),它看起来更简单。
awesoon

1
@soon为什么我们要重载运算符()?这与内部如何实现priority_queue相关联吗?重载>或<在直觉上有意义,但是()运算符没有那么多
Piyush

2
@Piyush,问题是关于将自定义比较器传递给pritority_queue。根据问题,可以重载operator<和使用内置的std::less比较器,但是可以bool Compare(Node a, Node b)在类外部声明Node
awesoon

1
我一直回到这个答案,大概是现在50次,我永远也记不清语法了
Rockstar5645

48

接受的答案使您相信必须使用类或std::functionas作为比较器。这不是真的!正如cute_ptr的答案所示,您可以将函数指针传递给构造函数。但是,这样做的语法比那里显示的要简单得多:

class Node;
bool Compare(Node a, Node b);

std::priority_queue<Node, std::vector<Node>, decltype(&Compare)> openSet(Compare);

也就是说,不需要显式编码函数的类型,可以让编译器使用来完成该操作decltype

如果比较器是lambda,这将非常有用。除了使用,您不能通过其他任何方式指定Lambda的类型decltype。例如:

auto compare = [](Node a, Node b) { return a.foo < b.foo; }
std::priority_queue<Node, std::vector<Node>, decltype(compare)> openSet(compare);

1
这太棒了,我想知道这里是否有任何潜在的陷阱(问题)。希望看到这个答案得到更多的关注和讨论。
Apollys支持Monica

1
@Apollys:我定期使用此方法(通常Compare是lambda,无法为其编写声明),我不知道任何陷阱。
克里斯·伦戈

如果要对lambda函数执行此操作,则将lambda函数的主体放在哪里?您是否可以f事先将其存储在变量中,然后替换Comparef
Eric Auld

@EricAuld:是的,Compare可以在其中作为lambda函数,如中所示auto Compare = [](){};。但是您需要使用decltype(Compare),而不是decltype(&Compare)
克里斯·伦戈

克里斯,您好,我很好,我在寻找某种要与decltype一起用于priority_queue的格式,而没有声明一个类,您给出了完美的答案!谢谢!
Amanda Wang

16

第三个模板参数必须是已operator()(Node,Node)重载的类。因此,您将必须以这种方式创建一个类:

class ComparisonClass {
    bool operator() (Node, Node) {
        //comparison code here
    }
};

然后,您将使用此类作为第三个模板参数,如下所示:

priority_queue<Node, vector<Node>, ComparisonClass> q;

13
操作员方法必须是公共的。
knezi'3

第三个模板不必是类。它可以是函数的类型。
Cris Luengo '18

根据cpluplus的说法这可能是函数指针或函数对象
Benav

9

直接回答您的问题:

我正在尝试声明一个 priority_queue节点bool Compare(Node a, Node b) as the comparator function

我目前拥有的是:

priority_queue<Node, vector<Node>, Compare> openSet;

由于某种原因,我收到错误消息:

"Compare" is not a type name

编译器正在告诉您确切的问题:Compare不是类型名称,而是一个函数实例,该实例需要两个Nodes并返回a bool
您需要指定函数指针类型:
std::priority_queue<Node, std::vector<Node>, bool (*)(Node, Node)> openSet(Compare)


这正是我要在priority_queue声明中提供功能的内容,谢谢!
Amanda Wang

4

也可以使用lambda函数。

auto Compare = [](Node &a, Node &b) { //compare };
std::priority_queue<Node, std::vector<Node>, decltype(Compare)> openset(Compare);

2

如果这可以帮助任何人:

static bool myFunction(Node& p1, Node& p2) {}
priority_queue <Node, vector<Node>, function<bool(Node&, Node&)>> pq1(myFunction);

2

您必须先定义比较。有3种方法可以做到这一点:

  1. 使用类
  2. 使用结构(与类相同)
  3. 使用lambda函数。

使用类/结构很容易,因为只需在执行代码上方编写此行代码即可轻松声明

struct compare{
  public:
  bool operator()(Node& a,Node& b) // overloading both operators 
  {
      return a.w < b.w: // if you want increasing order;(i.e increasing for minPQ)
      return a.w > b.w // if you want reverse of default order;(i.e decreasing for minPQ)
   }
};

调用代码:

priority_queue<Node,vector<Node>,compare> pq;

0

更喜欢struct,这就是std :: greater所做的

struct Compare {
  bool operator()(Node const&, Node &) {}
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.