tema 4 Árboles. Árboles binarios. algoritmos básicos

Post on 04-Feb-2015

33 Views

Category:

Documents

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Tema 4 Árboles.

Árboles binarios. Algoritmos básicos

Algoritmos básicos con árboles binarios

Recorrido completo.Creación.Terminación 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:Búsquedas.

Recorrido en Preorden.

1

3

4

2

5 8 7

9 15

arbol nombre

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 físico de los nodos.En árboles binarios de búsqueda recupera la

secuencia.

arbolnombre

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

más bajos del árbol.

Recorrido en Postorden

1

3

4

2

5 8 7

9 15

arbol nombre

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

47

9

If (nodoArbol != null) { resul =sumaClaves(nodoArbol.iz)+nodoArbol.clave; resul =resul+sumaClaves(arbol.de); } else resul=0

null null

1

2

3

resul=04

resul=0+25

6

resul=07

resul=2+0 = 28

resul=2+39

10

null null

11

resul=012

resul=0+413

14

resul=015

16 resul=5+4 = 9

6resul =9+617

18

19

nullresul=021

20

nullresul=023

resul =0+722resul =7+0 = 724

resul =7+825

26

nullresul=028

27

nullresul=031

resul=0+929

30

resul=9+0 = 932

resul =15+9=2433

34 resul =15+24=39

Recorrido en Amplitudstatic 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

Arbol

Obtención de la copia de un árbolstatic 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; }

InsertarCriterio de inserción:

Orden de los nodos.Operación juntar (join).Preguntar en qué rama se quiere insertar …

No se permite insertar claves repetidasBúsqueda previa del dato que se quiere

insertar para evitar repeticiones.

Se inserta cuando alcanzamos el nivel más profundo (nodos hojas) de la rama seleccionada.

Inserción en árbol binario genérico

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; } }

Inserción en árbol binario de búsqueda.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);

}

Método de objeto de Arbol

Método static que recibe un NodoArbol

y devuelve otro como resultado

Búsqueda 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;}

Búsqueda en árbol binario de búsqueda.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 Búsqueda

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 subárbol no vacío y liberar memoria

(innecesario en Java).

Clave tiene dos descendientes: [Orden topológico anterior] Se localiza el descendiente

más a la derecha del hijo izquierdo, se sustituye la clave a borrar por la clave encontrada, se “cortocircuita” el subárbol izquierdo y se borra (innecesario en Java) el nodo que contenía 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.

Técnica posible: Construir métodos que devuelvan actualizado el puntero (referencia) que se recibe como argumento. Ejemplo:

static NodoArbol elimina (NodoArbol nodoArbol, int dato) { // cuerpo del método 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 (“Faltaría '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.

Condición de hoja:(nodoArbol.iz == null) && (nodoArbol.de == null)

Ejemplo: Devuelve el número 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: Método 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:Iteración 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: número 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 = 1siguiente = 0contador = 0altura = 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 1contador = 1

↑3↑2

↑1

Iteración interna:

while (contador <= actual)

salimos de la iteración interna

actual = 1contador = 0altura = 1

siguiente = 1siguiente = 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 = 2siguiente = 0contador = 0altura = 2

↑3↑2

while (contador <= actual)

siguiente = 1

1

3

4

2

5 8

P

↑3

↑2

clave es 2 y altura 2contador = 1

↑4 ↑5

siguiente = 2

siguiente =2altura =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++;

}}

}}

iteración 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 iteración interna ----

1

3

4

2

5 8

P

clave es 3 y altura 2

↑4 ↑5 ↑8

actual = 3siguiente = 0contador = 0altura = 3

iteración interna: while (contador < =actual)

1

3

4

2

5 8

P

clave es 4 y altura 3

↑4

↑5 ↑8

actual = 3contador = 1

clave es 5 y altura 3↑5

↑8 actual = 3contador = 2

clave es 8 y altura 3↑8

actual = 3contador = 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 1p = ↑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 1clave 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 1clave 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 1clave 2, nivel 2clave 3, nivel 2clave 4, nivel 3

↑4 3

↑5 3 ↑8 3

1

3

4

2

5 8

nodoArbol

p

p = ↑5; n =3;clave 1, nivel 1clave 2, nivel 2clave 3, nivel 2clave 4, nivel 3clave 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 1clave 2, nivel 2clave 3, nivel 2clave 4, nivel 3clave 5, nivel 3Clave 8, nivel 3

↑8 3

Verificar si dos árboles son igualesstatic 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 Búsqueda 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);}

top related