объявление priority_queue в c ++ с помощью настраиваемого компаратора


88

Я пытаюсь объявить a priority_queue of nodes, используя bool 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?

Ответы:


113

Вы должны объявить класс Compareи перегрузить operator()его следующим образом:

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_queues? перегрузка> или <имеет смысл интуитивно, но оператор () не так
важен

2
@Piyush, речь идет о передаче кастомного компаратора в pritority_queue. Возможна перегрузка operator<и использование встроенного std::lessкомпаратора, однако, bool Compare(Node a, Node b)заявленного вне класса Node, согласно вопросу.
awesoon

3
Я продолжаю возвращаться к этому ответу, наверное, раз 50, я никогда не могу вспомнить синтаксис
Rockstar5645

52

Принятый ответ заставляет вас поверить, что вы должны использовать класс или a в std::functionкачестве компаратора. Это неправда! Как показывает ответ cute_ptr , вы можете передать конструктору указатель на функцию. Однако синтаксис для этого намного проще, чем показано здесь:

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

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

То есть нет необходимости явно кодировать тип функции, вы можете позволить компилятору сделать это за вас decltype.

Это очень полезно, если компаратором является лямбда. Вы не можете указать тип лямбда иначе, чем с помощью decltype. Например:

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

2
Это фантастика, интересно, есть ли здесь какие-то потенциальные ловушки (проблемы). Хотелось бы, чтобы этот ответ получил больше внимания и обсуждения.
Apollys поддерживает Монику

1
@Apollys: я использую этот метод регулярно (обычно Compareэто лямбда, для которой невозможно написать объявление), я не знаю ни одной ловушки.
Крис Луенго

Если бы вы сделали это для лямбда-функции, куда бы вы поместили тело лямбда-функции? Вы бы сохранили его fзаранее в переменной, а затем заменили бы Compareна f?
Эрик Олд

@EricAuld: Да, там Compareможет быть лямбда-функция, например auto Compare = [](){};. Но нужно использовать decltype(Compare), а не decltype(&Compare).
Cris Luengo

Привет, Крис, это здорово, я искал какой-то формат для использования с decltype для priority_queue, и, не объявляя класс, вы дали идеальный ответ! Благодаря!
Аманда Ван

17

Третий параметр шаблона должен быть operator()(Node,Node)перегруженным классом . Итак, вам нужно будет создать класс следующим образом:

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

Затем вы будете использовать этот класс в качестве третьего параметра шаблона, например:

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

14
Метод оператора должен быть открытым.
Knezi 06

1
Третий шаблон не обязательно должен быть классом. Это может быть тип функции.
Крис Луенго

1
Согласно cpluplus : это может быть указатель на функцию или объект функции
Бенав,

10

Отвечая на ваш вопрос напрямую:

Я пытаюсь объявить несколько 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и возвращает bool.
Вам нужно указать тип указателя функции:
std::priority_queue<Node, std::vector<Node>, bool (*)(Node, Node)> openSet(Compare)


Это именно то, что я ищу, чтобы указать функцию в объявлении priority_queue, спасибо!
Аманда Ван

6

Также можно использовать лямбда-функцию.

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

6

Сначала вы должны определить сравнение. Для этого есть 3 способа:

  1. использовать класс
  2. использовать структуру (то же, что и класс)
  3. использовать лямбда-функцию.

Класс / структуру легко использовать, потому что легко объявить, просто напишите эту строку кода над исполняемым кодом

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;

В точку @shivam Mishra.
fight_club

3

Если это кому-то поможет:

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

0

предпочитают структуру, и это то, что делает std :: больше

struct Compare {
  bool operator()(Node const&, Node &) {}
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.