Algoritmos y Lenguaje de Programación, Sección 1 Árboles Árboles • Árboles • Estructura recursiva )Árbol vacío )0 o más árboles hijos Mario Medina C. [email protected] • Altura ilimitada • Árbol binario )A lo más dos hijos: izquierdo y derecho Árboles Árboles binarios de búsqueda 20 Raíz 12 • Árbol binario de búsqueda • Cada nodo almacena un valor 25 16 28 5 14 9 17 15 26 Hojas 29 Hojas Árbol binario de búsqueda 20 < 12 < 5 Inserción en un árbol • Si árbol está vacío Raíz )Insertar valor como nodo raíz > 25 • Caso contrario > > 16 28 > > 9 17 < )Si nuevo valor es menor que valor del nodo actual ` Insertar nuevo valor en el subárbol a la izquierda del nodo actual > 26 29 Hojas ©Mario Medina C. )mayor que todos los valores almacenados en el subárbol izquierdo )menor que todos los valores almacenados en el subárbol derecho )No almacena valores duplicados )Ideales para búsqueda )Si nuevo valor es mayor que valor del nodo actual ` Insertar nuevo valor en el subárbol a la derecha del valor actual 1 Algoritmos y Lenguaje de Programación, Sección 1 Inserción Remoción en un árbol 20 12 5 • Nodo sin hijos Raíz )Eliminación directa • Nodo con un nodo hijo 25 )Nodo padre hereda al nodo hijo • Nodo con dos hijos 28 16 )Buscar el nodo de mayor valor en el hijo izquierdo 9 15 17 26 Hojas 29 Hojas Búsqueda en un árbol Remover raíz 17 • Búsqueda en árboles binarios es rápida Raíz 12 5 1. Comparar valor buscado con la raíz ` Si es igual, algoritmo termina 25 15 17 26 Hojas 29 • Varias formas de recorrer un árbol ) Pre-orden 1. Visita primero la raíz 2. Luego el subárbol izquierdo 3. Finalmente, el subárbol derecho ) Post-orden 1. Visita primero el subárbol izquierdo 2. Luego el subárbol derecho 3. Finalmente, visita la raíz • Algoritmo iterativo o recursivo! Hojas Recorrido de un árbol ©Mario Medina C. 2. Si valor de la raíz es mayor que valor buscado, buscar en subárbol izquierdo 3. Si valor de la raíz es menor que el valor buscado, buscar en subárbol derecho 28 16 9 ` Reemplazar el valor del nodo raíz por mayor valor ` Eliminar el nodo de mayor valor Recorrido de un árbol ) In-orden 1. Visita primero el subárbol izquierdo 2. Luego la raíz 3. Finalmente, el subárbol derecho ) Por niveles 1. 2. 3. 4. Visita primero la raíz Luego los dos hijos de la raíz Luego los dos hijos de cada hijo de la raíz Luego los hijos de éstos, y así hasta llegar a las hojas 2 Algoritmos y Lenguaje de Programación, Sección 1 Ejemplos de recorridos Ejemplos de recorridos 20 12 5 • Pre-Orden Raíz )20, 12, 5, 9, 16, 17, 25, 28, 26, 29 • In-Orden 25 )5, 9, 12, 16, 17, 20, 25, 26, 28, 29 • Post-Orden 28 16 )9, 5, 17, 16, 12, 26, 29, 28, 25, 20 9 17 26 Hojas 29 Hojas Implementación de árboles /* Estructura para un nodo */ typedef struct NODOARBOL { int valor; struct NODOARBOL *izq; struct NODOARBOL *der; } NodoArbol; /* Raiz del arbol */ NodoArbol *raiz; Inserción iterativa (1) void inserta(NodoArbol *raiz, int valor) { NodoArbol *nodo, **temp; temp = &raiz; while((nodo = *temp) != NULL) { if(valor < nodo->valor) temp = &nodo->izq; else temp = &nodo->der; } /* Continúa */ ©Mario Medina C. • Por Niveles )20, 12, 25, 5, 16, 28, 9, 17, 26, 29 Búsqueda iterativa int *buscar(NodoArbol *nodo, int valor) { while(nodo != NULL && nodo->valor != valor) { if (valor < nodo->valor) nodo = nodo->izq; else nodo = nodo->der; } if (nodo != NULL) return TRUE; else return FALSE; } Inserción iterativa (2) nodo = malloc(sizeof(NodoArbol)); assert(nodo != NULL); nodo->valor = valor; nodo->izq = NULL; nodo->der = NULL; *temp = nodo; } 3 Algoritmos y Lenguaje de Programación, Sección 1 Búsqueda recursiva int *buscar(NodoArbol *nodo, int valor) { if (nodo == NULL) return FALSE; if (nodo->valor == valor) return TRUE; if (nodo->valor > valor) return buscar(nodo->izq, valor); else return buscar(nodo->der, valor); } Inserción recursiva (2) if (valor < nodo->valor) nodo->izq = insertar(nodo->izq, valor); else nodo->der = insertar(nodo->der, valor); } Inserción recursiva (1) NodoArbol *insertar(NodoArbol *nodo, int valor) { NodoArbol *temp; if (nodo == NULL) { temp = malloc(sizeof(NodoArbol)); temp->izq = NULL; temp->der = NULL; temp->valor = valor; return temp; } /* Continúa */ Tamaño de un árbol • Calcula el número de nodos de un árbol int tamano(NodoArbol *nodo) { if (nodo == NULL) return 0; return tamano(nodo->izq) + 1 + tamano(nodo->der); return nodo; } /* Funcion retorna puntero a nueva raiz */ } Profundidad de un árbol Mínimo valor en un árbol • Calcula camino más largo en un árbol • Encuentra el valor mínimo en un árbol int profundidad(NodoArbol *nodo) { int profIzq, profDer; if (nodo == NULL) return 0; profIzq = profundidad(nodo->izq); profDer = profundidad(nodo->der); return (profIzq > profDer) ? profIzq + 1 : profDer + 1; } ©Mario Medina C. )No se requiere revisar todo el árbol )Sólo revisar los hijos izquierdos int minValor(NodoArbol *nodo) { NodoArbol *actual = nodo; if (actual == NULL) return 0; while (actual->izq != NULL) actual = actual->izq; return actual->dato; } 4 Algoritmos y Lenguaje de Programación, Sección 1 Imprimir un árbol Imprimir un árbol en post-orden • Imprime el árbol en in-orden • Imprime el árbol en post-orden )Orden creciente de los valores void imprime(NodoArbol *nodo) { if (nodo == NULL) return; imprime(nodo->izq); printf(“%d ”, nodo->valor); imprime(nodo->der); } Orden de operaciones en un árbol void imprime(NodoArbol *nodo) { if (nodo == NULL) return; imprime(nodo->izq); imprime(nodo->der); printf(“%d ”, nodo->valor); } Búsqueda binaria • Buscar en un árbol de búsqueda binario es orden O(log2 n) • Cada nodo visitado desde la raíz divide el árbol en dos )1 nodo → 2 divisiones )2 nodos → 4 divisiones )3 nodos → 8 divisiones )4 nodos → 16 divisiones 20 Raíz 12 5 25 28 16 9 17 26 Hojas 29 Hojas Orden: árbol de búsqueda binario Orden de operaciones en un árbol • Buscar un elemento: O(log n) • Insertar un elemento: O(n) • Encontrar el tamaño del árbol: O(n) • Encontrar la profundidad del árbol: O(n) • Encontrar menor elemento: O(log n) • Imprimir el árbol: O(n) Y si el árbol no está balanceado? • Peor caso: Buscar en un árbol es orden O(n) ©Mario Medina C. )Árbol binario no está necesariamente balanceado 12 16 17 18 5 Algoritmos y Lenguaje de Programación, Sección 1 Árboles balanceados Árboles B (B-Trees) • Garantizan comportamiento O(log n) • Árboles n-arios balanceados )Código de operaciones típicas es más complejo ` Más eficientes si se opera sobre muchos datos )Árboles AVL ` Diferencia entre altura de árboles hijos es a lo más 1 )Árboles Rojo-Negro ` Camino más largo es a los más dos veces el camino más corto )Árboles 2-3 )Usados en sistemas de archivos y bases de datos )Optimizados para sistemas donde sólo una parte del árbol puede residir en memoria principal ` El resto del árbol se almacena en disco )Nodos pueden tener un número variable de hijos )Todas las hojas del árbol están a la misma altura ` Operaciones de inserción y remoción son O(log n) ` Log2 n < altura < Log3 n ©Mario Medina C. 6