Comment puis-je créer Min stl priority_queue?

110

La file d'attente de priorité stl par défaut est Max one (la fonction Top renvoie le plus grand élément).

Disons, pour simplifier, qu'il s'agit d'une file d'attente prioritaire de valeurs int.

amitlicht
la source

Réponses:

189

Utiliser std::greatercomme fonction de comparaison:

std::priority_queue<int, std::vector<int>, std::greater<int> > my_min_heap;
James McNellis
la source
4
@eriks Vous avez quelques options. Soit votre classe définit operator>, ce qui fonctionnerait à merveille avec std::greater. Vous pouvez également écrire votre propre foncteur au lieu de std::greatersi vous le souhaitez.
AraK
2
@AraK, je pense que vous voulez dire operator<;)
Peter Alexander
15
Il convient de noter que pour utiliser std :: Greater <int>, vous devez #include <functional>
reggaeguitar
3
@CarryonSmiling dans la bibliothèque de modèles standard, les classes vectoret dequeremplissent les conditions qu'un conteneur sous-jacent doit remplir pour une priority_queue. Vous pouvez également utiliser une classe de conteneur personnalisée. Vous pouvez trouver une explication beaucoup plus élaborée sur cplusplus.com/reference/queue/priority_queue
Tanmay Garg
3
Quelqu'un peut-il expliquer pourquoi le tas min utilise un plus grand <int> pas moins <int>?
Telenoobies
45

Une façon serait de définir un comparateur approprié avec lequel opérer sur la file d'attente de priorité ordinaire, de sorte que sa priorité soit inversée:

 #include <iostream>  
 #include <queue>  
 using namespace std;  

 struct compare  
 {  
   bool operator()(const int& l, const int& r)  
   {  
       return l > r;  
   }  
 };  

 int main()  
 {  
     priority_queue<int,vector<int>, compare > pq;  

     pq.push(3);  
     pq.push(5);  
     pq.push(1);  
     pq.push(8);  
     while ( !pq.empty() )  
     {  
         cout << pq.top() << endl;  
         pq.pop();  
     }  
     cin.get();  
 }

Ce qui produirait respectivement 1, 3, 5, 8.

Quelques exemples d'utilisation de files d'attente prioritaires via les implémentations de STL et de Sedgewick sont donnés ici .

AndyUK
la source
1
Pouvez-vous expliquer pourquoi nous utilisons l> r et non l <r, pour implémenter une file d'attente à priorité minimale?
Dhruv Mullick
3
Le comparateur par défaut pour la file d'attente prioritaire est l <r. Vous pouvez le voir dans le paramètre par défaut du constructeur . En faisant l> r ou r <l vous obtiendrez le contraire.
Diaa
1
@AndyUK Bonjour, ¿pourquoi vous utilisez une structure pour implémenter l'opérateur de comparaison? merci d'avance
AER
La file d'attente de priorité par défaut en C ++ est une file d'attente de priorité maximale.
QWR
30

Le troisième paramètre de modèle pour priority_queueest le comparateur. Réglez-le pour l'utiliser greater.

par exemple

std::priority_queue<int, std::vector<int>, std::greater<int> > max_queue;

Vous aurez besoin #include <functional>de std::greater.

Peter Alexander
la source
@Potatoswatter: ce n'est pas toujours le cas.
Moha le chameau tout-puissant
11
C'est mieux que la réponse acceptée car elle mentionne également #include <functional>
reggaeguitar
22

Vous pouvez le faire de plusieurs manières:
1. En utilisant greatercomme fonction de comparaison:

 #include <bits/stdc++.h>

using namespace std;

int main()
{
    priority_queue<int,vector<int>,greater<int> >pq;
    pq.push(1);
    pq.push(2);
    pq.push(3);

    while(!pq.empty())
    {
        int r = pq.top();
        pq.pop();
        cout<<r<< " ";
    }
    return 0;
}

