You are on page 1of 45

Tema 4 rboles.

rboles binarios. Algoritmos bsicos



Algoritmos bsicos con rboles binarios
Recorrido completo.
Creacin.
Terminacin anticipada.
Recorridos especiales.
Manejo de varias estructuras.
Aplicado a objetos de la clase Arbol:
// Escribe las claves del rbol binario en preorden.
static void preOrden (NodoArbol arbol) {
if (arbol != null) {
System.out.print (arbol.clave+" ") ;
preOrden (arbol.iz);
preOrden (arbol.de);
}
}
public void preorden () {
preorden (raiz);
}
Orden de visita de nodos:
1, 2, 4, 9, 15, 5, 3, 8 y 7.

Preferido para:
Bsquedas.
Recorrido en Preorden.
1
3
4
2
5 8 7
9 15
arbol

nombre

r
a
i
z

Aplicado a objetos de la clase Arbol:
// Escribe las claves del rbol binario en orden central.
static void ordenCentral (NodoArbol arbol) {
if (arbol != null) {
ordenCentral (arbol.iz);
System.out.print (arbol.clave+" ");
ordenCentral (arbol.de);
}
}
public void ordenCentral () {
ordenCentral (raiz);
}
Orden de visita de nodos:
9, 4, 15, 2, 5, 1, 8, 3 y 7.
Preferido para:
Recorrido de acuerdo al orden fsico de los nodos.
En rboles binarios de bsqueda recupera la secuencia.
arbol

nombre

r
a
i
z

Recorrido en Orden Central
1
3
4
2
5 8 7
9 15
Aplicado a objetos de la clase Arbol:
// Escribe las claves del rbol binario en postorden.
static void postOrden (NodoArbol arbol) {
if (arbol != null) {
postOrden (arbol.iz);
postOrden (arbol.de);
System.out.print (arbol.clave + " ") ;
}
}
public void postOrden () {
postOrden (raiz);
}
Orden de visita de nodos:
9, 15, 4, 5, 2, 8, 7, 3 y 1.
Preferido para:
Liberar memoria.
Nodos buscados en los niveles
ms bajos del rbol.

Recorrido en Postorden
1
3
4
2
5 8 7
9 15
arbol

nombre

r
a
i
z

Ejemplo: suma de claves
static int sumaClaves (NodoArbol nodoArbol) {
int resul = 0;

if (nodoArbol != null) {
resul = nodoArbol.clave + sumaClaves (nodoArbol.iz);
resul = resul + sumaClaves (nodoArbol.de);
}
return resul;
}
static int sumaClaves (Arbol a) {
return sumaClaves (a.raiz);
}



8
2
3
4
7
9
If (nodoArbol != null)
{
resul =sumaClaves(nodoArbol.iz)+nodoArbol.clave;
resul =resul+sumaClaves(arbol.de);
}
else resul=0
null null
1
2
3
resul=0 4
resul=0+2 5
6
resul=0 7
resul=2+0 = 2
8
resul=2+3 9
10
null null
11
resul=0 12
resul=0+4 13
14
resul=0 15
16 resul=5+4 = 9
6
resul =9+6 17
18
19
null
resul=0 21
20
null
resul=0 23
resul =0+7 22
resul =7+0 = 7 24
resul =7+8 25
26
null
resul=0 28
27
null
resul=0 31
resul=0+9 29
30
resul=9+0 = 9 32
resul =15+9=24
33
34 resul =15+24=39
Recorrido en Amplitud
static void probarAmplitud (Arbol arbol) {
NodoArbol referencia;
ColaArbol colaArbol = new ColaArbol ();

referencia = arbol.raiz;
if (referencia != null)
colaArbol.encolar (referencia);
while (! colaArbol.colaVacia ()) {
referencia = colaArbol.desencolar ();
System.out.print (referencia.clave + " ");
if (referencia.iz != null)
colaArbol.encolar (referencia.iz);
if (referencia.de != null)
colaArbol.encolar (referencia.de);
}
}


Orden de visita de nodos:
1, 2, 3, 4, 5, 8, 7, 9 y 15.
1
3
4
2
5 8 7
9 15
arbol

nombre
r
a
i
z

