Sei sulla pagina 1di 24

Alberi

Albero binario

Un albero binario un albero (ordinato) in cui


ciascun nodo pu avere al massimo due figli
(figlio destro e figlio sinistro)

albero binario proprio:


ogni nodo interno ha esattamente due figli

Strutture Dati

Alberi

Albero binario (definizione ricorsiva)


Un albero binario T o vuoto oppure formato da

un nodo r detto radice;


un albero binario detto sottoalbero sinistro di T;
un albero binario detto sottoalbero destro di T.

Strutture Dati

Alberi

L'ADT albero binario

L'ADT albero binario un caso speciale dell'ADT albero


Metodi aggiuntivi:
left(v): restituisce il figlio sinistro di v; si verifica una condizione
di errore se v non ha il figlio sinistro
right(v): restituisce il figlio destro di v; si verifica una condizione
di errore se v non ha il figlio destro
hasLeft(v): verifica se v ha il nodo sinistro
hasRight(v): verifica se v ha il nodo destro

Strutture Dati

Alberi

Interfaccia dell'ADT albero binario

public interface BinaryTree<E> extends Tree<E>{


/** Restituisce il figlio sinistro di un nodo. */
public Position<E> left(Position<E> v)
throws InvalidPositionException, BoundaryViolationException;
/** Restituisce il figlio destro di un nodo. */
public Position<E> right(Position<E> v)
throws InvalidPositionException, BoundaryViolationException;
/** Ci dice se un nodo ha un figlio sinistro. */
public boolean hasLeft(Position<E> v) throws InvalidPositionException;
/** Ci dice se un nodo ha un figlio destro. */
public boolean hasRight(Position<E> v) throws InvalidPositionException;
}

Strutture Dati

Alberi

Propriet degli alberi binari


Livello d: insieme dei nodi a profondit d
Domanda: Quanti nodi ci sono ad un dato livello i?

livello

numero max di nodi

Risposta: ci sono al pi 2 i nodi


Strutture Dati

Alberi

Visita inorder

In una visita inorder un nodo viene visitato

Algorithm inOrder(v)
if hasLeft (v)
inOrder (left (v))
visit(v)
if hasRight (v)
inOrder (right (v))

dopo il suo sottoalbero sinistro e


prima del suo sottoalbero destro

5
2
1

8
4

3
Strutture Dati

Alberi

Implementazione mediante struttura concatenata


riferimento alla radice
parent

left

right

element

Strutture Dati

Alberi

Interfaccia BTPosition
public interface BTPosition<E> extends Position<E>{
public void setElement(E o);
public BTPosition<E> getLeft();
public void setLeft(BTPosition<E> v);
public BTPosition<E> getRight();
public void setRight(BTPosition<E> v);
public BTPosition<E> getParent();
public void setParent(BTPosition<E> v);
}

Strutture Dati

Alberi

Implementazione di BTPosition

public class BTNode<E> implements BTPosition<E>{


private E element; // l'elemento memorizzato in questo nodo
private BTPosition<E> left, right, parent; // nodi adiacenti

/** Costruttore */
public BTNode(E elem, BTPosition<E> p, BTPosition<E> l, BTPosition<E> r){
element = elem;
parent = p;
left = l;
right = r;
}
...
}

Strutture Dati

Alberi

Implementazione di BTPosition

public class BTNode<E> implements BTPosition<E>{


...
public E element() { return element; }
public void setElement(E o) { element=o; }
public BTPosition<E> getLeft() { return left; }
public void setLeft(BTPosition<E> v) { left=v; }
public BTPosition<E> getRight() { return right; }
public void setRight(BTPosition<E> v) { right=v; }
public BTPosition<E> getParent() { return parent; }
public void setParent(BTPosition<E> v) { parent=v; }
}

Strutture Dati

Alberi

Implementazione di BinaryTree

public class LinkedBinaryTree<E> implements BinaryTree<E> {


protected BTPosition<E> root;
// riferimento alla radice
protected int size;
// numero di nodi
/** Crea un albero binario vuoto. */
public LinkedBinaryTree() {
root = null; // si parte con un albero vuoto
size = 0;
}
/** Ci dice se un nodo e` interno. */
public boolean isInternal(Position<E> v) throws InvalidPositionException {
checkPosition(v);
return (hasLeft(v) || hasRight(v));
}
/** Ci dice se un nodo e` una foglia. */
public boolean isExternal(Position<E> v) throws InvalidPositionException {
return !isInternal(v);
}
...
}
Strutture Dati

