U binarnom stablu svaki čvor ima najviše dva deteta – levo i desno. Na takvom stablu su definisana tri klasična obilaska, a binarno stablo pretrage (BST) čuva brojeve tako da se traženje radi kao binarna pretraga.
Pre nego što počneš: potrebno predznanje – stabla, rekurzija. 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.
Zapisivanje binarnog stabla
1
/ \
2 3
/ \ \
4 5 6
Najjednostavnije je čuvati dva niza: L[v] (levo dete) i R[v] (desno dete), sa 0 kada deteta nema. Za stablo sa slike: L[1]=2, R[1]=3, L[2]=4, R[2]=5, L[3]=0, R[3]=6, a čvorovi 4, 5 i 6 nemaju decu.
Tri obilaska: preorder, inorder, postorder
Obilasci se razlikuju samo po tome kada se ispisuje čvor u odnosu na podstabla:
Obilazak
Redosled
Za stablo sa slike
preorder (pre)
čvor, levo, desno
1 2 4 5 3 6
inorder (između)
levo, čvor, desno
4 2 5 1 3 6
postorder (posle)
levo, desno, čvor
4 5 2 6 3 1
#include <iostream>
using namespace std;
int L[1001], R[1001];
void preorder(int v) {
if (v == 0) return; // nema čvora
cout << v << " ";
preorder(L[v]);
preorder(R[v]);
}
void inorder(int v) {
if (v == 0) return;
inorder(L[v]);
cout << v << " ";
inorder(R[v]);
}
void postorder(int v) {
if (v == 0) return;
postorder(L[v]);
postorder(R[v]);
cout << v << " ";
}
int main() {
int n;
cin >> n; // čvorovi 1..n, koren je 1
for (int v = 1; v <= n; v++) cin >> L[v] >> R[v];
preorder(1); cout << endl;
inorder(1); cout << endl;
postorder(1); cout << endl;
return 0;
}
Postorder se koristi kada rezultat čvora zavisi od dece (visina, veličina podstabla), a preorder kada se informacija prenosi od korena ka listovima (dubina).
Visina binarnog stabla
Visina praznog stabla je −1, a inače 1 + veća od visina levog i desnog podstabla:
int visina(int v) {
if (v == 0) return -1; // prazno stablo
return 1 + max(visina(L[v]), visina(R[v]));
}
Binarno stablo pretrage (BST)
U BST-u za svaki čvor važi: sve vrednosti u levom podstablu su manje, a u desnom veće od vrednosti čvora. Traženje počinje od korena: ako je traženi broj manji, idemo levo, ako je veći – desno. Ubacivanje ide istim putem dok se ne dođe do praznog mesta.
#include <iostream>
using namespace std;
const int MAXN = 100001;
int vr[MAXN], L[MAXN], R[MAXN]; // čvorovi se prave redom 1, 2, 3, ...
int brojCvorova = 0;
int ubaci(int v, int x) { // ubacuje x u podstablo čvora v, vraća (novi) koren podstabla
if (v == 0) { // prazno mesto: novi čvor
brojCvorova++;
vr[brojCvorova] = x;
return brojCvorova;
}
if (x < vr[v]) L[v] = ubaci(L[v], x);
else if (x > vr[v]) R[v] = ubaci(R[v], x);
return v; // jednaki se ne ubacuju ponovo
}
bool nadji(int v, int x) {
while (v != 0) {
if (x == vr[v]) return true;
v = (x < vr[v]) ? L[v] : R[v];
}
return false;
}
void inorder(int v) {
if (v == 0) return;
inorder(L[v]);
cout << vr[v] << " ";
inorder(R[v]);
}
int main() {
int n, koren = 0;
cin >> n;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
koren = ubaci(koren, x);
}
inorder(koren); // ispisuje brojeve sortirano!
cout << endl;
cout << (nadji(koren, 6) ? "6 postoji" : "6 ne postoji") << endl;
cout << (nadji(koren, 7) ? "7 postoji" : "7 ne postoji") << endl;
return 0;
}
Inorder obilazak BST-a daje vrednosti sortirano – to je ujedno i način da se proveri da li je stablo ispravan BST.
Složenost i balansirana stabla
Traženje i ubacivanje rade onoliko koraka kolika je visina stabla. Ako su brojevi ubacivani u slučajnom redosledu, visina je oko log₂ n. Ali ako se ubacuju već sortirani (1, 2, 3, …), stablo postaje lanac visine n i sve operacije su O(n).
Balansirana stabla (crveno-crna, AVL) se sama preuređuju tako da visina ostane O(log n). Ne treba ih pisati ručno: C++ set i map su upravo balansirana binarna stabla pretrage.
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
Da li je stablo BST?
Dato je binarno stablo sa n čvorova (koren je 1). Za svaki čvor data je vrednost i deca L R (0 ako nema). Ispiši DA ako je stablo binarno stablo pretrage (sve vrednosti različite), inače NE.
Ulaz: n, zatim za svaki čvor vrednost L R.
Primer 1
Ulaz
5
8 2 3
3 4 5
10 0 0
1 0 0
6 0 0
Izlaz
DA
Primer 2
Ulaz
3
5 2 3
3 0 0
4 0 0
Izlaz
NE
Uputstvo
Nije dovoljno porediti čvor samo sa decom. Najlakše: uradi inorder obilazak i proveri da li je dobijeni niz strogo rastući.
Rešenje (C++)
#include <iostream>
#include <vector>
using namespace std;
int vr[100001], L[100001], R[100001];
vector<int> redosled;
void inorder(int v) {
if (v == 0) return;
inorder(L[v]);
redosled.push_back(vr[v]);
inorder(R[v]);
}
int main() {
int n;
cin >> n;
for (int v = 1; v <= n; v++) cin >> vr[v] >> L[v] >> R[v];
inorder(1);
bool ok = true;
for (size_t i = 1; i < redosled.size(); i++)
if (redosled[i - 1] >= redosled[i]) ok = false; // mora biti strogo rastuće
cout << (ok ? "DA" : "NE") << endl;
return 0;
}
ZADATAK 02Težina: Lako
Visina BST-a
Brojevi se redom ubacuju u prazno binarno stablo pretrage. Ispiši visinu dobijenog stabla (stablo sa jednim čvorom ima visinu 0).
Primer 1
Ulaz
7
8 3 10 1 6 14 4
Izlaz
3
Primer 2
Ulaz
4
1 2 3 4
Izlaz
3
Uputstvo
Koristi funkciju ubaci iz lekcije i rekurzivnu funkciju visina. Drugi primer pokazuje da sortiran ulaz pravi lanac.
Rešenje (C++)
#include <iostream>
#include <algorithm>
using namespace std;
int vr[100001], L[100001], R[100001], br = 0;
int ubaci(int v, int x) {
if (v == 0) {
vr[++br] = x;
return br;
}
if (x < vr[v]) L[v] = ubaci(L[v], x);
else if (x > vr[v]) R[v] = ubaci(R[v], x);
return v;
}
int visina(int v) {
if (v == 0) return -1;
return 1 + max(visina(L[v]), visina(R[v]));
}
int main() {
int n, koren = 0;
cin >> n;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
koren = ubaci(koren, x);
}
cout << visina(koren) << endl;
return 0;
}
Česte greške i saveti
Bazni slučaj obilaska je „nema čvora“ (v == 0), a ne „list“.
Kod provere BST-a nije dovoljno da je levo dete manje od roditelja – ceo levi deo mora biti manji.
Sortiran ulaz pravi BST-lanac; tada je rekurzija duboka n, a operacije O(n). Za garantovano O(log n) koristi set.
Proveri znanje
Otvori kviz
Binarna stabla
1. Koji obilazak BST-a daje vrednosti sortirano?
2. Redosled „čvor, levo, desno“ je:
3. Koliko koraka traje traženje u BST-u koji je nastao ubacivanjem brojeva 1, 2, …, n redom?
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.