Arbol
Obtencin de la copia de un rbol
static Arbol copiarArbol (Arbol arbol) {
Arbol resul = new Arbol();
resul.nombre = "Arbol copia";
if (arbol.raiz != null)
resul.raiz = copiaArbol (arbol.raiz);
return resul;
}

static NodoArbol copiaArbol (NodoArbol nodoArbol) {
NodoArbol nuevoNodo = new NodoArbol();

nuevoNodo.clave = nodoArbol.clave;
if (nodoArbol.iz != null)
nuevoNodo.iz = copiaArbol (nodoArbol.iz);
if (nodoArbol.de != null)
nuevoNodo.de = copiaArbol(nodoArbol.de);
return nuevoNodo;
}
Insertar
Criterio de insercin:
Orden de los nodos.
Operacin juntar (join).
Preguntar en qu rama se quiere insertar
No se permite insertar claves repetidas
Bsqueda previa del dato que se quiere insertar para
evitar repeticiones.
Se inserta cuando alcanzamos el nivel ms
profundo (nodos hojas) de la rama seleccionada.
Insercin en rbol binario genrico
static public void juntar (Arbol arbol, int dato, Arbol a1, Arbol a2) {
if (a1.raiz == a2.raiz && a1.raiz != null)
System.out.println ("no se pueden juntar, a1 y a2 son iguales") ;
else {
arbol.raiz = new NodoArbol () ;
arbol.raiz.clave = dato;
arbol.raiz.iz = a1.raiz;
arbol.raiz.de = a2.raiz;
if (arbol != a1)
a1.raiz = null;
if (arbol != a2)
a2.raiz = null;
}
}
Insercin en rbol binario de bsqueda.
static NodoArbol insertar (NodoArbol arbol, int dato) {
NodoArbol resul = arbol;
if (arbol != null)
if (arbol.clave < dato)
arbol.de = insertar (arbol.de, dato);
else if (arbol.clave > dato)
arbol.iz = insertar (arbol.iz, dato);
else System.out.println ("la clave ya existe");
else resul = new NodoArbol (dato);
return resul;
}

public void insertar (int dato) {
raiz = insertar (raiz, dato);
}

Mtodo de objeto
de Arbol
Mtodo static que
recibe un NodoArbol
y devuelve otro
como resultado
Bsqueda en rbol binario.
boolean encontrar (int dato) {
return encuentra (raiz, dato);
}

static boolean encuentra (NodoArbol nodoArbol, int dato) {
boolean resul;
if (nodoArbol != null)
if (nodoArbol.clave == dato)
resul = true;
else {
resul = encuentra (nodoArbol.iz, dato);
if (!resul)
resul = encuentra (nodoArbol.de, dato);
}
else resul = false;
return resul;
}
Bsqueda en rbol binario de bsqueda.
boolean encontrar (int dato) {
return encuentra (raiz, dato);
}

public static boolean encuentra (NodoArbol nodoArbol, int dato) {
boolean resul = false;

if (nodoArbol != null)
if (nodoArbol.clave == dato)
resul = true;
else if (nodoArbol.clave > dato)
resul = encuentra (nodoArbol.iz, dato);
else resul = encuentra (nodoArbol.de, dato);
return resul;
}
Ejemplo: Verificar que un rbol Binario es
de Bsqueda
static class arbolBusqueda {
static int ant;
static boolean primero = true;
static boolean esBusqueda (NodoArbol arbol) {
boolean resul;
if (arbol == null)
resul = true;
else {
resul = esBusqueda (arbol.iz);
if (primero)
primero = false;
else if (arbol.clave <= ant)
resul = false;
if (resul) {
ant = arbol.clave;
resul = esBusqueda(arbol.de);
}
}
return resul;
}
}
static boolean esBusqueda (Arbol a) {
return arbolBusqueda.esBusqueda (a.raiz);
}
Eliminar una clave (I).
Fase I. Se localiza la clave a eliminar (si existe).
Fase II. Tres posibles situaciones:
Clave est en un nodo hoja:
Liberar memoria (innecesario en Java) y asignar el rbol a null.
Clave tiene un nico descendiente:
Apuntar al subrbol no vaco y liberar memoria (innecesario en
Java).
Clave tiene dos descendientes:
[Orden topolgico anterior] Se localiza el descendiente ms a la
derecha del hijo izquierdo, se sustituye la clave a borrar por la
clave encontrada, se cortocircuita el subrbol izquierdo y se
borra (innecesario en Java) el nodo que contena la clave
sustituida.
Peculiaridades del lenguaje Java.
Causa: Las referencias (punteros) se pasan por valor.
Efecto: Los cambios realizados en la instancia actual
sobre el puntero (NodoArbol) que se recibe como
argumento no surten efecto cuando se retorna a la
instancia de llamada.
Tcnica posible: Construir mtodos que devuelvan
actualizado el puntero (referencia) que se recibe como
argumento.
Ejemplo:
static NodoArbol elimina (NodoArbol nodoArbol, int dato) {
// cuerpo del mtodo que modifica nodoArbol;
return nodoArbol;
}
Eliminar una clave (II).
static void eliminarClave (Arbol arbol, int dato) {
arbol.raiz = eliminarElemento (arbol.raiz, dato);
}
static NodoArbol eliminarElemento (NodoArbol arbol, int elem) {
NodoArbol p;
if (arbol != null)
if (arbol.clave > elem)
arbol.iz = eliminarElemento (arbol.iz, elem);
else if (arbol.clave < elem)
arbol.de = eliminarElemento (arbol.de, elem);
else {
p = arbol;
if (arbol.iz == null)
arbol= arbol.de;
else if (arbol.de == null)
arbol = arbol.iz;
else arbol.iz = eliminar2Hijos (arbol.iz, p);
}
else System.out.println (" la clave buscada no existe");
return arbol;
}