Alberi

Implementazione di BinaryTree

public class LinkedBinaryTree<E> implements BinaryTree<E> {


...
public boolean isRoot(Position<E> v) throws InvalidPositionException {
checkPosition(v);
return (v == root);
}
/** Ci dice se un nodo ha un figlio sinistro. */
public boolean hasLeft(Position<E> v) throws InvalidPositionException {
BTPosition<E> vv = checkPosition(v);
return (vv.getLeft() != null);
}
/** Ci restituisce il figlio sinistro di un nodo. */
public Position<E> left(Position<E> v)
throws InvalidPositionException, BoundaryViolationException {
BTPosition<E> vv = checkPosition(v);
Position<E> leftPos = vv.getLeft();
if (leftPos == null)
throw new BoundaryViolationException("Non esiste un figlio sinistro");
return leftPos;
}
...
}
Strutture Dati

Alberi

Implementazione di BinaryTree

public class LinkedBinaryTree<E> implements BinaryTree<E> {


...
protected BTPosition<E> checkPosition(Position<E> v)
throws InvalidPositionException {
if (v == null || !(v instanceof BTPosition))
throw new InvalidPositionException("The position is invalid");
return (BTPosition<E>) v;
}
protected void preorderPositions(Position<E> v,
PositionList<Position<E>> pos)
throws InvalidPositionException {
pos.addLast(v);
if (hasLeft(v))
preorderPositions(left(v), pos);
// recurse on left child
if (hasRight(v))
preorderPositions(right(v), pos);
// recurse on right child
}
...
}
Strutture Dati

Alberi

Implementazione di BinaryTree

public class LinkedBinaryTree<E> implements BinaryTree<E> {


...
/** Restituisce una collezione iterabile dei figli di un nodo. */
public Iterable<Position<E>> children(Position<E> v)
throws InvalidPositionException {
PositionList<Position<E>> children = new NodePositionList<Position<E>>();
if (hasLeft(v))
children.addLast(left(v));
if (hasRight(v))
children.addLast(right(v));
return children;
}
/** Restituisce una collezione iterabile dei nodi di questo albero. */
public Iterable<Position<E>> positions() {
PositionList<Position<E>> positions = new NodePositionList<Position<E>>();
if(size != 0)
preorderPositions(root(), positions); // assegna le posizioni secondo
// una visita preorder
return positions;
}
...
}
Strutture Dati

Alberi

Implementazione di BinaryTree

public class LinkedBinaryTree<E> implements BinaryTree<E> {


...
/** Restituisce un iteratore degli elementi memorizzati nei nodi. */
public Iterator<E> iterator() {
Iterable<Position<E>> positions = positions();
PositionList<E> elements = new NodePositionList<E>();
for (Position<E> pos: positions)
elements.addLast(pos.element());
return elements.iterator(); // Un iteratore degli elementi
}
...
}

Strutture Dati

Alberi

Implementazione di BinaryTree

Abbiamo visto che la classe LinkedBinaryTree ha un costruttore che restituisce


un albero binario vuoto.
A partire da questo albero binario vuoto possiamo costruire un albero binario qualsiasi
prima aggiungendo la radice e
poi via via gli altri nodi usando i seguenti metodi aggiuntivi:
addRoot(e): crea e restituisce un nuovo nodo r contenente l'elemento e,
r diventa la radice dell'albero; si ha una condizione di errore se l'albero non vuoto

insertLeft(v, e): crea e restituisce un nuovo nodo u contenente


l'elemento e; u diventa il figlio sinistro di v; si ha una condizione di errore
se v ha gi il figlio sinistro

insertRight(v, e): crea e restituisce un nuovo nodo u contenente


l'elemento e; u diventa il figlio destro di v; si ha una condizione di errore
se v ha gi il figlio destro

Strutture Dati

Alberi

Implementazione di BinaryTree

remove(v): rimuove il nodo v e lo sostituisce con il suo figlio (se esiste)


e restituisce l'elemento memorizzato in v; si ha una condizione di errore se
v ha due figli

remove(v)

w
b

w
b

