


















































































Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Questa dispensa è divisa in 2 parti: - una parte teorica che descrive gli algoritmi e dimostrazioni delle varie strutture dati. - una parte scritta in cui vengono svolti esercizi d'esame. Sono presenti 10 tipi di compiti differenti.
Tipologia: Dispense
1 / 90
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!



















































































Dispensa del corso Dati algoritmi di ingegneria informatica
public int depth(Tree
If(t.isRoot())
return 0;
return 1+ depth(t,parent(p))
Definizione : la profondità è il numero di antenati di p, diversi dalla posizione stessa.
Prestazioni : 𝑂(𝑑𝑣) dove 𝑑𝑣 è la profondità dell’albero.
Caso peggiore : 𝑂
perché 𝑑𝑣 può essere al massimo 𝑛 − 1.
public int heigth(t, Position
Int h=0;
If(t.isExternal(p))
return h;
for(Position
h=Math.max(h, 1+ heigth(c));
return h
Definizione : l’altezza è il valore massimo delle profondità delle sue posizioni.
Prestazioni : 𝑂(𝑔𝑣) dove 𝑔𝑣 è il numero di figli di ciascuna posizione.
Caso peggiore : 𝑂
perché 𝑔𝑣 può essere al massimo 𝑛 − 1.
public void preOrder(Position
visit(p);
for(Position
preOrder(c);
public void postOrder(Position
for(Position
postOrder(c);
visit(p);
public void breadth (Position
Queue q=new Queue();
q.enqueue(p); //Si suppone che p sia la radice dell’albero
while(!q.isEmpty()){
Position
visit(p);
for(Position
q.enqueue(c);
Prestazioni : Tutti e 3 gli algoritmi sono 𝑂
Contare le foglie di un albero (viene restituito un valore che rappresenta un risultato
globale, elaborato dall’attraversamento dell’albero)
public static
if (t == null || t.isEmpty()) return 0;
return countLeaves(t, t.root());
private static
if (t.isExternal(v)) // azione di visita di una foglia
return 1;
int count = 0; // azione di visita di un nodo interno
for (Position
count += countLeaves(t, x);
return count; // foglie nel sottoalbero con radice v
Contare i nodi interni di un albero
public static
if (t == null || t.isEmpty()) return 0;
return countLeaves(t, t.root());
private static
if (t.isExternal(v)) // azione di visita di una foglia
return 0 ;
int count = 1 ; // azione di visita di un nodo interno
for (Position
count += countLeaves(t, x);
return count; // foglie nel sottoalbero con radice v
Prestazioni : entrambi gli algoritmi sono 𝑂
perché l’operazione di visita è 𝑂
Applicazione di attraversamento pre-order per l’implementazione del metodo
positions() dell’interfaccia Tree.
public Iterable<Position
ArrayList<Position
if (isEmpty())
return list; // lista vuota
preorderAppendPosition(list, root());
list.trimToSize(); // ritaglia la capacità per evitare spreco di spazio
return list;
private void preorderAppendPosition(ArrayList<Position
list.add(v); // azione di visita 𝜃( 1 ) in media
for (Position
preorderAppendPosition(list, c);
Prestazioni : l’algoritmo positions ha prestazioni 𝑂(𝑛) perché l’operazione di visita è
Assegnare l’altezza a ciascun nodo
public static void setHeigth(Tree
If(t != null && !t.isEmpty())
setHeigth(t, t.root());
private static void setHeigth(Tree
Int height=0; //Se è una foglia
for(Position
setHeigth(t, c);
int h= c.element(); //Altezza salvata nel nodo
if(h+1 > height)
height=h+1;
Caso base : ℎ = 0 la tesi si riduce 𝑛
𝐸
0
Se l'albero ha altezza zero, allora la sua radice ha altezza zero e di conseguenza è una
foglia. Se la radice di un albero è una foglia allora non ha discendenti propri e quindi
la radice è l’unico nodo esterno.
Caso Per ∀ ℎ > 0
Usando le ipotesi induttive sui due sottoalberi della radice, si possono definire:
𝐿
sottoalbero sinistro, 𝑆
𝑅
sottoalbero destro e deve valere 𝑆
𝐿
𝑅
𝐿
𝑅
insiemi che contengono i nodi esterni dei sottoalberi 𝑆
𝐿
𝑅
della radice
r.
𝐸𝐿
𝐸𝑅
cardinalità degli insiemi 𝐸
𝐿
𝑅
(cioè numero di nodi esterni dei 2
sottoalberi.
𝐿
𝑅
L'insieme dei nodi esterni dell’albero è l'unione degli insiemi 𝐸
𝐿
𝑅
dei sottoalberi,
quindi 𝑛
𝐸
𝐸𝐿
𝐸𝑅.
Dunque, per ∀ ℎ > 0 e se ∃ 𝑆
𝐿
𝑅
(esistono entrambi):
𝐸
𝐸𝐿
𝐸𝑅
𝐻𝐿
𝐻𝑅
ℎ− 1
ℎ− 1
ℎ− 1
𝒉
. (limite superiore)
𝐸
𝐸𝐿
𝐸𝑅
≥ 2 perché 𝑛
𝐸𝐿
≥ 1 e 𝑛
𝐸𝑅
≥ 1 ma se uno dei 2 sottoalberi non
esiste bisogna considerare 𝑛
𝐸
≥ 𝟏. (limite inferiore)
Dimostrazione 2 proprietà
Usando il principio di induzione applicato all’altezza ℎ dell’albero, dimostrare che in
ogni albero binario vale la relazione ℎ ≤ 𝑛
𝐼
ℎ
− 1 , dove 𝑛
𝐼
è il numero di nodi
interni dell’albero.
Caso base : ℎ = 0 la tesi si riduce 𝑛
𝐼
0
Se l'albero ha altezza zero, allora la sua radice ha altezza zero e di conseguenza è una
foglia. Se la radice di un albero è una foglia allora non ha discendenti propri e quindi
non ha nodi interni.
Caso Per ∀ ℎ > 0
Usando le ipotesi induttive sui due sottoalberi della radice, si possono definire:
𝐿
sottoalbero sinistro, 𝑆
𝑅
sottoalbero destro e deve valere 𝑆
𝐿
𝑅
𝐿
𝑅
insiemi che contengono i nodi interni dei sottoalberi 𝑆
𝐿
𝑅
della radice r.
𝐼𝐿
e 𝑛
𝐼𝑅
cardinalità degli insiemi 𝐼
𝐿
𝑅
(cioè numero di nodi interni dei 2
sottoalberi.
𝐿
𝑅
L'insieme dei nodi interni dell’albero è l'unione degli insiemi 𝐼
𝐿
𝑅
dei sottoalberi 𝑆
𝐿
quindi 𝑛 𝐼
𝐼𝐿
𝐼𝑅
Dunque, per ∀ ℎ > 0 e se ∃ 𝑆
𝐿
𝑅
(esistono entrambi):
𝐼
𝐼𝐿
𝐼𝑅
𝐻𝐿
𝐻𝑅
ℎ− 1
ℎ− 1
ℎ− 1
𝒉
− 𝟏 (limite superiore)
Se esiste un solo sottoalbero:
𝐼
𝐼𝐿
𝐼𝑅
𝐿
𝐼𝐿
𝐿
e 𝑛
𝐼𝑅
Dimostrazione 3 proprietà
Sommando membro a membro le prime relazioni dimostrate precedentemente:
𝐸
ℎ
𝐼
ℎ
Si ottiene:
𝐸
𝐼
ℎ
ℎ
ℎ
𝒉+𝟏
Dimostrazione 4
Avendo dimostrato la terza proprietà:
ℎ+ 1
Si può agevolmente dimostrare la quarta:
ℎ+ 1
ℎ+ 1
2
𝟐
Dimostrazione proprietà 2 (caso albero binario proprio)
Usando il principio di induzione applicato all’altezza ℎ dell’albero, dimostrare che in
ogni albero binario proprio vale la relazione ℎ ≤ 𝑛 𝐼
ℎ
− 1 , dove 𝑛
𝐼
è il numero
di nodi interni dell’albero.
Caso base : ℎ = 0 la tesi si riduce 𝑛
𝐼
0
Se l'albero ha altezza zero, allora la sua radice ha altezza zero e di conseguenza è una
foglia. Se la radice di un albero è una foglia allora non ha discendenti propri e quindi
non ha nodi interni.
Caso Per ∀ ℎ > 0
Usando le ipotesi induttive sui due sottoalberi della radice, si possono definire:
𝐿
sottoalbero sinistro, 𝑆
𝑅
sottoalbero destro e deve valere 𝑆
𝐿
𝑅
𝐿
𝑅
insiemi che contengono i nodi interni dei sottoalberi 𝑆
𝐿
𝑅
della radice r.
𝐼𝐿
e 𝑛
𝐼𝑅
cardinalità degli insiemi 𝐼
𝐿
𝑅
(cioè numero di nodi interni dei 2
sottoalberi.
𝐿
𝑅
L'insieme dei nodi interni dell’albero è l'unione degli insiemi 𝐼
𝐿
𝑅
dei sottoalberi 𝑆
𝐿
quindi 𝑛 𝐼
𝐼𝐿
𝐼𝑅
Dunque, per ∀ ℎ > 0 e se ∃ 𝑆
𝐿
𝑅
(esistono entrambi):
𝐼
𝐼𝐿
𝐼𝑅
𝐻𝐿
𝐻𝑅
ℎ− 1
ℎ− 1
ℎ− 1
𝒉
− 𝟏 (limite superiore)
𝐼
𝐼𝐿
𝐼𝑅
𝐿
𝑅
𝐿
𝑅
perché ℎ
𝐿
𝑅
𝐿
𝑅
≥ max(ℎ
𝐿
𝑅
Dimostrazione 3 proprietà (caso albero binario proprio)
Sommando membro a membro le prime relazioni dimostrate precedentemente
𝐸
ℎ
𝐼
ℎ
Si ottiene:
𝐸
𝐼
ℎ
ℎ
ℎ
𝒉+𝟏
Dimostrazione 4 (caso albero binario proprio)
Avendo dimostrato la terza proprietà:
ℎ+ 1
Si può agevolmente dimostrare la quarta:
𝒏−𝟏
𝟐
ℎ+ 1
ℎ+ 1
2
𝟐
Un albero binario 𝑇 di altezza ℎ > 0 si dice completo se:
possibile. (quindi il livello 𝑖 ha 2
𝑖
nodi, con 𝑖 < ℎ)
esterni.
interni) può avere un solo figlio, che deve essere il suo figlio sinistro.
ℎ che ha alla propria sinistra tutti gli altri nodi di livello ℎ.
2
Dalla definizione discende che un albero binario completo può essere triangolare
oppure triangolare fino al livello 𝒉 – 𝟏 con un ultimo livello “compatto a sinistra”.
Algoritmo in pseudocodice
while (!T.isExternal(z) && (key(z) > key(T.left(z)) || key(z) > key(T.right(z)) ){
//scambia e(z) con e(parent(z))
if(key(T.left(z))<=key(T.right)){
// si scambiano i dati, non i nodi
T.replace(z, T.element(T.left(z));
z = T.left(z) // scendo a sinistra
}else{
// si scambiano i dati, non i nodi
T.replace(z, T.element(T.right(z));
z = T.right(z) // scendo a destra
Con la rappresentazione di un heap basata su array si evitano alcune complicazioni
che derivano dall’albero con struttura concatenata. In particolare, i metodi insert ,
removeMin devono individuare l’ultima posizione nel heap:
2
Un albero binario di ricerca (Binary Search Tree, BST) è un albero binario proprio, non
vuoto, con queste ulteriori caratteristiche:
𝑖
contiene un elemento, x(v) , appartenente a un insieme totalmente
ordinato.
𝑒
non contengono alcun elemento (sono nodi “segnaposto”, placeholder, in
Java, contengono null).
𝑒
𝑖
di contenuto crescente.
Il sottoalbero sinistro della radice contiene elementi minori della radice, nel
sottoalbero destro sono maggiori.
E’ usato per memorizzare una mappa ordinata.
Algoritmo di ricerca in una mappa ordinata
SearchInBSTsubTree(T, k, v)
if T.isExternal (v)
return null // non trovato
(else) if k == key(v) // usare equals
return value(v) // trovato
(else) if k < key(v) // usare compareTo
return SearchInBSTsubTree(T, k, T.left(v))
(else) // k > key(v)
return SearchInBSTsubTree(T, k, T.right(v))
Proprietà di bilanciamento in altezza
Per ogni posizione 𝑝 di 𝑇, le altezze dei figli di 𝑝 devono differire di al massimo
un’unità.
Proposizione sull’altezza di un albero AVL
L’altezza h di un albero AVL di dimensione n è O(log
2
n
Dimostrazione
Invece di trovare un limite superiore per l’altezza si rivela più semplice trovare il limite
inferiore quando il numero di nodi interni indicato con 𝑛(ℎ) è minimo.
Si può osservare che:
Con ℎ ≥ 3 per la proprietà di bilanciamento dell’altezza si ha che l’albero AVL è
costituito da un sottoalbero con altezza ℎ − 1 e uno con ℎ − 2.
Dunque, è opportuno definire:
Si ottiene:
Attraverso le proprietà delle progressioni di Fibonacci si può notare che 𝑛(ℎ) è una
funzione crescente di conseguenza vale:
--> n
h
i
∗ n
h − 2i
con h − 2i ≥ 1
Per comodità scegliamo h − 2i = 2 quindi i =
ℎ
2
− 1 e sostituendo nella formula si
ottiene:
n
h
ℎ
2
− 1
∗ n
ℎ
2
− 1
∗ n
ℎ
2
− 1
--> n
h
ℎ
2
− 1
Elevando il logaritmo entrambi i membri:
2
ℎ
2
2
𝟐
L’ultima disuguaglianza implica che un albero AVL di dimensione n ha un’altezza
inferiore a 2 ∗ log
2
(n
h
L’inserimento di un nuovo nodo in un albero AVL esegue lo stesso algoritmo visto per
la mappa realizzata con BST “normale”. Per effetto dell’inserimento in 𝑇, una foglia,
𝑤, diventa nodo interno e un sottoinsieme del percorso minimo che collega 𝑤 alla
radice aumenta la propria altezza di un’unità: tale sottoinsieme comprende 𝑤 e un
certo numero di suoi antenati disposti consecutivamente lungo il percorso.
L’aumento delle altezze sbilancia gli antenati di 𝑤, dunque è opportuno ribilanciare
l’albero per garantire le prestazioni 𝑂(log(𝑛)). Possiamo definire come nodo 𝑧 il
primo che si è sbilanciato risalendo verso la radice. Il sottoalbero avente radice in 𝑧 è
minimamente sbilanciato perché i 2 sottoalberi hanno altezze che differiscono di 2. A
questo punto possiamo definire:
A questo punto possiamo ripristinare il bilanciamento del sottoalbero invocando il
metodo di ristrutturazione di una terna di nodi. Che consiste nel prendere il nodo
con chiave intermedia tra i tre: 𝑧, 𝑦, 𝑥 e lo si fa diventare radice. Gli altri 2 nodi si
sistemano di conseguenza come figli sinistro e destro e i sottoalberi si “attaccano” nei
rami liberi rispettando l’ordinamento precedente.
Le prestazioni della ristrutturazione sono 𝜃( 1 ) e hanno un effetto globale. Nel
complesso l’algoritmo di inserimento è 𝑂(log(𝑛)) perché l’altezza dell’albero AVL è
𝑂(log
) grazie al bilanciamento della sua altezza.