2. Insérer des valeurs en modifiant leur signe (en utilisant moins (-) pour un nombre positif et en utilisant plus (+) pour un nombre négatif:

int main()
{
    priority_queue<int>pq2;
    pq2.push(-1); //for +1
    pq2.push(-2); //for +2
    pq2.push(-3); //for +3
    pq2.push(4);  //for -4

    while(!pq2.empty())
    {
        int r = pq2.top();
        pq2.pop();
        cout<<-r<<" ";
    }

    return 0;
}

3. Utilisation d'une structure ou d'une classe personnalisée:

struct compare
{
    bool operator()(const int & a, const int & b)
    {
        return a>b;
    }
};

int main()
{

    priority_queue<int,vector<int>,compare> pq;
    pq.push(1);
    pq.push(2);
    pq.push(3);

    while(!pq.empty())
    {
        int r = pq.top();
        pq.pop();
        cout<<r<<" ";
    }

    return 0;
}

4. En utilisant une structure ou une classe personnalisée, vous pouvez utiliser priority_queue dans n'importe quel ordre. Supposons que nous voulions trier les personnes par ordre décroissant en fonction de leur salaire et si égalité, en fonction de leur âge.

    struct people
    {
        int age,salary;

    };
    struct compare{
    bool operator()(const people & a, const people & b)
        {
            if(a.salary==b.salary)
            {
                return a.age>b.age;
            }
            else
            {
                return a.salary>b.salary;
            }

    }
    };
    int main()
    {

        priority_queue<people,vector<people>,compare> pq;
        people person1,person2,person3;
        person1.salary=100;
        person1.age = 50;
        person2.salary=80;
        person2.age = 40;
        person3.salary = 100;
        person3.age=40;


        pq.push(person1);
        pq.push(person2);
        pq.push(person3);

        while(!pq.empty())
        {
            people r = pq.top();
            pq.pop();
            cout<<r.salary<<" "<<r.age<<endl;
    }
  1. Le même résultat peut être obtenu par surcharge de l'opérateur:

    struct people
    {
    int age,salary;
    
    bool operator< (const people & p)const
    {
        if(salary==p.salary)
        {
            return age>p.age;
        }
        else
        {
            return salary>p.salary;
        }
    }};

    En fonction principale:

    priority_queue<people> pq;
    people person1,person2,person3;
    person1.salary=100;
    person1.age = 50;
    person2.salary=80;
    person2.age = 40;
    person3.salary = 100;
    person3.age=40;
    
    
    pq.push(person1);
    pq.push(person2);
    pq.push(person3);
    
    while(!pq.empty())
    {
        people r = pq.top();
        pq.pop();
        cout<<r.salary<<" "<<r.age<<endl;
    }
Islam Taohidul
la source
Ne voulez-vous pas dire bool operator > (const people & p)const dans 5) surcharge de l'opérateur
Rockstar5645
1
En fait, votre droite, 5) fonctionne, c'est juste bizarre, je n'ai jamais vu <surchargé comme ça, il vaut mieux surcharger >et utilisergreater<people>
Rockstar5645
19

En C ++ 11, vous pouvez également créer un alias pour plus de commodité:

template<class T> using min_heap = priority_queue<T, std::vector<T>, std::greater<T>>;

Et utilisez-le comme ceci:

min_heap<int> my_heap;
mécatron
la source
8

Une façon de résoudre ce problème est de pousser le négatif de chaque élément dans priority_queue afin que le plus grand élément devienne le plus petit élément. Au moment de faire l'opération pop, prenez la négation de chaque élément.

#include<bits/stdc++.h>
using namespace std;

int main(){
    priority_queue<int> pq;
    int i;

// push the negative of each element in priority_queue, so the largest number will become the smallest number

    for (int i = 0; i < 5; i++)
    {
        cin>>j;
        pq.push(j*-1);
    }

    for (int i = 0; i < 5; i++)
    {
        cout<<(-1)*pq.top()<<endl;
        pq.pop();
    }
}
PAVAN BANSAL
la source
3

Sur la base de toutes les réponses, j'ai créé un exemple de code pour savoir comment créer une file d'attente prioritaire. Remarque: cela fonctionne avec les compilateurs C ++ 11 et supérieurs

#include <iostream>
#include <vector>
#include <iomanip>
#include <queue>

using namespace std;

// template for prirority Q
template<class T> using min_heap = priority_queue<T, std::vector<T>, std::greater<T>>;
template<class T> using max_heap = priority_queue<T, std::vector<T>>;

const int RANGE = 1000;

vector<int> get_sample_data(int size);

int main(){
  int n;
  cout << "Enter number of elements N = " ; cin >> n;
  vector<int> dataset = get_sample_data(n);

  max_heap<int> max_pq;
  min_heap<int> min_pq;

  // Push data to Priority Queue
  for(int i: dataset){
    max_pq.push(i);
    min_pq.push(i);
  }

  while(!max_pq.empty() && !min_pq.empty()){
    cout << setw(10) << min_pq.top()<< " | " << max_pq.top() << endl;
    min_pq.pop();
    max_pq.pop();
  }

}


vector<int> get_sample_data(int size){
  srand(time(NULL));
  vector<int> dataset;
  for(int i=0; i<size; i++){
    dataset.push_back(rand()%RANGE);
  }
  return dataset;
}

Sortie du code ci-dessus

Enter number of elements N = 4

        33 | 535
        49 | 411
       411 | 49
       535 | 33
Ajayramesh
la source
1

Nous pouvons le faire de plusieurs manières.

Utilisation du paramètre de comparateur de modèle

    int main() 
    {
      priority_queue<int, vector<int>, greater<int> > pq;

      pq.push(40);
      pq.push(320);
      pq.push(42);
      pq.push(65);
      pq.push(12);

      cout<<pq.top()<<endl;
      return 0;
    }

Utilisation de la classe de compartiment définie utilisée

     struct comp
     {
        bool operator () (int lhs, int rhs)
        {
           return lhs > rhs;
        }
     };

    int main()
    {
       priority_queue<int, vector<int>, comp> pq;

       pq.push(40);
       pq.push(320);
       pq.push(42);
       pq.push(65);
       pq.push(12);

       cout<<pq.top()<<endl;

       return 0;
    }
éruptions cutanées
la source