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.

Réponses:


189

Utiliser std::greatercomme fonction de comparaison:

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

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 .


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.


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

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;

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

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

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;
    }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.