declarando un priority_queue en c ++ con un comparador personalizado

84

Estoy tratando de declarar a priority_queue of nodes, usando bool Compare(Node a, Node b)como función de comparación (que está fuera de la clase de nodo).

Lo que tengo actualmente es:

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

Por alguna razón, estoy recibiendo Error: "Compare" is not a type name

Cambiar la declaración a priority_queue <Node, vector<Node>, bool Compare>

me da Error: expected a '>'

También he probado:

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

¿Cómo debo declarar correctamente mi priority_queue?

Steven Morad
fuente

Respuestas:

110

Deberías declarar una clase Comparey sobrecargarla operator()de esta manera:

class Foo
{

};

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

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

O, si por alguna razón no puedes hacerlo como clase, puedes usarlo 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;
}
asombroso
fuente
1
Perfecto, justo lo que buscaba. Nunca pensé en hacer una clase separada. ¿El primer ejemplo se consideraría mejor estilo?
Steven Morad
2
@StevenMorad, prefiero usar la clase con sobrecargado operator(), parece más simple.
Awesoon
1
@soon ¿Por qué sobrecargamos el operador ()? ¿Está esto relacionado con cómo se implementan las colas de prioridad internamente? sobrecarga> o <tiene sentido intuitivamente, pero el operador () no tanto
Piyush
2
@Piyush, la pregunta es sobre pasar un comparador personalizado al pritority_queue. Es posible sobrecargar operator<y usar el std::lesscomparador incorporado , sin embargo, el bool Compare(Node a, Node b)declarado fuera de la clase Node, según la pregunta.
Awesoon
1
Sigo volviendo a esta respuesta, probablemente como 50 veces ahora, nunca puedo recordar la sintaxis
Rockstar5645
48

La respuesta aceptada te hace creer que debes usar una clase o un std::functioncomparador. ¡Esto no es verdad! Como muestra la respuesta de cute_ptr , puede pasar un puntero de función al constructor. Sin embargo, la sintaxis para hacerlo es mucho más simple de lo que se muestra allí:

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

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

Es decir, no es necesario codificar explícitamente el tipo de función, puede dejar que el compilador lo haga por usted usando decltype.

Esto es muy útil si el comparador es un lambda. No puede especificar el tipo de lambda de otra forma que no sea usando decltype. Por ejemplo:

auto compare = [](Node a, Node b) { return a.foo < b.foo; }
std::priority_queue<Node, std::vector<Node>, decltype(compare)> openSet(compare);
Cris Luengo
fuente
1
Esto es fantástico, me pregunto si hay trampas (problemas) potenciales aquí. Me encantaría ver que esta respuesta tenga más visibilidad y discusión.
Apollys apoya a Monica el
1
@Apollys: uso este método con regularidad (generalmente Comparees una lambda, para la cual es imposible escribir una declaración), no conozco ninguna trampa.
Cris Luengo
Si tuviera que hacer esto para una función lambda, ¿dónde colocaría el cuerpo de la función lambda? ¿Lo almacenaría en una variable de fantemano y luego lo reemplazaría Comparecon f?
Eric Auld
@EricAuld: Sí, Comparepuede haber una función lambda allí, como en auto Compare = [](){};. Pero necesitas usar decltype(Compare), en lugar de decltype(&Compare).
Cris Luengo
Hola Chris, esto es genial, estaba buscando algún formato para usar con decltype para priority_queue y sin declarar una clase, ¡diste la respuesta perfecta! ¡Gracias!
Amanda Wang
16

El tercer parámetro de plantilla debe ser una clase que se haya operator()(Node,Node)sobrecargado. Entonces tendrás que crear una clase de esta manera:

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

Y luego usará esta clase como el tercer parámetro de plantilla como este:

priority_queue<Node, vector<Node>, ComparisonClass> q;
Micrófono
fuente
13
El método del operador debe ser público.
knezi
La tercera plantilla no necesita ser una clase. Puede ser el tipo de función.
Cris Luengo
Según cpluplus : esto puede ser un puntero de función o un objeto de función
Benav
9

Respondiendo su pregunta directamente:

Estoy tratando de declarar una priority_queuede nodos, usandobool Compare(Node a, Node b) as the comparator function

Lo que tengo actualmente es:

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

Por alguna razón, recibo un error:

"Compare" is not a type name

El compilador le dice exactamente qué está mal: Compareno es un nombre de tipo, sino una instancia de una función que toma dos Nodesy devuelve un bool.
Lo que necesita es especificar el tipo de puntero de función:
std::priority_queue<Node, std::vector<Node>, bool (*)(Node, Node)> openSet(Compare)

cute_ptr
fuente
Esto es exactamente lo que estoy buscando para dar una función en la declaración priority_queue, ¡gracias!
Amanda Wang
4

También se puede utilizar una función lambda.

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

En caso de que esto ayude a alguien:

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

Primero tienes que definir la comparación. Hay 3 formas de hacerlo:

  1. clase de uso
  2. use struct (que es lo mismo que class)
  3. utilizar la función lambda.

Es fácil de usar class / struct porque es fácil de declarar, simplemente escriba esta línea de código sobre su código de ejecución

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

Código de llamada:

priority_queue<Node,vector<Node>,compare> pq;
Shivam Kumar Mishra
fuente
0

prefiero estructura, y es lo que std :: mayor hace

struct Compare {
  bool operator()(Node const&, Node &) {}
}
Canhua Li
fuente