оголошення prioritet_черепи в 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?

Відповіді:


114

Ви повинні оголосити клас 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

2
@soon Чому ми перевантажуємо оператор ()? Чи пов’язано це з тим, як prior_queue впроваджуються внутрішньо? перевантаження> або <має сенс інтуїтивно, але () оператор не стільки
Піюш

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

3
Я постійно повертаюся до цієї відповіді, мабуть, як і 50 разів, я ніколи не пам’ятаю синтаксис
Rockstar5645

52

Прийнята відповідь змушує вас повірити, що ви повинні використовувати клас або 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це лямбда, для якого неможливо написати декларацію), я не знаю жодної пастки.
Cris Luengo,

Якби ви робили це для лямбда-функції, куди б ви помістили тіло функції лямбда? Чи могли б ви fзаздалегідь зберегти його у змінній, а потім замінити Compareна f?
Ерік Олд

@EricAuld: Так, там Compareможе бути лямбда-функція, як у auto Compare = [](){};. Але вам потрібно використовувати decltype(Compare), а не decltype(&Compare).
Кріс Луенго,

Привіт, Кріс, це чудово, я шукав якийсь формат для використання з 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.03.17

1
Третій шаблон не повинен бути класом. Це може бути тип функції.
Cris Luengo,

1
Відповідно до cpluplus : Це може бути вказівник на функцію або об’єкт функції
Бенав

10

Відповідаючи безпосередньо на ваше запитання:

Я намагаюся оголосити a 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, дякую!
Аманда Ванг


6

Спочатку потрібно визначити порівняння. Є 3 способи зробити це:

  1. використовувати клас
  2. використовувати struct (що таке саме, як клас)
  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

віддайте перевагу struct, і це те, що std :: larger робить

struct Compare {
  bool operator()(Node const&, Node &) {}
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.