static NodoArbol eliminar2Hijos (NodoArbol arbol, NodoArbol p) {
NodoArbol resul;
if (arbol.de != null) {
resul = arbol;
arbol.de = eliminar2Hijos (arbol.de, p);
}
else {
p.clave = arbol.clave;
resul = arbol.iz;
}
return resul;
}
static void eliminarArbol (Arbol arbol) {
System.out.println ("NOTA: Este algoritmo es innecesario en Java ");
System.out.println (Lo que no sucede en todos los lenguajes");
if (arbol.raiz == null)
System.out.println ("Arbol vacio");
else {
arbol.raiz =eliminaArbol (arbol.raiz);
System.out.println (Faltara 'destruir' la referencia principal (arbol)");
}
}

static NodoArbol eliminaArbol (NodoArbol nodoArbol) {
NodoArbol resul;
if (nodoArbol != null) {
nodoArbol.iz = eliminaArbol (nodoArbol.iz);
nodoArbol.de = eliminaArbol (nodoArbol.de);
System.out.println ("Clave antes de ser eliminada: +nodoArbol.clave);
nodoArbol = null;
resul = nodoArbol;
}
else resul = null;
return resul;
}
Eliminar un rbol.
Condicin de hoja:
(nodoArbol.iz == null) && (nodoArbol.de == null)
Ejemplo: Devuelve el nmero de hojas de un rbol

static int cuentaHojas (Arbol arbol) {
return contarHojas (arbol.raiz);
}

static int contarHojas (NodoArbol nodoArbol) {
int resul = 0;
if (nodoArbol != null)
if ((nodoArbol.iz == null) && (nodoArbol.de == null))
resul = 1;
else resul = contarHojas (nodoArbol.iz) + contarHojas (nodoArbol.de);
return resul;
}
Tratamiento de hojas. Ejemplo.
Mecanismo:
Se pasa un argumento entero (inicializado a 1) que se incrementa
en cada llamada.
Ejemplo:
static void clavesNiveles (Arbol arbol) {
clavesNiveles (arbol.raiz,1);
}

static void clavesNiveles (NodoArbol nodoArbol, int n) {
if (nodoArbol != null) {
System.out.println ("Clave: + nodoArbol.clave + " en el nivel: + n);
clavesNiveles (nodoArbol.iz, n+1);
clavesNiveles (nodoArbol.de, n+1);
}
}
Constancia de nivel. Recorrido en
profundidad (I)
Ejemplo: Mtodo que devuelve la altura de un rbol.

static int pruebaAltura (Arbol arbol) {
int resul = 0;
if (arbol.raiz != null)
resul = Altura.altura (arbol.raiz,1);
return resul;
}
static int altura (NodoArbol nodoArbol, int n, int altura) {
int resulIz, resulDe;
if (nodoArbol != null) {
if (n > altura)
altura = n;
resulIz = altura (nodoArbol.iz, n+1, altura);
resulDe = altura (nodoArbol.de, n+1, altura);
altura = Math.max (resulIz, resulDe);
}
return altura;
}
Constancia de nivel. Recorrido en
profundidad (II)
Dos opciones:
Iteracin anidada en dos niveles.
Modificar la cola de referencias a nodos del rbol para
que incluya una variable con el nivel.




Constancia de nivel. Recorrido en amplitud (I).
Sin modificar la cola de referencias.
Dos iteraciones:
Externa que recorre el rbol en niveles
Interna que visita los nodos en amplitud
Variables:
contador: controla el recorrido del nivel
actual: amplitud del nivel
siguiente: nmero de hijos del siguiente nivel
Constancia de nivel. Recorrido en amplitud (II)
static void ListarAmplitud (Arbol arbol) {
Cola c = new tad_cola ();
int actual, siguiente, contador, altura;
NodoArbol p p = arbol.raiz;
altura = 0;
siguiente = 1;
p = arbol;
if (p != null )
c.encolar (p);
while (!c.colaVacia()) {
actual = siguiente;
siguiente = 0;
contador = 1;
altura++;
while (contador <= actual) {
p = c.desencolar ();
System.out.println ("clave: "+p.clave+" nivel: "+altura);
contador++;
if (p.iz != null) {
c.encolar (p.iz);
siguiente++;
}
if (p.de != null) {
c.encolar (p.de);
siguiente++;
}
}
}
}
1
3
4
2
5 8
Arbol.raiz
p
1
altura = 0
siguiente =1;
static void ListarAmplitud (Arbol arbol) {
Cola c = new tad_cola ();
int actual, siguiente, contador, altura;
c.inicializarCola ();
NodoArbol p = arbol.raiz;
altura = 0;
siguiente = 1;
p = arbol;
if (p != null )
c.encolar (p);
while (!c.colaVacia()) {
actual = siguiente;
siguiente = 0;
contador = 1;
altura++;
while (contador <= actual) {
p = c.desencolar ();
System.out.println ("clave: "+p.clave+" nivel: "+altura);
contador++;
if (p.iz != null) {
c.encolar (p.iz);
siguiente++;
}
if (p.de != null) {
c.encolar (p.de);
siguiente++;
}
}
}
}

1
altura = 0
siguiente =1;
1
3
4
2
5 8
Arbol.raiz
p
actual = 1
siguiente = 0
contador = 0
altura = 1
static void ListarAmplitud (Arbol arbol) {
NodoArbol p p = arbol.raiz;
Cola c = new tad_cola ();
int actual, siguiente, contador, altura;
altura = 0;
siguiente = 1;
c.inicializarCola ();
p = arbol;
if (p != null )
c.encolar (p);
while (!c.colaVacia()) {
actual = siguiente;
siguiente = 0;
contador = 1;
altura++;
while (contador <= actual) {
p = c.desencolar ();
System.out.println ("clave: "+p.clave+" nivel: "+altura);
contador++;
if (p.iz != null) {
c.encolar (p.iz);
siguiente++;
}
if (p.de != null) {
c.encolar (p.de);
siguiente++;
}
}
}
}
1
3
4
2
5 8
Arbol.raiz
p
clave es 1, altura 1
contador = 1
3 2
1
Iteracin interna:
while (contador <= actual)
salimos de la iteracin interna
actual =1
contador =0
altura =1
siguiente = 1
siguiente = 2
static void ListarAmplitud (Arbol arbol) {
NodoArbol p p = arbol.raiz;
Cola c = new tad_cola ();
int actual, siguiente, contador, altura;
altura = 0;
siguiente = 1;
c.inicializarCola ();
p = arbol;
if (p != null )
c.encolar (p);
while (!c.colaVacia()) {
actual = siguiente;
siguiente = 0;
contador = 1;
altura++;
while (contador <= actual) {
p = c.desencolar ();
System.out.println ("clave: "+p.clave+" nivel: "+altura);
contador++;
if (p.iz != null) {
c.encolar (p.iz);
siguiente++;
}
if (p.de != null) {
c.encolar (p.de);
siguiente++;
}
}
}
}
1
3
4
2
5 8
Arbol.raiz
P
actual = 2
siguiente = 0
contador = 0
altura = 2
3 2
while (contador <= actual)
siguiente = 1
1
3
4
2
5 8
P
3
2
clave es 2 y altura 2
contador = 1
4 5
siguiente = 2
siguiente =2
altura =1
static void ListarAmplitud (Arbol arbol) {
NodoArbol p p = arbol.raiz;
Cola c = new tad_cola ();
int actual, siguiente, contador, altura;
altura = 0;
siguiente = 1;
c.inicializarCola ();
p = arbol;
if (p != null )
c.encolar (p);
while (!c.colaVacia()) {
actual = siguiente;
siguiente = 0;
contador = 1;
altura++;
while (contador <= actual) {
p = c.desencolar ();
System.out.println ("clave: "+p.clave+" nivel: "+altura);
contador++;
if (p.iz != null) {
c.encolar (p.iz);
siguiente++;
}
if (p.de != null) {
c.encolar (p.de);
siguiente++;
}
}
}
}
iteracin interna:
while (contador <= actual)
siguiente = 3
1
3
4
2
5 8
P
3
clave es 3 y altura 2
4
contador = 2
5 8
---- salimos de la iteracin interna ----
1
3
4
2
5 8
P
clave es 3 y altura 2
4 5 8
actual = 3
siguiente = 0
contador = 0
altura = 3
iteracin interna:
while (contador < =actual)
1
3
4
2
5 8
P
clave es 4 y altura 3
4
5 8
actual = 3
contador = 1
clave es 5 y altura 3
5
8
actual = 3
contador = 2
clave es 8 y altura 3
8
actual = 3
contador = 3
static void ListarAmplitud (Arbol arbol) {
NodoArbol p p = arbol.raiz;
Cola c = new tad_cola ();
int actual, siguiente, contador, altura;
altura = 0;
siguiente = 1;
c.inicializarCola ();
p = arbol;
if (p != null )
c.encolar (p);
while (!c.colaVacia()) {
actual = siguiente;
siguiente = 0;
contador = 1;
altura++;
while (contador <= actual) {
p = c.desencolar ();
System.out.println ("clave: "+p.clave+" nivel: "+altura);
contador++;
if (p.iz != null) {
c.encolar (p.iz);
siguiente++;
}
if (p.de != null) {
c.encolar (p.de);
siguiente++;
}
}
}
}
class tElemento {

int nivel;
NodoArbol nodoArbol;

tElemento (NodoArbol a, int n) {
nivel = n;
nodoArbol = a;
}
}

Constancia de nivel. Recorrido en amplitud (III)

public class ColaArbolModificada {
private NodoColaArbolModificada principio;
private NodoColaArbolModificada fin;

public ColaArbolModificada () {
principio = null;
fin = null;
}
}

Modificando la cola de referencias.
class NodoColaArbolModificada {
NodoColaArbolModificada siguiente;
tElemento elem;

NodoColaArbolModificada () {
elem = null;
siguiente = null;
}
}



static void listarAmplitud (Arbol arbol) {
NodoArbol p;
int nivel;
ColaArbolModificada cola = new ColaArbolModificada();
p = arbol.raiz;
if (p != null) {
tElemento elem = new tElemento (referencia, 1);
cola.encolar(elem);
while (! cola.colaVacia()) {
elem = cola.desencolar ();
p = elem.nodoArbol;
nivel = elem.nivel;
System.out.println("nivel: "+nivel+" "+p.clave+" ");
if (p.iz != null) {
elem = new tElemento(p.iz,nivel+1);
cola.encolar(elem);
}
if (p.de != null) {
elem = new tElemento (p.de, nivel+1);
cola.encolar(elem);
}
}
}
}
Constancia de nivel. Recorrido en amplitud (IV)
Ver codigo
1
3
4
2
5 8
static void listarAmplitud(Arbol arbol) {
NodoArbol referencia;
int nivel;
ColaArbolModificada cola = new ColaArbolModificada();
p = arbol.raiz;
if (p != null) {
tElemento elem = new tElemento (p, 1);
cola.encolar(elem);
while (! cola.colaVacia()) {
elem = cola.desencolar();
p = elem.nodoArbol;
nivel = elem.nivel;
System.out.println("nivel: "+nivel+" "+p.clave+" ");
if (p.iz != null) {
elem = new tElemento (p.iz, nivel+1);
cola.encolar (elem);
}
if (p.de != null) {
elem = new tElemento(p.de, nivel+1);
cola.encolar(elem);
}
}
}
}

nodoArbol
p
1 1
1
3
4
2
5 8
nodoArbol
p
1 1
p = 1
nivel =1;
clave 1, Nivel 1
2 2 3 2

while (! cola.colaVacia()) {
elem = cola.desencolar();
referencia = elem.nodoArbol;
nivel = elem.nivel;
System.out.println("nivel: "+nivel+" "+p.clave+" ");
if (p.iz != null) {
elem = new tElemento (p.iz,nivel+1);
cola.encolar(elem);
}
if (p.de != null) {
elem = new tElemento (p.de,nivel+1);
cola.encolar(elem);
}
}
1
3
4
2
5 8
nodoArbol
p
p = 2
nivel =2;
clave 1, nivel 1
clave 2, nivel 2
2 2
3 2 4 3 5 3
1
3
4
2
5 8
nodoArbol
p
p = 3
nivel =3;
clave 1, nivel 1
clave 2, nivel 2
3 2
4 3 5 3 8 3

while (! cola.colaVacia()) {
elem = cola.desencolar();
referencia = elem.nodoArbol;
nivel = elem.nivel;
System.out.println("nivel: "+nivel+" "+p.clave+" ");
if (p.iz != null) {
elem = new tElemento (p.iz,nivel+1);
cola.encolar(elem);
}
if (p.de != null) {
elem = new tElemento (p.de,nivel+1);
cola.encolar(elem);
}
}
1
3
4
2
5 8
nodoArbol
p
p = 4; n =2;
clave 1, nivel 1
clave 2, nivel 2
clave 3, nivel 2
clave 4, nivel 3
4 3
5 3 8 3
1
3
4
2
5 8
nodoArbol
p
p = 5; n =3;
clave 1, nivel 1
clave 2, nivel 2
clave 3, nivel 2
clave 4, nivel 3
clave 5, nivel 3
5 3
8 3

while (! cola.colaVacia()) {
elem = cola.desencolar();
referencia = elem.nodoArbol;
nivel = elem.nivel;
System.out.println("nivel: "+nivel+" "+p.clave+" ");
if (p.iz != null) {
elem = new tElemento (p.iz,nivel+1);
cola.encolar(elem);
}
if (p.de != null) {
elem = new tElemento (p.de,nivel+1);
cola.encolar(elem);
}
}

1
3
4
2
5 8
nodoArbol
p
p = 8; n =3;
clave 1, nivel 1
clave 2, nivel 2
clave 3, nivel 2
clave 4, nivel 3
clave 5, nivel 3
Clave 8, nivel 3
8 3
Verificar si dos rboles son iguales
static boolean pruebaIguales (Arbol arboA, Arbol arbolB) {
return sonIguales (arbol1.raiz, arbol2.raiz);
}

static boolean sonIguales (NodoArbol a, NodoArbol b) {
boolean resul ;

if ((a == null) && (b == null))
resul = true;
else if ((a == null) || (b == null))
resul = false;
else if (a.clave == b.clave)
resul = sonIguales (a.iz, b.iz) && sonIguales (a.de, b.de);
else resul = false;
return resul;
}
Arbol Binario de Bsqueda contenido en
lista
static boolean estaContenido (NodoArbol nodoArbol, NodoLista nodoLista) {
boolean seguir, saltar;

if (nodoArbol == null)
seguir = true;
else {
seguir = estaContenido (nodoArbol.iz, nodoLista);
if (seguir && (nodoLista != null))
if (nodoArbol.clave < nodoLista.clave)
seguir = false;
else {
saltar = true;
while ((nodoLista != null) && saltar)
if (nodoArbol.clave == nodoLista.clave)
saltar = false;
else nodoLista = nodoLista.sig;
if (!saltar)
seguir = estaContenido (nodoArbol.de, nodoLista.sig);
else seguir = false;
}
else seguir = false;
}
return seguir;
}
static boolean estaContenido (Arbol arbol, Lista lista) {
return estaContenido (arbol.raiz, lista.inicio);
}

You might also like