Descargar la presentación
La descarga está en progreso. Por favor, espere
1
Árboles binarios. Algoritmos básicos
Tema 3 Árboles. Árboles binarios. Algoritmos básicos Curso 2014/2015 ETSISI UPM
2
Algoritmos básicos con árboles binarios
Recorrido completo. Creación. Terminación anticipada. Recorridos especiales. Manejo de varias estructuras.
3
RECORRIDO COMPLETO.
4
Recorrido en Preorden. Aplicado a objetos de la clase Arbol:
Orden de visita de nodos: 1, 2, 4, 9, 15, 5, 3, 8 y 7. Preferido para: Búsquedas. void preOrden (pNodoArbol nodo) { if (nodo != NULL) { cout << nodo->clave << " "; // Nodo preOrden (nodo->iz); // Izquierda preOrden (nodo->de); // Derecha } void Arbol::recorrerPreOrden (){ preOrden (raiz); Arbol raiz 1 3 4 2 5 8 7 9 15
5
Recorrido en Orden Central
Arbol Aplicado a objetos de la clase Arbol: 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. raiz void ordenCentral (pNodoArbol nodo) { if (nodo != NULL) { ordenCentral (nodo->iz); // Izquierda cout << nodo->clave << " "; // Nodo ordenCentral (nodo->de); // Derecha } void Arbol::recorrerOrdenCentral(){ ordenCentral (raiz); 1 3 4 2 5 8 7 9 15
6
Recorrido en Postorden
Aplicado a objetos de la clase Arbol: 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. Arbol void postOrden (pNodoArbol nodo) { if (nodo != NULL) { postOrden (nodo->iz); // Izquierda postOrden (nodo->de); // Derecha cout << nodo->clave << " "; // Nodo } void Arbol::recorrerPostOrden (){ postOrden (raiz); raiz 1 3 4 2 5 8 7 9 15
7
Ejemplo: suma de claves
int sumarClaves (pNodoArbol nodo){ int resul; if (nodo != NULL) { resul = sumarClaves(nodo->iz) + nodo->clave; resul = resul + sumarClaves(nodo->de); } else resul = 0; return resul; } int Arbol::sumaClaves (){ return sumarClaves (raiz);
8
34 resul =15+24=39 Arbo l null null null null null null null null
If (nodo != null) { resul = sumarClaves(nodo->iz) + nodo->clave; resul = resul + sumarClaves(nodo->de); } else resul=0 raiz 34 resul =15+24=39 resul =9+6 17 6 1 18 16 resul=5+4 = 9 resul =15+9=24 33 resul=2+3 9 resul =7+8 25 3 8 2 10 19 26 resul=2+0 = 2 8 resul =7+0 = 7 24 resul=0+4 13 resul=0+2 5 resul =0+7 22 4 2 3 7 11 20 6 14 null null null null null null resul=0 4 resul=0 7 resul=0 21 resul=0 23 resul=0 15 resul=0 12 resul=9+0 = 9 32 resul=0+9 29 9 30 27 null null resul=0 28 resul=0 31
9
Recorrido en Amplitud Orden de visita de nodos:
void Arbol::amplitud (){ pNodoArbol p; Cola c; cout << "Amplitud: "; p = raiz; if (p != NULL) c.encolar (p); while (! c.colaVacia ()) { p = c.desencolar (); cout << p->clave << " "; if (p->iz != NULL) c.encolar (p->iz); if (p->de != NULL) c.encolar (p->de); } cout << endl; Orden de visita de nodos: 1, 2, 3, 4, 5, 8, 7, 9 y 15. Se requiere la utilización de la técnica iterativa así como de un TAD cola cuyos nodos contienen como información un puntero a un árbol Arbol raiz 1 3 4 2 5 8 7 9 15 class NodoCola { public: pNodoArbol dato; NodoCola *siguiente; NodoCola (pNodoArbol elemento, NodoCola *n) { dato = elemento; siguiente = n; } };
10
CREACIÓN.
11
Insertar Criterio de inserción:
Orden de los nodos. Operación juntar (join). Preguntar en qué rama se quiere insertar … No se permite insertar claves repetidas Bú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.
12
Inserción en árbol binario genérico
void Arbol::juntar (Arbol aizq, Arbol ader){ pNodoArbol pizq = aizq.raiz; pNodoArbol pder = ader.raiz; if (pizq == pder && pizq != NULL) cout << "Error : izquierda y derecha son el mismo nodo" << endl; else { raiz->iz = pizq; raiz->de = pder; } void juntarRacimos(Arbol &arbol){ Arbol a1 = Arbol(1); Arbol a3 = Arbol(3); Arbol a2 = Arbol(2); Arbol a5 = Arbol(5); Arbol a7 = Arbol(7); Arbol a6 = Arbol(6); a2.juntar(a1, a3); a6.juntar(a5, a7); arbol.juntar (a2, a6); } int main () { Arbol a = Arbol(4); juntarRacimos (a);
13
Inserción en árbol binario de búsqueda.
void inserta(pNodoArbol &nodo, int valor){ if (nodo == NULL) nodo = new NodoArbol(valor); else if (valor != nodo->clave) { if (valor < nodo->clave) inserta(nodo->iz,valor); inserta(nodo->de,valor); } cout << "Error, la clave ya existe" << endl; void Arbol::insertar(int x){ inserta(raiz, x);
14
TERMINACIÓN ANTICIPADA
15
Búsqueda en árbol binario.
bool buscar (pNodoArbol nodo, int n){ bool resul = false; if (nodo != NULL){ if (nodo->clave == n) resul = true; else { resul = buscar (nodo->iz, n); if (!resul) resul = buscar (nodo->de, n); } return resul; bool Arbol::busqueda (int n){ return buscar (raiz, n);
16
Búsqueda en árbol binario de búsqueda.
bool buscar (pNodoArbol nodo, int n){ bool resul = false; if (nodo != NULL){ if (nodo->clave == n) resul = true; else { if (nodo->clave > n) resul = buscar (nodo->iz, n); else resul = buscar (nodo->de, n); } return resul; bool Arbol::busqueda (int n){ return buscar (raiz, n);
17
Ejemplo: Verificar que un árbol Binario es de Búsqueda
bool esArbolBusqueda (pNodoArbol nodo, bool& primero, int& anterior){ bool resul = true; if (nodo != NULL){ resul = esArbolBusqueda (nodo->iz, primero, anterior); if (primero) primero = false; else { if (nodo->clave <= anterior) resul = false; } if (resul){ anterior = nodo->clave; resul = esArbolBusqueda (nodo->de, primero, anterior); return resul; bool Arbol::arbolBusqueda (){ int a; bool b = true; return esArbolBusqueda(raiz, b, a);
18
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 y asignar el árbol a null. Clave tiene un único descendiente: Apuntar al subárbol no vacío y liberar memoria. 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 el nodo que contenía la clave sustituida.
20
Eliminar una clave (III).
void elimina (pNodoArbol &nodo, int valor ){ pNodoArbol hijo; if (nodo != NULL) { if (valor == nodo->clave) if ((nodo->iz == NULL) || (nodo->de == NULL)) { if (nodo->iz == NULL) hijo = nodo->de; else hijo = nodo->iz; delete nodo; nodo = hijo; } quitarSucesor (nodo, nodo->iz); if (valor < nodo->clave) elimina (nodo->iz, valor); elimina (nodo->de, valor); else cout << "la clave buscada no existe" << endl;
21
Eliminar una clave (IV).
void quitarSucesor (pNodoArbol &nodoQuitar, pNodoArbol &sucesor) { pNodoArbol hijo; if (sucesor->de == NULL) { hijo = sucesor->iz; nodoQuitar->clave = sucesor->clave; delete sucesor; sucesor = hijo; } else quitarSucesor (nodoQuitar, sucesor->de); void Arbol::eliminar(int x){ elimina(raiz, x);
22
Recorridos especiales
23
Tratamiento de hojas. Ejemplo.
Condición de hoja: (nodo.iz == null) && (nodo.de == null) Ejemplo: Devuelve el número de hojas de un árbol int contarHojas (pNodoArbol nodo){ int resul = 0; if (nodo != NULL){ if (nodo->iz==NULL && nodo->de==NULL) resul = 1; else resul = contarHojas (nodo->iz) + contarHojas (nodo->de); } return resul; int Arbol::cuentaHojas (){ return contarHojas (raiz);
24
Constancia de nivel. Recorrido en profundidad
Mecanismo: Se pasa un argumento entero (inicializado a 1) que se incrementa en cada llamada. Ejemplo: void obtenerclavesNiveles (pNodoArbol nodo, int nivel){ if (raiz != NULL){ cout << "Clave: " << nodo->clave << " en el nivel: " << nivel << endl; obtenerclavesNiveles (nodo->iz, nivel+1); obtenerclavesNiveles (nodo->de, nivel+1); } void Arbol::clavesNiveles (){ obtenerclavesNiveles (raiz, 1);
25
Constancia de nivel. Recorrido en amplitud (I).
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.
26
Constancia de nivel. Recorrido en amplitud (II)
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
27
↑1 altura = 1 nodosSiguiente =1; void Arbol::amplitudNiveles (){
Cola c; pNodoArbol p; int nodosActual, nodosSiguiente, contadorNodos, altura; altura = 1; if (raiz != NULL){ c.encolar(raiz); nodosSiguiente = 1; } while (!c.colaVacia()){ nodosActual = nodosSiguiente; nodosSiguiente = 0; contadorNodos = 1; while (contadorNodos<=nodosActual){ contadorNodos++; p = c.desencolar(); cout << p->clave << " nivel: " << altura << endl; if (p->iz != NULL){ c.encolar(p->iz); nodosSiguiente++; if (p->de != NULL){ c.encolar(p->de); altura++; 1 3 4 2 5 8 Arbol.raiz p ↑1 altura = 1 nodosSiguiente =1;
28
altura = 1 nodosSiguiente = 1; ↑1 nodosActual = 1 nodosSiguiente = 0
void Arbol::amplitudNiveles (){ Cola c; pNodoArbol p; int nodosActual, nodosSiguiente, contadorNodos, altura; altura = 1; if (raiz != NULL){ c.encolar(raiz); nodosSiguiente = 1; } while (!c.colaVacia()){ nodosActual = nodosSiguiente; nodosSiguiente = 0; contadorNodos = 1; while (contadorNodos<=nodosActual){ contadorNodos++; p = c.desencolar(); cout << p->clave << " nivel: " << altura << endl; if (p->iz != NULL){ c.encolar(p->iz); nodosSiguiente++; if (p->de != NULL){ c.encolar(p->de); altura++; altura = 1 nodosSiguiente = 1; Arbol.raiz 1 p 2 3 4 5 8 ↑1 nodosActual = 1 nodosSiguiente = 0 contadorNodos = 1
29
while (contadorNodos <= nodosActual)
void Arbol::amplitudNiveles (){ Cola c; pNodoArbol p; int nodosActual, nodosSiguiente, contadorNodos, altura; altura = 1; if (raiz != NULL){ c.encolar(raiz); nodosSiguiente = 1; } while (!c.colaVacia()){ nodosActual = nodosSiguiente; nodosSiguiente = 0; contadorNodos = 1; while (contadorNodos<=nodosActual){ contadorNodos++; p = c.desencolar(); cout << p->clave << " nivel: " << altura << endl; if (p->iz != NULL){ c.encolar(p->iz); nodosSiguiente++; if (p->de != NULL){ c.encolar(p->de); altura++; nodosActual = 1 contadorNodos = 1 altura = 1 Iteración interna: while (contadorNodos <= nodosActual) Arbol.raiz 1 p 2 3 4 5 8 ↑2 ↑3 ↑1 contador Nodos= 2 clave es 1, altura 1 nodosSiguiente = 1 nodosSiguiente = 2 salimos de la iteración interna altura = 2
30
while (contadorNodos <= nodosActual)
void Arbol::amplitudNiveles (){ Cola c; pNodoArbol p; int nodosActual, nodosSiguiente, contadorNodos, altura; altura = 1; if (raiz != NULL){ c.encolar(raiz); nodosSiguiente = 1; } while (!c.colaVacia()){ nodosActual = nodosSiguiente; nodosSiguiente = 0; contadorNodos = 1; while (contadorNodos<=nodosActual){ contadorNodos++; p = c.desencolar(); cout << p->clave << " nivel: " << altura << endl; if (p->iz != NULL){ c.encolar(p->iz); nodosSiguiente++; if (p->de != NULL){ c.encolar(p->de); altura++; nodosSiguiente =2 altura =2 Arbol.raiz 1 P 2 3 4 5 8 ↑2 ↑3 nodosActual = 2 nodosSiguiente = 0 contadorNodos = 1 while (contadorNodos <= nodosActual) 1 P ↑3 ↑4 ↑5 2 3 4 5 8 ↑2 nodosSiguiente = 1 nodosSiguiente = 2 clave es 2 y altura 2 contadorNodos = 2
31
altura = 3 ↑4 ↑5 ↑8 ↑3 ↑4 ↑5 ↑8 void Arbol::amplitudNiveles (){
Cola c; pNodoArbol p; int nodosActual, nodosSiguiente, contadorNodos, altura; altura = 1; if (raiz != NULL){ c.encolar(raiz); nodosSiguiente = 1; } while (!c.colaVacia()){ nodosActual = nodosSiguiente; nodosSiguiente = 0; contadorNodos = 1; while (contadorNodos<=nodosActual){ contadorNodos++; p = c.desencolar(); cout << p->clave << " nivel: " << altura << endl; if (p->iz != NULL){ c.encolar(p->iz); nodosSiguiente++; if (p->de != NULL){ c.encolar(p->de); altura++; iteración interna: while (contadorNodos <= nodosActual) 1 P ↑4 ↑5 ↑8 2 3 4 5 8 ↑3 nodosSiguiente = 3 clave es 3 y altura 2 contadorNodos = 3 ---- salimos de la iteración interna ---- altura = 3 1 P ↑4 ↑5 ↑8 2 3 4 5 8 nodosActual = 3 nodosSiguiente = 0 contador Nodos= 1
32
↑5 ↑8 ↑4 ↑8 ↑5 ↑8 void Arbol::amplitudNiveles (){ Cola c;
pNodoArbol p; int nodosActual, nodosSiguiente, contadorNodos, altura; altura = 1; if (raiz != NULL){ c.encolar(raiz); nodosSiguiente = 1; } while (!c.colaVacia()){ nodosActual = nodosSiguiente; nodosSiguiente = 0; contadorNodos = 1; while (contadorNodos<=nodosActual){ contadorNodos++; p = c.desencolar(); cout << p->clave << " nivel: " << altura << endl; if (p->iz != NULL){ c.encolar(p->iz); nodosSiguiente++; if (p->de != NULL){ c.encolar(p->de); altura++; nodosActual = 3 nodosSiguiente = 0 contador Nodos= 1 iteración interna: while (contadorNodos <= nodosActual) P 1 ↑5 ↑8 2 3 4 5 8 ↑4 clave es 4 y altura 3 contadorNodos = 2 ↑8 clave es 5 y altura 3 contadorNodos = 3 ↑5 clave es 8 y altura 3 contadorNodos = 4 ↑8
33
Constancia de nivel. Recorrido en amplitud (III)
Modificando la cola de referencias. #include "Arbol.h" #ifndef NODOCOLA_H_ #define NODOCOLA_H_ class NodoCola { public: pNodoArbol dato; int nivel; NodoCola *siguiente; NodoCola(){ dato = NULL; nivel = -1; siguiente = NULL; } NodoCola(pNodoArbol d, int n, NodoCola *sig){ dato = d; nivel = n; siguiente = sig; }; #endif /* NODOCOLA_H_ */
34
Constancia de nivel. Recorrido en amplitud (IV)
void Arbol::amplitudNiveles (){ Cola c; pNodoCola nodoDesencolado; int n = 1; pNodoArbol p; if (raiz != NULL) { pNodoCola nodoEncolar = new NodoCola(raiz, n, NULL); c.encolar(nodoEncolar); while (!c.colaVacia()){ nodoDesencolado = c.desencolar(); n = nodoDesencolado->nivel; p= nodoDesencolado->dato; cout << "la clave es: " << p->clave << " y el nivel: " << n << endl; if (p->iz!= NULL){ pNodoCola nodoEncolar = new NodoCola(p->iz, n+1, NULL); } if (p->de!= NULL){ pNodoCola nodoEncolar = new NodoCola(p->de, n+1, NULL);
35
↑1 1 ↑2 2 ↑3 2 p = ↑1 n =1; clave 1, Nivel 1 ↑1 1 1 3 2 4 5 8 1 2 3 4
nodoArbol 1 p 3 2 4 5 8 ↑1 1 nodoArbol 1 p 2 3 4 5 8 ↑2 2 ↑3 2 p = ↑1 n =1; clave 1, Nivel 1 ↑1 1
36
↑3 2 ↑4 3 ↑5 3 ↑2 2 p = ↑2 n =2; clave 1, nivel 1 clave 2, nivel 2
nodoArbol 1 p 2 3 4 5 8 ↑3 2 ↑4 3 ↑5 3 ↑2 2 p = ↑2 n =2; clave 1, nivel 1 clave 2, nivel 2 nodoArbol p 1 2 3 4 5 8 ↑4 3 ↑5 3 ↑8 3 ↑3 2 p = ↑3 n =3; clave 1, nivel 1 clave 2, nivel 2
37
↑5 3 ↑8 3 p = ↑4; n =2; ↑4 3 clave 1, nivel 1 clave 2, nivel 2
nodoArbol 1 p 2 3 4 5 8 ↑5 3 ↑8 3 p = ↑4; n =2; clave 1, nivel 1 clave 2, nivel 2 clave 3, nivel 2 clave 4, nivel 3 ↑4 3 nodoArbol 1 2 3 4 5 8 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 ↑8 3 ↑5 3
38
p = ↑8; n =3; ↑8 3 clave 1, nivel 1 clave 2, nivel 2 clave 3, nivel 2
nodoArbol 1 2 3 p 4 5 8 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
39
VARIAS ESTRUCTURAS
40
Verificar si dos árboles son iguales
bool igual (pNodoArbol a, pNodoArbol b){ bool resul; if (( a== NULL) && (b == NULL)) resul = true; else { if (( a== NULL) || (b == NULL)) resul = false; if (a->clave == b->clave) resul = igual(a->iz, b->iz) && igual(a->de, b->de); else } return resul; bool igualesContenido (Arbol a, Arbol b){ return igual (a.raiz, b.raiz);
41
Arbol Binario de Búsqueda contenido en lista
bool estaContenido(pNodoArbol nodoArbol, pNodo nodoLista){ bool seguir, saltar; if (nodoArbol == NULL) seguir = true; else{ seguir = estaContenido(nodoArbol->iz, nodoLista); if (seguir && (nodoLista != NULL)){ if (nodoArbol->clave < nodoLista->clave) seguir = false; 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; return seguir; bool estaContenidoEn(Arbol a, ListaOrdenada l){ return estaContenido(a.raiz, l.inicio);
Presentaciones similares
© 2025 SlidePlayer.es Inc.
All rights reserved.