attach(v, T1, T2): attacca T1 e T2 rispettivamente


come sottoalbero sinistro e destro del nodo foglia v; si ha una condizione di
errore se v un nodo interno

Strutture Dati

Alberi

Implementazione di BinaryTree

public class LinkedBinaryTree<E> implements BinaryTree<E> {


...
/** Aggiunge un nodo radice ad un albero binario vuoto. */
public Position<E> addRoot(E e) throws NonEmptyTreeException {
if(!isEmpty())
throw new NonEmptyTreeException("L'albero ha gi la radice.");
size = 1;
root = new BTNode<E>(e,null,null,null);
return root;
}
...
}

Strutture Dati

Alberi

Implementazione di BinaryTree

public class LinkedBinaryTree<E> implements BinaryTree<E> {


...
/** Inserisce un figlio sinistro ad un dato nodo. */
public Position<E> insertLeft(Position<E> v, E e)
throws InvalidPositionException {
BTPosition<E> vv = checkPosition(v);
Position<E> leftPos = vv.getLeft();
if (leftPos != null)
throw new InvalidPositionException("Il nodo ha gia` un figlio
sinistro.");
BTPosition<E> ww = new BTNode<E>(e, vv, null, null);
vv.setLeft(ww);
size++;
vv
return ww;
}
...
}

Strutture Dati

ww

Alberi

Implementazione di BinaryTree

public class LinkedBinaryTree<E> implements BinaryTree<E> {


...
/** Rimuove un nodo con zero o un figlio. */
public E remove(Position<E> v)
throws InvalidPositionException {
BTPosition<E> vv = checkPosition(v);
BTPosition<E> leftPos = vv.getLeft();
BTPosition<E> rightPos = vv.getRight();
if (leftPos != null && rightPos != null)
throw new InvalidPositionException("Non posso rimuovere un nodo con due
figli.");
BTPosition<E> ww;
if (leftPos != null)
ww = leftPos;
else if (rightPos != null)
assegna a ww il figlio
ww = rightPos;
di v, se esiste;
else
// ... v una foglia
se v una foglia, ww sar
ww = null;

null

...
}
Strutture Dati

Alberi

Implementazione di BinaryTree

public class LinkedBinaryTree<E> implements BinaryTree<E> {


...
if (vv == root) {
// se v la radice...
if (ww != null)
ww.setParent(null);
root = ww;
//... w diventa la nuova radice
}
else {
// se v non la radice...
BTPosition<E> uu = vv.getParent();
if (vv == uu.getLeft())
uu
uu.setLeft(ww);
else
vv
uu.setRight(ww);
if(ww != null)
ww.setParent(uu);
ww
}
size--;
return v.element();
uu
}
...
}
Strutture Dati

ww

uu
vv
ww

uu
ww

Esercizi
Completare la classe LinkedBinaryTree che implementa l'ADT albero binario
con i rimanenti metodi(insertRight, attach....)

Si scriva un metodo BinaryTree<E> mirror (BinaryTree<E> T, Position<E> v)


che, dato un albero binario T e un nodo v di T, restituisca un nuovo
albero S che rappresenti la copia speculare del sottoalbero di T radicato
in v.
Ad esempio, se invocato sulla radice:

b
c

Strutture Dati

c
e

Alberi

Stampa di espressioni aritmetiche

Specializzazione di una visita inorder

quando visita un nodo stampa


l'operatore o l'operando
corrispondente

stampa ( all'inizio della visita di


un sottoalbero sinistro

stampa ) al termine della visita di


un sottoalbero destro

Algorithm printExpression(v)
if hasLeft (v)
print(()
printExpression (left(v))
print(v.element ())
if hasRight (v)
printExpression (right(v))
print ())

3
a
Strutture Dati

6
10

b
((3 (a 10)) (6 /b))

Alberi

Valutazione di espressioni aritmetiche

Specializzazione di una visita postorder

chiamare ricorsivamente il metodo di


valutazione sui sottoalberi

quando si visita un nodo interno,


combinare i valori dei suoi
sottoalberi

3
a
Strutture Dati

6
10

Algorithm evalExpr(v)
if isLeaf (v)
return v.element ()
else
x = evalExpr(leftChild (v))
y = evalExpr(rightChild (v))
<> = operatore contenuto in v
return x <> y