![]() ![]() |
|
Introduciamo ora gli alberi binari e gli
alberi
binari di ricerca. Questi ultimi saranno utilizzati nella classe TreeSet
per una realizzazione del TDA Insieme (Set).
Gli alberi binari hanno una elegante definizione ricorsiva:
Molti algoritmi su alberi binari possono essere descritti in modo naturale sfruttando questa definizione ricorsiva, comprendendo un caso base (per l'albero vuoto) e una clausola ricorsiva (con due chiamate ricorsive, per i due sottoalberi).
|
![]() ![]() |
|
Per chiamare i nodi di un albero binario e le
relazioni tra di essi si usano termini botanici e di parentela.
Un nodo senza figli è detto foglia. Se il sottoalbero sinistro (risp. destro) di un albero non è vuoto, la sua radice viene detta figlio sinistro (risp. destro) della radice dell'intero albero (che è il padre). La relazione antenato-discendente generalizza quella di padre-figlio nel modo intuitivo. Ad esempio, nell'albero seguente [il nodo contenente] 10 è la radice dell'albero, ed ha sia un figlio sinistro (20) che un figlio destro (2). I nodi 1, 29 e 7 sono foglie. Il nodo 20 è il padre di 3 e un antenato di 29, che è un discendente di 10. Il nodo 3 ha soltanto il figlio sinistro, perché il suo sottoalbero destro è vuoto.
|
![]() ![]() |
|
Per realizzare gli alberi binari in Java utilizziamo
la classe BinNode,
i cui oggetti rappresentano i nodi di un albero. Ogni nodo contiene:
La figura seguente mostra l'albero della figura precedente,
in cui nodi sono oggetti di
BinNode. Le frecce rappresentano
riferimenti, null è rappresentato da un cerchietto,
l'oggetto nel campo key è impropriamente riportato
direttamente dentro il nodo.
|
![]() ![]() |
|
La classe BinNode contiene quattro
costruttori che permettono la creazione di un
BinNode specificando
come inizializzare uno o più campi.
|
![]() ![]() |
|
I costruttori di BinNode permette
di costruire un albero binario "dal basso", a partire dalla foglie. Ad
esempio, dopo i comandi
la variabile D contiene il riferimento
all'albero:
|
![]() ![]() |
|
"Visitare" un albero significa esaminare sequenzialmente
tutti i suoi nodi. Ci sono tre tipi principali di visite:
Il metodo seguente realizza la visita in ordine anticipato, stampando tutti i nodi dell'albero passato per argomento. Si noti che la struttura dell'algoritmo riflette la definizione ricorsiva degli alberi binari.
Le altre due visite si ottengono modificando l'ordine delle tre istruzioni del ramo else. |
![]() ![]() |
|
Il metodo seguente stabilisce se un certo oggetto
appartiene o meno ad un dato albero binario, usando una visita in ordine
anticipato. Si noti che:
|
![]() ![]() |
|
Come ultimo esempio di algoritmo su alberi binari,
vediamo un metodo che conta le foglie dell'albero passato per parametro.
Lo schema è il solito:
|
![]() ![]() |
|
Un albero binario di ricerca è
un albero binario tale che:
Una importante conseguenza della proprietà (ABR)
è la seguente:
|
![]() ![]() |
|
![]() ![]() |
Sugli alberi binari di ricerca sono definite diverse
operazioni (si veda [Cormen-Leiserston-Rivest]). Oltre a quelle dell'interfaccia
Set
(che vedremo in seguito), sono importanti:
|