/**
* Trieda implementujuca binarny vyhladavaci strom cisel
*/
public class BVS {
/**
* Sukromna privatna trieda reprezentujuca uzol stromu
*/
private static class Uzol {
// Hodnota ulozena v uzle
int hodnota;
// Referencia na laveho syna
Uzol lavy;
// Referencia na praveho syna
Uzol pravy;
/**
* Jednoduchy konstruktor ...
*/
public Uzol(int hodnota, Uzol lavy, Uzol pravy) {
this.hodnota = hodnota;
this.lavy = lavy;
this.pravy = pravy;
}
}
/**
* Referencia na uzol, ktory je korenom stromu
*/
private Uzol koren = null;
/**
* Vrati, ci strom obsahuje zadanu hodnotu
*
* @param hodnota
* hladana hodnota
*/
public boolean contains(int hodnota) {
// Cestu v strome zaciname v koreni stromu
Uzol aktualny = koren;
while (aktualny != null) {
if (aktualny.hodnota == hodnota)
return true;
// Na zaklade hodnoty v aktualnom uzle a hladanej hodnoty
// sa navigujeme ku jednemu zo synov (vid. vlastnosti BVS)
if (hodnota < aktualny.hodnota) {
aktualny = aktualny.lavy;
} else if (aktualny.hodnota < hodnota) {
aktualny = aktualny.pravy;
}
}
return false;
}
/**
* Prida zadanu hodnotu do stromu (ak v nom este nie je)
*
* @param hodnota
* vkladana hodnota
*/
public void add(int hodnota) {
// Specialne osetrime pripad, ked vkladame do prazdneho stromu
if (koren == null) {
koren = new Uzol(hodnota, null, null);
return;
}
// Vkladanie hodnoty do neprazdneho stromu (zaciname v koreni)
Uzol aktualny = koren;
while (true) {
// Ak taka hodnota uz je v BVS, niet co pridavat
if (aktualny.hodnota == hodnota)
break;
// Ak je vkladana hodnota mensia, ako hodnota v aktualnom uzle
// tak hodnotu treba vlozit do laveho podstromu
if (hodnota < aktualny.hodnota) {
// Ak laveho syna niet, tak namiesto neho vytvorime uzol
// s vkladanou hodnotou a koncime. V opacnom pripade sa
// presunieme do laveho syna
if (aktualny.lavy == null) {
aktualny.lavy = new Uzol(hodnota, null, null);
break;
} else
aktualny = aktualny.lavy;
}
// Ak je vkladana hodnota vacsia, ako hodnota v aktualnom uzle
// tak hodnotu treba vlozit do praveho podstromu
if (aktualny.hodnota < hodnota) {
// Ak praveho syna niet, tak namiesto neho vytvorime uzol
// s vkladanou hodnotou a koncime. V opacnom pripade sa
// presunieme do praveho syna
if (aktualny.pravy == null) {
aktualny.pravy = new Uzol(hodnota, null, null);
break;
} else
aktualny = aktualny.pravy;
}
}
}
public void remove(int hodnota) {
// Uzol, v ktorom sa nachadzame pri zostupe stromom
Uzol aktualny = koren;
// Uzol, ktory je rodicom uzla "aktualny"
Uzol rodicAktualneho = null;
while (aktualny != null) {
if (aktualny.hodnota == hodnota)
break;
// Ako rodicia aktualneho si pre dalsiu iteraciu while-cyklu
// poznacime aktualny uzol (o chvilu sa totiz ideme posunut
// k jednemu z jeho synov)
rodicAktualneho = aktualny;
// Na zaklade hodnoty v aktualnom uzle a hladanej hodnoty
// sa navigujeme ku jednemu zo synov (vid. vlastnosti BVS)
if (hodnota < aktualny.hodnota) {
aktualny = aktualny.lavy;
} else if (aktualny.hodnota < hodnota) {
aktualny = aktualny.pravy;
}
}
// Ak while skoncil preto, ze sme dosli na neexistujuci uzol, tak
// odstranovana hodnota v strome nie je (t.j. mozeme skoncit)
if (aktualny == null)
return;
int pocetDetiAktualneho = 0;
if (aktualny.lavy != null)
pocetDetiAktualneho++;
if (aktualny.pravy != null)
pocetDetiAktualneho++;
// Osetrime situaciu, kedy ma odstranovany uzol 0 synov. Vtedy
// jednoducho odstranime uzol zo stromu (nastavime jeho rodicovi
// ako syna null - popri tom si davame pozor na pripad, ked odstranovany
// uzol je koren - on nema rodica)
if (pocetDetiAktualneho == 0) {
if (rodicAktualneho == null)
koren = null;
else {
if (rodicAktualneho.lavy == aktualny)
rodicAktualneho.lavy = null;
else
rodicAktualneho.pravy = null;
}
}
// Osetrime situaciu, kedy odstranovany uzol ma prave jedno dieta
if (pocetDetiAktualneho == 1) {
// Vyberieme prave jeho dieta aktualneho uzla
Uzol dietaAktualneho = null;
if (aktualny.lavy != null)
dietaAktualneho = aktualny.lavy;
else
dietaAktualneho = aktualny.pravy;
if (rodicAktualneho == null)
koren = dietaAktualneho;
else {
if (rodicAktualneho.lavy == aktualny)
rodicAktualneho.lavy = dietaAktualneho;
else
rodicAktualneho.pravy = dietaAktualneho;
}
}
// Osetrime situaciu, kedy odstranovany uzol ma obe deti
if (pocetDetiAktualneho == 2) {
// Najdeme maximum v lavom podstrome (stale ideme doprava)
Uzol rodicMaxima = aktualny;
Uzol maximum = aktualny.lavy;
while (maximum.pravy != null) {
rodicMaxima = maximum;
maximum = maximum.pravy;
}
// Hodnotu z maxima presunieme do odstranovaneho uzla
// (ale uz ho neideme odstranovat, namiesto neho odstranime uzol,
// v ktorom bola maximalna hodnota laveho podstromu - tento uzol ma
// nanajvys jedno dieta a to dieta lave)
aktualny.hodnota = maximum.hodnota;
// Odstranime uzol, ktory uchovaval maximalnu hodnotu
if (rodicMaxima.lavy == maximum)
rodicMaxima.lavy = maximum.lavy;
else
rodicMaxima.pravy = maximum.lavy;
}
}
/**
* Privatna metoda na vypis stromu s korenom v zadanom uzle
*
* @param koren
* uzol, ktory je korenom vypisovaneho stromu
*/
private void vypisStrom(Uzol koren) {
if (koren == null)
return;
vypisStrom(koren.lavy);
System.out.println(koren.hodnota);
vypisStrom(koren.pravy);
}
/**
* Vypise hodnoty v strome v inorder prechode
*/
public void vypis() {
vypisStrom(koren);
}
/**
* @param args
*/
public static void main(String[] args) {
BVS bvs = new BVS();
int[] hodnoty = { 4, 5, 6, 2, 7, 1, 5, 7, 2 };
for (int i = 0; i < hodnoty.length; i++)
bvs.add(hodnoty[i]);
bvs.vypis();
System.out.println("odstranujem 7");
bvs.remove(7);
System.out.println("odstranujem 4");
bvs.remove(4);
bvs.vypis();
}
}