È un albero binario in cui per ogni nodo le chiavi del sottoalbero sinistro sono minori della chiave del nodo corrente e quelle del sottoalbero destro sono più grandi. Non possono esserci duplicati.
Si può utilizzare per implementare i dizionari.
Implementazioni dell’algoritmo di ricerca
def ricerca_iterativa(nodo, query):
while nodo is not None:
if nodo.key == query: # valore trovato
return nodo
if nodo.key < query: # il valore corrente è minore di quello da trovare
nodo = nodo.right
else: # il valore corrente è maggiore di quello da trovare
nodo = nodo.left
return None # valore non trovato
def ricerca_ricorsiva(nodo, query):
if nodo.key == None:
return False
if nodo.key == query:
return nodo
if nodo.key < query:
return ricerca_ricorsiva(nodo.right, query)
else:
return ricerca_ricorsiva(nodo.left, query)
Inserimento e cancellazione di un nodo in
Inserimento
def inserimento(nodo, to_add):
if nodo is None:
return Nodo(to_add)
if to_add < nodo.key:
if nodo.left is None:
nodo.left = Nodo(to_add)
else:
inserimento(nodo.left, to_add)
elif to_add > nodo.key:
if nodo.right is None:
nodo.right = Nodo(to_add)
else:
inserimento(nodo.right, to_add)
# If to_add == nodo.key: non fare niente (no duplicati)
return nodo
Cancellazione
Abbiamo tre casi:
- Il nodo da cancellare non ha figli: si elimina direttamente
- Il nodo da cancellare ha solo un figlio: si fa un bypass tra il suo padre e il figlio, eliminando quello intermedio
- Il nodo da cancellare ha due figli: si cancella il valore sostituendo quello del successore e si scende a cancellare il successore (che sarà una foglia o un nodo con un solo figlio, quello destro).
def cancellaABR(root, x):
if root is None:
return None
nodo = root
genitore = None
# Cerca iterativamente il nodo da cancellare
while nodo is not None and nodo.key != x:
genitore = nodo
if x < nodo.key:
nodo = nodo.left
else:
nodo = nodo.right
if nodo is None:
return root # Nodo non trovato
# Caso 1: il nodo da cancellare è una foglia
if nodo.left is None and nodo.right is None:
if genitore is None:
return None
elif genitore.left == nodo:
genitore.left = None
else:
genitore.right = None
# Caso 2: Il nodo da cancellare ha un solo figlio
elif nodo.left is None or nodo.right is None:
# Determina il figlio da mantenere
if nodo.left is not None:
figlio = nodo.left
else:
figlio = nodo.right
if genitore is None:
return figlio # La radice cambia
elif genitore.left == nodo:
genitore.left = figlio
else:
genitore.right = figlio
# Caso 3: il nodo da cancellare ha due figli
else: # Trova il succcessore (minimo del sottoalbero destro)
successore_gen = nodo
succcessore = nodo.right
while successore.left:
successore_gen = successore
successore = successore.left
# Copia la chiave del successore del nodo
nodo.key = successore.key
# Rimuovi il successore dal suo posto
if succcessore_gen.left == successore:
successore_gen.left = successore.right
else:
successore_gen.right = successore.right
return root