alberi
tipo astratto, implementazione,
algoritmi
argomenti
tipo astratto albero
definizione
implementazione in Java
algoritmi di visita
alberi binari
implementazione di alberi binari in Java
ASD - Alberi
2
tipo di dato astratto albero
insieme vuoto di nodi oppure costituito da
una radice R e da 0 o più alberi (sottoalberi)
la radice di ogni sottoalbero è collegata a R
da un arco
R
es.: radice R con n
sottoalberi
T1
ASD - Alberi
T2
Tn
3
terminologia
genitore, figlio, fratello
radice
concetti intuitivi
nodo interno
nodo
foglia se ha zero figli
interno se ha almeno un
figlio
ASD - Alberi
foglia
4
terminologia/2
livello di un nodo
lunghezza (n.ro nodi)
percorso radice-nodo
ramo
livello radice = 1
percorso radice-foglia
altezza albero
altezza = 3
lunghezza (n.ro nodi)
ramo più lungo
ASD - Alberi
5
alberi?
ASD - Alberi
6
esempi di alberi
alberi genealogici
gerarchie di ereditarietà
classificazioni di specie animali
organizzazione del territorio
ad es., in Java
continente, nazione, regione, provincia ecc
(alcuni) organigrammi
file system
domini Internet
ASD - Alberi
7
rappresentazione di alberi con
liste collegate
livello di C = 3
R
B
A
Primo figlio
di R
C
Fratello di A
Elemento
Riferimento al prossimo fratello
Riferimento al primo figlio
ASD - Alberi
8
operazioni sugli alberi
operazioni più importanti
element(v): restituisce l’elemento
memorizzato nel nodo v
root(): restituisce la radice dell’albero
parent(v): restituisce il genitore del nodo v
children(v): restituisce i figli di v
isLeaf(v): restituisce true se v è una foglia
isRoot(v): restituisce true se v è la radice
ASD - Alberi
9
operazioni sugli alberi
Altre operazioni
livello di un nodo
altezza dell’albero
# nodi
# foglie
arità
max # di figli di un nodo dell’albero
isEmpty
true se l’albero ha zero nodi
ASD - Alberi
10
rappresentazione
dei nodi in Java
nodi
class TreeNode {
Object element;
TreeNode firstChild;
TreeNode nextSibling;
TreeNode parent;
}
ASD - Alberi
11
tipo astratto albero in Java
public interface Tree {
Object element(TreeNode v);
TreeNode root();
TreeNode parent(TreeNode v);
ListIterator children(TreeNode v);
boolean isLeaf(TreeNode v);
boolean isRoot(TreeNode v);
}
ASD - Alberi
12
algoritmi su alberi
livello di un nodo
public int level(TreeNode v) {
if(this.isRoot(v))
return 1;
else
return 1 + level(this.parent(v));
}
costo proporzionale all’altezza: O(h )
ASD - Alberi
13
algoritmi su alberi/2
altezza di un
(sotto)albero
costo
proporzionale al
numero di nodi:
(n )
viene esaminato
ogni nodo
ciascun nodo
viene esaminato
una sola volta
int height(v) {
int h=0, hmax=0;
if(v == null) return 0;
if(isLeaf(v)) return 1;
TreeNode w = v.firstChild;
hmax = height(w);
while(w.nextSibling != null) {
w = w.nextSibling;
h = height(w);
if(h > hmax) hmax = h;
}
return 1 + hmax;
}
ASD - Alberi
14
algoritmi su alberi/3
visita (o attraversamento) di un albero
in profondità (depth-first search, a
scandaglio): DFS
vengono visitati i rami, uno dopo l’altro
tre varianti
in ampiezza (breadth-first search, a
ventaglio): BFS
a livelli, partendo dalla radice
ASD - Alberi
15
visite in profondità/preordine
in preordine (preorder, o ordine anticipato)
dato un nodo v
visita v
visita i sotto-alberi aventi come radice i figli di v, da
sinistra verso destra
void treePreorder(root) {
if(root == null) return;
<visita root>
r = root.firstChild
while (r != null) {
treePreorder(r);
r = r.nextSibling;
}
ASD - Alberi
}
16
visite in profondità/inordine
in ordine simmetrico (inorder)
dato un nodo v con k sotto-alberi
visita il primo sotto-albero (radice v.firstChild)
visita v
visita gli altri k-1 sotto-alberi
void treeInorder(root) {
if(root == null) return;
r = root.firstChild;
treeInorder(r);
<visita root>
r = r.nextSibling;
while (r != null) {
treeInorder(r);
r = r.nextSibling;
}
}
ASD - Alberi
17
visite in profondità/postordine
in postordine (postorder, o ordine posticipato)
dato un nodo v
visita i sotto-alberi aventi come radice i figli di v, da
sinistra verso destra
visita v
void treePostorder(root) {
if(root == null) return;
r = root.firstChild
while (r != null) {
treePostorder(r);
r = r.nextSibling;
}
<visita root>
ASD - Alberi
}
18
visite in profondità
2
1
2
3
4
1
5
6
preordine
7
7
4
3
1
6
5
inordine
ASD - Alberi
7
3
2
6
4
5
postordine
19
visita in ampiezza
breadth-first search (BFS), usa una coda
dato un nodo v
void bfs(v) {
if(v == null) return;
queue.enqueue(v);
while (!queue.isEmpty()) {
v = queue.dequeue();
v.visit();
TreeNode w = v.firstChild;
while(w != null) {
queue.enqueue(w);
w = w.nextSibling;
}
}
ASD - Alberi
}
20
visita in ampiezza
1
2
3
4
5
6
7
BFS
ASD - Alberi
21
alberi binari
un albero si dice binario se ogni nodo può
avere al più 2 figli
la rappresentazione si semplifica
public class BinaryNode {
protected Object element;
protected BinaryNode leftChild;
protected BinaryNode rightChild;
}
ASD - Alberi
22
ADT albero binario in Java
public interface BinaryTree {
Object element(BinaryNode v);
BinaryNode root();
BinaryNode parent(BinaryNode v);
BinaryNode leftChild(BinaryNode v);
BinaryNode rightChild(BinaryNode v);
boolean isLeaf(BinaryNode v);
boolean isRoot(BinaryNode v);
}
ASD - Alberi
23
alberi binari/visita in preordine
void treePreorder(BinaryNode v) {
if(v == null) return;
<visita v>
treePreorder(leftChild(v));
treePreorder(rightChild(v));
}
ASD - Alberi
24
alberi binari/visita inordine
void treeInorder(BinaryNode v) {
if(v == null) return;
treeInorder(leftChild(v));
<visita v>
treeInorder(rightChild(v));
}
ASD - Alberi
25
alberi binari/visita in postordine
void treePostorder(BinaryNode v)
{
if(v == null) return;
treePostorder(leftChild(v));
treePostorder(rightChild(v));
<visita v>
}
ASD - Alberi
26
alberi binari/visita in ampiezza
void bfs(v) {
TreeNode p = v;
queue.enqueue(p);
while (!queue.isEmpty()) {
p = (BSTNode) queue.dequeue();
p.visit();
if (p.leftChild != null)
queue.enqueue(p.leftChild);
if (p.rightChild != null)
queue.enqueue(p.rightChild);
}
}
ASD - Alberi
27
strutture dati per alberi binari
vettori
rappresentazioni collegate
esercizi:
implementare l’interfaccia BinaryTree
usando una rappresentazione collegata
scrivere un programma che legga gli
elementi (stringhe) di un albero binario e li
stampi effettuando una visita in preordine
ASD - Alberi
28
uso di vettori
ogni nodo v è memorizzato in posizione p(v)
2
4
se v è la radice allora p(v)=1 (indice 0 in Java, C,
C++)
se v è il figlio sinistro di u allora p(v)=2p(u)
se v è il figlio destro di u allora
1
p(v)=2p(u)+1
2
1
3
4
3
6
7
6
7
ASD - Alberi
29
uso di vettori/2
implementazione statica: è necessaria
una stima del numero massimo di nodi
dell’albero
può portare a spreco di risorse
nel caso peggiore, un albero con n nodi
richiede un vettore con 2n-1 elementi (se
l’albero degenera in una catena)
ASD - Alberi
30
uso di vettori/3
in Java: si possono usare le classi Vector
(sincronizzata) o ArrayList (non sincronizzata)
Vector e ArrayList gestiscono anche il
ridimensionamento quando il numero di elementi
cresce oltre la capacità corrente
ciò porta a ritardi (per gestire l’allocazione di nuova
memoria)
esercizio: scrivere una classe che implementi
l’interfaccia BinaryTree usando ArrayList o
Vector
ASD - Alberi
31
rappresentazione collegata
public class LinkedBinaryTree implements BinaryTree {
private BinaryNode root; /* Rif. alla radice*/
private int size;
public LinkedBinaryTree() {
root = new BinaryTreeNode(null, null, null);
size = 0;
}
/* Metodi */
} /* Fine della classe */
ASD - Alberi
32