Red sa prioritetom (priority_queue) u C++

Lekcija 8 od 11 · Strukture podataka

Red sa prioritetom uvek daje element sa najvećim (ili najmanjim) prioritetom, a dodavanje i uzimanje traju samo O(log n). Koristi se u Dijkstrinom algoritmu, za izbor „sledećeg najboljeg“ i u mnogim pohlepnim algoritmima.

Pre nego što počneš: potrebno predznanje – Red (queue), Stek.
Kako da učiš: svaki primer prekucaj i pokreni, a zadatke na kraju prvo reši sam/a; uputstvo i rešenje otvori tek posle toga. Svi programi su u C++-u.

Osnovne operacije

OperacijaZnačenjeSloženost
pq.push(x)dodaje elementO(log n)
pq.top()vraća element sa najvećim prioritetom (ne uklanja ga)O(1)
pq.pop()uklanja taj elementO(log n)
pq.size(), pq.empty()broj elemenata, da li je prazanO(1)

Unutra je hip (heap) – drvo u kome je svaki roditelj veći od svoje dece, pa je najveći element uvek u korenu. Zaglavlje je <queue>.

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

int main() {
    priority_queue<int> maks;                               // podrazumevano: najveći na vrhu
    priority_queue<int, vector<int>, greater<int>> mini;    // najmanji na vrhu
    for (int x : {5, 1, 8, 3}) {
        maks.push(x);
        mini.push(x);
    }
    while (!maks.empty()) { cout << maks.top() << " "; maks.pop(); }
    cout << "\n";
    while (!mini.empty()) { cout << mini.top() << " "; mini.pop(); }
    cout << "\n";
    return 0;
}

Parovi i sopstveni prioritet

Ako su u redu parovi pair<int,int>, porede se prvo po prvom, pa po drugom elementu. Uobičajen trik: u prvi element stavi prioritet, a u drugi podatak (npr. čvor grafa). Za min-hip parova piše se priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<>> – baš tako izgleda red u Dijkstrinom algoritmu.

Za složeniji kriterijum piše se struktura sa operatorom poređenja; pazi da je logika „obrnuta“: element za koji poređenje vraća true ide niže.

Tipične primene

  • k najvećih elemenata toka podataka – min-hip veličine k;
  • spajanje uvek dva najmanja elementa (užad, Hafmanovo kodiranje);
  • raspored poslova – uvek uzmi posao sa najvećim prioritetom ili najranijim rokom;
  • najkraći putevi – Dijkstra, Prim (Primov algoritam).

Zadaci za vežbu

Za svaki zadatak postoji primer, uputstvo i rešenje. Rešenja su provereno tačna na primerima iz teksta.

ZADATAK 01Težina: Srednje teško

k najvećih brojeva

Učitava se n brojeva (n ≤ 106) i broj k. Ispiši k najvećih, od najvećeg ka manjem, koristeći memoriju samo za k brojeva.

Primer

Ulaz

7 3
5 1 9 3 7 9 2

Izlaz

9 9 7
ZADATAK 02Težina: Srednje teško

Spajanje užadi

Imamo n komada užeta datih dužina. Spajanje dva komada dužina a i b košta a + b i daje komad dužine a + b. Koliko najmanje košta spajanje svih komada u jedan?

Primer

Ulaz

4
4 3 2 6

Izlaz

29
ZADATAK 03Težina: Teže

Poslovi sa prioritetom

Poslovi stižu tokom vremena: posao i stiže u trenutku t[i], traje d[i] i ima prioritet p[i]. Procesor radi jedan po jedan posao do kraja; kad je slobodan, od pristiglih bira onaj sa najvećim prioritetom (za isti prioritet – onaj koji je ranije stigao). Ispiši redosled izvršavanja (redni brojevi od 1).

Primer

Ulaz

4
0 3 1
1 2 5
2 1 3
3 2 5

Izlaz

1 2 4 3
Česte greške i saveti
  • Podrazumevani priority_queue je max-hip; za najmanji element na vrhu dodaj vector<T>, greater<T>.
  • top() na praznom redu je greška – uvek prvo proveri empty().
  • U redu ne može da se menja prioritet postojećeg elementa; umesto toga ubaci novi par, a zastareli preskoči kad izađe (tako radi Dijkstra).
  • Ako ti treba i najmanji i najveći, ili brisanje proizvoljnog elementa, koristi multiset.

Proveri znanje

Otvori kviz

Mini kviz: red sa prioritetom

1. Koji element vraća top() kod priority_queue<int>?




2. Kolika je složenost operacije push?




3. Koji red treba za Dijkstrin algoritam?