Na takmičenjima se sortiranje skoro nikada ne piše ručno – koristi se funkcija sort iz biblioteke <algorithm>. Ona radi O(n log n), a uz sopstvenu funkciju poređenja sortira po bilo kom kriterijumu: opadajuće, po više kriterijuma, strukture, parove i stringove.
Pre nego što počneš: potrebno predznanje – jednostavni algoritmi sortiranja, vector u C++, strukture. 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.
Osnovna upotreba
Funkcija sort(početak, kraj) sortira rastuće deo od početak do kraj (bez kraj):
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int a[6] = {5, 2, 9, 1, 7, 3};
sort(a, a + 6); // običan niz: od a do a + n
for (int x : a) cout << x << " ";
cout << endl;
vector<int> v = {5, 2, 9, 1, 7, 3};
sort(v.begin(), v.end()); // vektor: od begin() do end()
for (int x : v) cout << x << " ";
cout << endl;
sort(v.begin(), v.end(), greater<int>()); // opadajuće
for (int x : v) cout << x << " ";
cout << endl;
sort(v.begin() + 1, v.begin() + 4); // samo elementi na pozicijama 1, 2 i 3
for (int x : v) cout << x << " ";
cout << endl;
return 0;
}
Opadajući poredak može i bez greater: sortiraj rastuće pa obrni niz sa reverse(v.begin(), v.end()).
Sopstveni kriterijum: funkcija poređenja
Trećim argumentom zadajemo funkciju koja za dva elementa x i y vraća true ako x treba da bude ispredy. Na primer, sortiranje po zbiru cifara, a kod jednakog zbira po veličini broja:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int zbirCifara(int x) {
int s = 0;
while (x > 0) {
s += x % 10;
x /= 10;
}
return s;
}
// true ako x treba da bude ispred y
bool ispred(int x, int y) {
if (zbirCifara(x) != zbirCifara(y)) return zbirCifara(x) < zbirCifara(y);
return x < y; // isti zbir cifara: manji broj ide prvi
}
int main() {
int n;
cin >> n;
vector<int> v(n);
for (int &x : v) cin >> x;
sort(v.begin(), v.end(), ispred);
for (int x : v) cout << x << " ";
cout << endl;
return 0;
}
Važno: funkcija poređenja za jednake elemente mora da vrati false. Ako napišeš <= umesto <, program može da radi pogrešno ili da se sruši.
Umesto posebne funkcije može da se napiše lambda – funkcija napisana na mestu poziva:
sort(v.begin(), v.end(), [](int x, int y) {
return x % 10 < y % 10; // po poslednjoj cifri
});
Sortiranje struktura i parova
Najčešći takmičarski slučaj: rang lista. Takmičare sortiramo po bodovima opadajuće, a one sa istim brojem bodova po imenu abecedno.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
struct Takmicar {
string ime;
int bodovi;
};
bool bolji(const Takmicar &x, const Takmicar &y) {
if (x.bodovi != y.bodovi) return x.bodovi > y.bodovi; // više bodova ide prvo
return x.ime < y.ime; // pa abecedno
}
int main() {
int n;
cin >> n;
vector<Takmicar> t(n);
for (auto &x : t) cin >> x.ime >> x.bodovi;
sort(t.begin(), t.end(), bolji);
for (int i = 0; i < n; i++)
cout << i + 1 << ". " << t[i].ime << " " << t[i].bodovi << endl;
return 0;
}
Parovi (pair) se bez dodatne funkcije porede prvo po first, pa po second. Trik: ako sačuvamo par (-bodovi, ime), običan sort daje istu rang listu. Parovi su zgodni i kada treba zapamtiti originalnu poziciju elementa:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> p(n); // (vrednost, originalna pozicija)
for (int i = 0; i < n; i++) {
cin >> p[i].first;
p[i].second = i + 1;
}
sort(p.begin(), p.end());
// redni brojevi elemenata od najmanjeg do najvećeg
for (auto &x : p) cout << x.second << " ";
cout << endl;
return 0;
}
Stringovi, stable_sort i uklanjanje duplikata
Stringovi se porede leksikografski (kao u rečniku, po ASCII kodovima: velika slova su ispred malih, a "ab" < "abc"), pa sort nad vektorom stringova daje abecedni redosled.
stable_sort radi isto što i sort, ali čuva redosled jednakih elemenata. Kombinacija sort + unique + erase uklanja duplikate:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> v = {4, 1, 4, 2, 1, 4, 3};
sort(v.begin(), v.end()); // 1 1 2 3 4 4 4
v.erase(unique(v.begin(), v.end()), v.end()); // unique pomera različite na početak
for (int x : v) cout << x << " ";
cout << endl;
cout << "Različitih: " << v.size() << endl;
return 0;
}
Funkcija
Šta radi
Složenost
sort(b, e)
sortira rastuće
O(n log n)
sort(b, e, greater<int>())
sortira opadajuće
O(n log n)
stable_sort(b, e, f)
sortira i čuva redosled jednakih
O(n log n)
reverse(b, e)
obrće redosled
O(n)
unique(b, e)
uklanja uzastopne duplikate (pre toga sort)
O(n)
nth_element(b, b + k, e)
na mesto k stavlja element koji bi tu bio u sortiranom nizu
O(n) prosečno
is_sorted(b, e)
proverava da li je sortirano
O(n)
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
Rang lista sa deljenim mestima
Dati su takmičari (ime i bodovi). Ispiši rang listu sortiranu po bodovima opadajuće, a kod istih bodova po imenu. Takmičari sa istim brojem bodova dele isto mesto, a sledeće mesto se preskače (na primer 1, 2, 2, 4).
Primer
Ulaz
5
Marko 80
Ana 95
Jovan 80
Iva 70
Luka 95
Izlaz
1. Ana 95
1. Luka 95
3. Jovan 80
3. Marko 80
5. Iva 70
Uputstvo
Posle sortiranja mesto takmičara na poziciji i je i + 1, osim ako ima isto bodova kao prethodni – tada dobija isto mesto kao on.
Rešenje (C++)
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
struct Takmicar {
string ime;
int bodovi;
};
int main() {
int n;
cin >> n;
vector<Takmicar> t(n);
for (auto &x : t) cin >> x.ime >> x.bodovi;
sort(t.begin(), t.end(), [](const Takmicar &x, const Takmicar &y) {
if (x.bodovi != y.bodovi) return x.bodovi > y.bodovi;
return x.ime < y.ime;
});
int mesto = 1;
for (int i = 0; i < n; i++) {
if (i > 0 && t[i].bodovi != t[i - 1].bodovi) mesto = i + 1;
cout << mesto << ". " << t[i].ime << " " << t[i].bodovi << endl;
}
return 0;
}
ZADATAK 02Težina: Lako
Prvo parni, pa neparni
Sortiraj n prirodnih brojeva tako da prvo budu svi parni brojevi rastuće, a zatim svi neparni opadajuće.
Primer
Ulaz
7
5 8 3 2 9 4 1
Izlaz
2 4 8 9 5 3 1
Uputstvo
U funkciji poređenja: ako je jedan broj paran, a drugi neparan, paran ide prvi. Ako su oba parna – manji ide prvi; ako su oba neparna – veći ide prvi.
Rešenje (C++)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool ispred(int x, int y) {
bool px = (x % 2 == 0), py = (y % 2 == 0);
if (px != py) return px; // paran ide ispred neparnog
if (px) return x < y; // oba parna: rastuće
return x > y; // oba neparna: opadajuće
}
int main() {
int n;
cin >> n;
vector<int> v(n);
for (int &x : v) cin >> x;
sort(v.begin(), v.end(), ispred);
for (int x : v) cout << x << " ";
cout << endl;
return 0;
}
ZADATAK 03Težina: Teže
Spajanje intervala
Dato je n intervala [a, b] (1 ≤ n ≤ 105). Intervali koji se preklapaju ili dodiruju spajaju se u jedan. Ispiši dobijene intervale sleva nadesno.
Primer 1
Ulaz
4
1 3
8 10
2 6
15 18
Izlaz
1 6
8 10
15 18
Primer 2
Ulaz
2
1 4
4 5
Izlaz
1 5
Uputstvo
Sortiraj intervale po početku (parovi se sortiraju po first). Zatim prolazi redom: ako tekući interval počinje pre kraja poslednjeg spojenog (a <= kraj), produži kraj na max(kraj, b); inače započni novi interval.
Rešenje (C++)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> v(n);
for (auto &p : v) cin >> p.first >> p.second;
sort(v.begin(), v.end()); // po početku intervala
vector<pair<int, int>> rez;
for (auto &p : v) {
if (!rez.empty() && p.first <= rez.back().second)
rez.back().second = max(rez.back().second, p.second); // preklapa se: produži
else
rez.push_back(p); // novi interval
}
for (auto &p : rez) cout << p.first << " " << p.second << endl;
return 0;
}
Česte greške i saveti
Za vektor se piše sort(v.begin(), v.end()), a za niz sort(a, a + n) – ne a + n - 1.
Funkcija poređenja koristi strogo < ili >, nikada <=.
Strukture prosleđuj funkciji poređenja po referenci (const Takmicar &) – inače se pri svakom poređenju kopiraju.
unique uklanja samo uzastopne duplikate – niz prvo mora da se sortira.
Proveri znanje
Otvori kviz
Funkcija sort u C++
1. Kako se sortira ceo vektor v rastuće?
2. Šta vraća funkcija poređenja ispred(x, y)?
3. Kako se porede dva para (a, b) i (c, d)?
4. Šta treba uraditi pre unique da bi se uklonili svi duplikati?
Podešavanja kolačića
Koristimo kolačiće da bismo vam pružili najbolje moguće iskustvo. Takođe nam omogućavaju da analiziramo ponašanje korisnika kako bismo stalno poboljšavali veb lokaciju za vas.