6. Alberi binari
NICOLETTA DE FRANCESCO
• NULL è un albero binario ;
• un nodo p più due alberi binari Bs e Bd forma un
albero binario
Algoritmi e
strutture dati
II parte
p è radice
Bs è il sottoalbero sinistro di p
Bd il sottoalbero destro di p
2003/2004
alberi etichettati
Algoritmi e strutture dati
1
Algoritmi e strutture dati
6. Alberi binari
2
6. Ricorsione su alberi binari
A
• padre
• figlio sinistro (figlio destro)
caso base
albero vuoto (NULL)
caso ricorsivo
radice + due sottoalberi
C
B
• antecedente
• foglia
D
• discendente
E
F
• livello di un nodo
• livello dell'albero
G
H
Algoritmi e strutture dati
3
Algoritmi e strutture dati
6. Visita anticipata (preorder)
6. Visita differita (postorder)
preOrder ( albero ) {
se l'albero binario non e' vuoto {
esamina la radice;
preOrder ( sottoalbero sinistro);
preOrder ( sottoalbero destro );
}
}
postOrder ( albero ) {
se l'albero binario non e' vuoto {
postOrder ( sottoalbero sinistro);
postOrder ( sottoalbero destro);
esamina la radice;
}
}
A
B
A
C
B
A B D C E G H F
D
E
G
H
E
G
5
C
DBGHEFCA
D
F
Algoritmi e strutture dati
4
F
H
Algoritmi e strutture dati
6
6. Visita simmetrica (inorder)
6. Memorizzazione in lista multipla
inOrder ( albero ) {
se l'albero binario non e' vuoto {
inOrder ( sottoalbero sinistro);
esamina la radice;
inOrder ( sottoalbero destro);
}
}
struct Node {
InfoType label;
Node* left;
Node* right;
};
label
left right
A
A
B
D B A G E H C F
C
A
C
B
D
E
G
C
B
F
D
H
D
Algoritmi e strutture dati
7
Algoritmi e strutture dati
6. visite in C++
void preOrder(Node* tree) {
6. Visite in C++
void preOrder(Node* tree) {
if (tree) {
void postOrder(Node* tree) {
<esamina tree->label>;
cout << tree->label;
preOrder(tree->left);
preOrder(tree->left);
preOrder(tree->right);
preOrder(tree->right);
}
}
Algoritmi e strutture dati
if (tree) {
postOrder(tree->left);
inOrder(tree->left);
postOrder(tree->right);
<esamina tree->label>;
<esamina tree->label>;
inOrder(tree-> right);
}
}
}
}
void inOrder(Node* tree) {
if (tree) {
if (tree) {
}
8
}
9
Algoritmi e strutture dati
6. Complessità delle visite
10
6. Alberi binari bilanciati
ALBERO BINARIO BILANCIATO
Complessità in funzione del numero di nodi:
i nodi di tutti i livelli tranne quelli dell'ultimo hanno due figli
T(0) = a
T(n) = b+T(ns)+T(nd )
con ns+n d=n-1 n>0
Caso particolare :
T(0) = a
bilanciato
non bilanciato
T(n) = b+T(n/2)+T(n/2)
Un albero binario bilanciato con livello k ha
2 (k+1) -1 nodi e 2k foglie
T(n) ∈
∈ O(n)
Algoritmi e strutture dati
11
Algoritmi e strutture dati
12
6. Alberi binari
6. Complessità nel numero dei livelli
ALBERO BINARIO QUASI BILANCIATO
Complessità in funzione dei livelli (se l’albero è bilanciato):
fino al penultimo livello è un albero bilanciato
T(0) = a
T(n) = b+2T(n-1)
T(n) ∈
∈ O(2n )
quasi bilanciato
quasi bilanciato
Algoritmi e strutture dati
13
Algoritmi e strutture dati
6. Alberi binari: conta i nodi e le foglie
14
6. Alberi binari: cerca un’etichetta
conta i nodi
int nodes (Node* tree) {
if (!tree) return 0;
// albero vuoto
return 1+nodes(tree->left)+nodes(tree->right);
}
ritorna il puntatore al nodo che contiene l’etichetta n. Se l’etichetta
non compare nell’albero ritorna NULL. Se più nodi contengono n,
ritorna il primo nodo che si incontra facendo la visita anticipata
Node* findNode (Infotype n, Node* tree) {
conta le foglie
int leaves (Node* tree) {
if (!tree) return 0;
// albero vuoto
if ( !tree->left && !tree->right ) return 1; // foglia
return leaves(tree->left)+leaves(tree->right);
}
// trovata :ritorna il puntatore
Node* a=findNode (n, tree->left);
if (a) return a;
// cerca a sinistra
// se trovata ritorna il puntatore
else return findNode(n, tree->right); // cerca a destra
}
15
6. Alberi binari: cancella tutto l’albero
Algoritmi e strutture dati
16
6. Alberi binari: inserisci un nodo
inserisce un nodo (son) come figlio di father, sinistro se c=‘l’,
destro se c=‘r’. Ritorna 1 se l’operazione ha successo, 0
altrimenti. Se l’albero è vuoto, inserisce il nodo come radice
void delTree(Node* &tree) {
if (tree) {
delTree(tree->left);
delTree(tree->right);
delete tree;
tree=NULL;
}
}
int insertNode
(Node* tree, InfoType son, InfoType father, char c){
if (!tree) {
// albero vuoto
tree=new Node;
tree ->label=son;
tree ->left = tree ->right = NULL;
return 1;
}
alla fine il puntatore deve essere NULL
Algoritmi e strutture dati
//albero vuoto: l’etichetta non c’è
return tree;
T(n) ∈
∈ O(n)
Algoritmi e strutture dati
if (!tree) return NULL;
if (tree->label==n)
17
Algoritmi e strutture dati
18
6. Alberi binari: inserisci un nodo (cont.)
6. Alberi binari: inserisci un nodo (cont.)
Node* a=findNode(father,tree);
//cerca father
if (!a) return 0;
//father non c’è
if (c=='l' && !a->left ) {
if (c=='r' && !a->right) {
//inserisci come figlio destro
a->right=new Node;
//inserisci come figlio sinistro
a->right->label=son;
a->left=new Node;
a->left->label=son;
a->right->left = a->right->right = NULL;
a->left->left =a->left->right=NULL;
return 1;
}
return 1;
return 0;
}
//inserimento impossibile
}
Algoritmi e strutture dati
19
Algoritmi e strutture dati
6. Class BinTree
20
6. Class BinTree
public:
template<class InfoType>
BinTree() { root = NULL; };
class BinTree {
struct Node {
~BinTree(){ delTree(root); };
InfoType label;
int find(InfoType x) { return findNode(x, root); };
Node *left, *right;
void pre() { preOrder(root); };
};
Node *root ;
void post(){ postOrder(root); };
Node* findNode(InfoType, Node*);
void in() { inOrder(root); };
void preOrder(Node*);
void inOrder(Node*);
int insert( InfoType son, InfoType father, char c) {
insertNode(root,son, father,c);
void postOrder(Node*);
void delTree(Node*&);
};
int insertNode(Node*, InfoType, InfoType, char)
};
Algoritmi e strutture dati
21
Algoritmi e strutture dati
7.1 Alberi generici: definizione
7.1 Alberi generici: differenza con alberi binari
alberi binari
• un nodo p è un albero
• un nodo + una sequenza di alberi A1 .. An è un albero
A
B
• radice
B
sottoalbero sinistro vuoto
A
• i-esimo sottoalbero
B
C
• i-esimo figlio
• livello
A
diverso da
sottoalbero destro vuoto
• padre
22
D
E
R
alberi generici
A
F
unico albero : radice: A, un sottoalbero
B
G
Algoritmi e strutture dati
H
23
Algoritmi e strutture dati
24
7.1 Alberi generici: visite
7.1 Alberi generici: visite
preOrder ( albero ) {
postOrder ( albero ) {
esamina la radice;
se l'albero ha n sottoalberi {
preOrder ( primo sottoalbero);
…
preOrder ( n-esimo sottoalbero);
se l'albero ha n sottoalberi {
postOrder ( primo sottoalbero);
…
postOrder ( n-esimo sottoalbero);
esamina la radice ;
}
}
A
B
A
C
D
R
E
B
ABDCEGHFR
F
D
H
G
E
G
Algoritmi e strutture dati
25
7.1 Alberi generici: memorizzazione
C
R
DBGHEFCRA
F
H
Algoritmi e strutture dati
26
7.1 Alberi generici: corrispondenza fra visite
MEMORIZZAZIONE FIGLIO-FRATELLO
Utilizzando la memorizzazione figlio-fratello:
• primo figlio a sinistra
• primo fratello a destra
la visita preorder del trasformato corrisponde
alla visita preorder dell’albero generico
Α
Β
A
B
D
C
E
C
D
R
F
G
G
H
la la visita inorder del trasformato corrisponde
alla visita postorder dell’albero generico
R
Ε
F
H
Algoritmi e strutture dati
27
7.2 Esempi di programmi su alberi generici: conta nodi e foglie
Algoritmi e strutture dati
28
7.2 Esempi di programmi su alberi generici: inserimento
conta i nodi (vedi albero binario)
inserisce un nodo in fondo a una lista di fratelli
int nodes (Node* tree) {
if (!tree) return 0;
return 1+nodes(tree->left)+nodes(tree->right);
}
conta le foglie
int leaves(Node* tree) {
if (!tree) return 0;
if (!tree->left) return 1+ leaves(tree->right); // foglia
return leaves(tree->left)+ leaves(tree->right);
}
Algoritmi e strutture dati
29
void addSon(InfoType x, Node* &tree) {
if (!tree) {
//lista vuota
tree=new Node;
tree->label=x;
tree->left = tree->right = NULL;
}
else
//lista non vuota
addSon(x, tree->right);
}
Algoritmi e strutture dati
30
7.2 Esempi di programmi su alberi generici: inserimento
8. Alberi binari di ricerca: definizione
inserisce son come ultimo figlio di father . Se l’albero e’ vuoto,
lo inserisce come radice
Un albero binario di ricerca è un albero binario tale che
per ogni nodo p:
int insert(InfoType son, InfoType father, Node* &tree) {
if (!tree) {
// albero vuoto
tree=new Node;
• i nodi del sottoalbero sinistro di p hanno etichetta
minore dell’etichetta di p
tree->label=son;
tree->left = tree->right = NULL;
return 1;
}
Node* a=findNode(father, tree); // a: puntatore di father
if (!a) return 0;
• i nodi del sottoalbero destro di p hanno etichetta
maggiore dell’etichetta di p
// father non trovato
addSon(son, a->left);
return 1;
}
Algoritmi e strutture dati
31
8. Un albero binario di ricerca
Algoritmi e strutture dati
32
8. Un albero binario di ricerca con gli stessi nodi
50
50
80
35
80
20
20
10
35
90
90
10
Algoritmi e strutture dati
33
8. Un albero binario di ricerca con gli stessi nodi
Algoritmi e strutture dati
34
8. Alberi binari di ricerca: proprietà e operazioni
• non ci sono doppioni
90
• la visita simmetrica elenca le etichette in ordine crescente
80
OPERAZIONI
50
• ricerca di un nodo
35
• inserimento di un nodo
• cancellazione di un nodo
20
10
Algoritmi e strutture dati
35
Algoritmi e strutture dati
36
8. Alberi binari di ricerca: ricerca
8. Alberi binari di ricerca: ricerca
T(0)=a
Node* findNode (InfoType n, Node* tree) {
if (!tree) return 0;
// albero vuoto
T(n)= b + T(k)
k<n
T(0)=a
if (n == tree->label ) return tree;
if (n<tree->label )
return findNode(n, tree->left);
return findNode(n, tree->right);
// n=radice
O(log n)
T(n)= b + T(n/2)
// n<radice
T(0)=a
O(n)
T(n)= b + T(n-1)
// n>radice
}
in media : O(logn)
Algoritmi e strutture dati
37
Algoritmi e strutture dati
8. Alberi binari di ricerca: inserimento
38
8. Esempio di inserimento
50
void insertNode (InfoType n, Node* &tree) {
if (!tree) {
// albero vuoto : creazione nodo
tree=new Node;
tree->label=n;
tree->left = tree->right = NULL; return;
}
if (n<tree->label )
// n<radice
insertNode (n, tree->left);
if (n>tree->label )
// n>radice
insertNode (n, tree->right);
}
80
20
10
35
90
50
inserisco 40
80
20
10
35
40
O(log n)
Algoritmi e strutture dati
39
Algoritmi e strutture dati
8. Alberi binari di ricerca: cancellazione
40
8. Alberi binari di ricerca: cancellazione
restituisce l’etichetta del nodo più piccolo di un albero ed
elimina il nodo che la contiene
void deleteNode(InfoType n, Node* &tree) {
if (tree)
if (n < tree->label)
void deleteMin (Node* &tree, InfoType &m) {
if (tree->left)
//c’è un nodo più piccolo
deleteMin(tree->left, m);
else {
m=tree->label;
//restitusco l’etichetta
Node* a=tree;
tree=tree->right;
//connetto il sottoalbero destro di
//n minore della radice
{ deleteNode(n, tree->left); return; }
if (n > tree->label)
//n maggiore della radice
{ deleteNode(n, tree->right); return; }
if (!tree->left)
//n non ha figlio sinistro
{ Node* a=tree; tree=tree->right; delete a;return;}
if (!tree->right)
//n non ha figlio destro
{ Node* a=tree; tree=tree->left; delete a; return;}
// m al padre di m
delete a;
90
deleteMin(tree->right, tree->label);
//elimino il nodo
//n ha entrambi i figli
}
}
}
O(log n)
Algoritmi e strutture dati
41
Algoritmi e strutture dati
42
8. Esempio di cancellazione
100
100
50
50
40
40
200
200
80
80
100
100
70
70
60
60
cancello 50
60
60
65
65
40
40
200
200
80
80
70
70
65
65
Algoritmi e strutture dati
43