TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS ESTRUCTURA DE DATOS JERÁRQUICAS TEORÍA GENERAL DE ARBOLES Hermes Mosquera Julio de 2013 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Contenido ESTRUCTURA DE DATOS JERÁRQUICAS ......................................................... 3 1. ÁRBOLES ........................................................................................................ 3 1.1 Teoría general de Árboles .......................................................................... 3 1.2 Definición de árboles .................................................................................. 4 1.3 Otros conceptos de la teoría general de árboles ....................................... 5 1.4 Árbol completo ............................................................................................ 5 1.5 Estructura para la creación de un árbol de orden dos ................................ 6 1.6 Operaciones básicas con árboles ............................................................... 7 1.7 Árboles ordenados ...................................................................................... 8 2.1 ÁRBOLES BINARIOS ...................................................................................... 9 2.1 Conceptualización de Arboles Binarios....................................................... 9 2.2 Representación gráfica de un árbol binario .............................................. 10 2.3 Clasificación de los árboles binarios ......................................................... 14 2.3.1 Árbol Binario completo: .......................................................................... 14 2.3.3 Árbol Binario Isomorfo: .......................................................................... 16 2.4 Formas de Recorrer un Árbol Binario ....................................................... 16 2.4.1 Recorrido en Preorden .......................................................................... 17 2.4.2 Recorrido en Inorden ............................................................................ 18 2.4.3 Recorrido en Postorden ......................................................................... 19 2.5 Ábol binario de búsqueda (ABB) ............................................................... 21 2.5.1 Ventajas de los árboles binarios de búsqueda ...................................... 23 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 2.5.2 Operaciones en ABB ............................................................................. 24 2.5.3 Borrar un nodo rama con intercambio de un nodo hoja ......................... 24 2.5.4 Borrar un nodo rama con intercambio de un nodo rama ........................ 24 2.6 Implementación de un árbol binario con Punteros .................................... 26 2.7 Implementación de los árboles binarios en modo gráfico ......................... 34 2.7.1 Actividad de verificación ........................................................................ 42 2.8 Introducción al Modo Gráfico de C++ ....................................................... 43 2.8.1 Configuración del modo grafico de C++ en Borland C++5.5.................. 43 2.9 Otras opciones de compilador para implementar Modo grafico. ............... 46 2.9.1 El compilador DevC++: .......................................................................... 46 Fuentes Bibliográficas..................................................................................... 51 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS ESTRUCTURA DE DATOS JERÁRQUICAS 1. ÁRBOLES Introducción Los árboles a diferencia de las listas son una estructura de datos de no lineal, atendiendo a una estructura de tipo jerárquico. Se abordan los temas relacionados con los conceptos básicos de árboles, incluyendo la teoría general de árboles e identificando los diferentes tipos de árboles. Se presenta la teoría general de los arboles binarios, búsqueda, sus formas de recorridos. y árboles binarios de Finalizando con un apartado ampliamente desarrollado a cerca del modo gráfico de C++, finalizando con un programa de aplicación del modo gráfico que muestra figuras geométricas y texto manejando colores y rellenos. 1.1 Teoría general de Árboles Los árboles son, sin duda, una de las estructuras de datos no lineales, empleadas en informática, tanto para resolver problemas de hardware como de software. Los árboles de directorios son organizaciones bastante empleadas por cualquier usuario o programador de una computadora. De igual manera cumplen un buen papel en la toma de decisiones, valido como árbol de decisiones. Los árboles genealógicos y los organigramas son ejemplos comunes. Entre otras aplicaciones, los árboles se emplean para analizar circuitos eléctricos y para representar la estructura de fórmulas matemáticas, así como para organizar la información de bases de datos, para representar la estructura sintáctica de un programa fuente en compiladores y para la toma de decisiones. 3 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Después de haber conceptualizado la segunda unidad y haber realizado la implementación de los programas de aplicación con Arreglos y Apuntadores, se presenta otra alternativa para la aplicación y conceptualización de los árboles se recomienda que se realice por medio del entorno gráfico que hace parte del compilador de C++, de esta manera se logra un acercamiento a la programación orientada a objetos. 1.2 Definición de árboles Los árboles son estructuras de datos muy similares a las listas doblemente enlazadas, en el sentido que tienen punteros que apuntan a otros elementos, pero no tienen una estructura lógica de tipo lineal o secuencial como aquellas, sino ramificada. Tienen aspecto de árbol, de ahí su nombre. Su estudio desde el punto de vista matemático pertenece a la teoría de grafos; desde el punto de vista informático son estructuras de datos, lo que significa que cada elemento, denominado nodo u hoja, contiene un valor. Su estudio corresponde a la teoría de bases de datos, y en esta terminología, los nodos que dependen de otros se denominan hijos. Cada hoja puede tener un máximo de hijos, si no tiene ninguno se dice que es un nodo terminal. Un árbol es una estructura de datos no lineal en la que cada nodo puede apuntar a uno o varios nodos. También se suele dar una definición recursiva: un árbol es una estructura compuesta por un dato y varios árboles. Esto son definiciones simples. Una representación gráfica de los árboles se puede visualizar en la figura 50 presente a continuación. Figura 1. Representación gráfica de árboles Fuente: http://www.conclase.net/c/edd/index.php?cap=006b 4 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 1.3 Otros conceptos de la teoría general de árboles “Con relación al tipo de nodos que hacen parte de los árboles, se identifican algunos nodos: Nodo hijo: cualquiera de los nodos apuntados por uno de los nodos del árbol. En el ejemplo, 'L' y 'M' son hijos de 'G'. Nodo padre: nodo que contiene un puntero al nodo actual. En el ejemplo, el nodo 'A' es padre de 'B', 'C' y 'D'. Los árboles con los que trabajará tienen otra característica importante: cada nodo sólo puede ser apuntado por otro nodo, es decir, cada nodo sólo tendrá un padre. Esto hace que estos árboles estén fuertemente jerarquizados, y es lo que en realidad les da la apariencia de árboles. En cuanto a la posición dentro del árbol: Nodo raíz: nodo que no tiene padre. Este es el nodo que usaremos para referirnos al árbol. En el ejemplo, ese nodo es el 'A'. Nodo hoja: nodo que no tiene hijos. En el ejemplo hay varios: 'F', 'H', 'I', 'K', 'L', 'M', 'N' y 'O'. Nodo rama: aunque esta definición apenas la usaremos, estos son los nodos que no pertenecen a ninguna de las dos categorías anteriores. En el ejemplo: 'B', 'C', 'D', 'E', 'G' y 'J'. 1.4 Árbol completo Un árbol completo es aquel en el que en cada nodo o bien todos o ninguno de los hijos existen. Los árboles se parecen al resto de las estructuras tratadas en la unidad dos; dado un nodo cualquiera de la estructura, se puede considerar como una estructura independiente. Es decir, un nodo cualquiera puede ser considerado como la raíz de un árbol completo. Existen otros conceptos que definen las características del árbol, en relación a su tamaño: 5 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Orden: es el número potencial de hijos que puede tener cada elemento de árbol. De este modo, se dice que un árbol en el que cada nodo puede apuntar a otros dos es de orden dos, si puede apuntar a tres será de orden tres y así sucesivamente. Grado: el número de hijos que tiene el elemento con más hijos dentro del árbol. En el árbol del ejemplo en la figura 50, el grado es tres, ya que tanto 'A' como 'D' tienen tres hijos, y no existen elementos con más de tres hijos. Nivel: se define para cada elemento del árbol como la distancia a la raíz, medida en nodos. El nivel de la raíz siempre será cero y el de sus hijos uno. Así sucesivamente. En el ejemplo de la figura 50, el nodo 'D' tiene nivel 1, el nodo 'G' tiene nivel 2, y el nodo 'N', nivel 3. Altura: la altura de un árbol se define como el nivel del nodo de mayor nivel. Como cada nodo de un árbol puede considerarse a su vez como la raíz de un árbol, también se puede hablar de altura de ramas. El árbol del ejemplo de la figura 50, tiene altura 3, la rama 'B' tiene altura 2, la rama 'G' tiene altura 1, la 'H' cero. Los árboles de orden dos son bastante especiales, de hecho se ampliará un poco la información en el siguiente capítulo. Estos árboles se conocen también como árboles binarios. Frecuentemente, aunque tampoco es estrictamente necesario, para hacer más fácil moverse a través del árbol, se añade un puntero a cada nodo que apunte al nodo padre. De este modo se podrá avanzar en dirección a la raíz, y no sólo hacia las hojas. Es importante conservar siempre el nodo Raíz ya que es el nodo a partir del cual se desarrolla el árbol, si se pierde este nodo, se perderá el acceso a todo el árbol. 1.5 Estructura para la creación de un árbol de orden dos El nodo típico de un árbol difiere de los nodos que se vieron en la unidad dos para el manejo de las listas, aunque sólo en el número de nodos. A continuación se presenta un ejemplo de nodo para crear árboles de orden dos: struct Arbol { int dato; struct Arbol *rama1; struct Arbol *rama2; }; 6 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Generalizando más se puede declarar un a constantes llamada orden que se le asigna el valor de 5: #define ORDEN 5 struct Arbol { int dato; struct Arbol *rama[ORDEN]; }; El movimiento a través de árboles, salvo que se implementen punteros al nodo padre, será siempre partiendo del nodo raíz hacia un nodo hoja. Cada vez que se llegue a un nuevo nodo se podrá optar por cualquiera de los nodos a los que apunta para avanzar al siguiente nodo. Un ejemplo de estructura en árbol es el sistema de directorios y ficheros de un sistema operativo. Aunque en este caso se trata de árboles con nodos de dos tipos, nodos directorio y nodos fichero, se podría considerar que los nodos hoja son ficheros y los nodos rama son directorios. 1.6 Operaciones básicas con árboles Salvo que se trabaje con algún tipo de árboles especiales, como los que se verán en el siguiente capítulo es decir el capítulo 8, las inserciones serán siempre en punteros de nodos hoja o en punteros libres de nodos rama. Ya que con estas estructuras no es tan fácil generalizar, existen muchas variedades de árboles. Nuevamente se tiene casi el mismo concepto de operaciones de las que se disponía con las listas enlazadas: Añadir o insertar elementos a un árbol. Buscar o localizar elementos dentro del árbol. Borrar elementos creados en el árbol. Moverse a través del árbol por cada uno de sus ramas. Recorrer el árbol completo. Los algoritmos de inserción y borrado dependen en gran medida del tipo de árbol que se esté implementando, de modo que por ahora se dejarán a un lado y se centrará la atención en el modo de recorrer los árboles. 7 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 1.7 Árboles ordenados Los árboles ordenados son los que tienen más interés desde el punto de vista de los tipos de datos abstractos (TAD), y los que tienen más aplicaciones genéricas. Un árbol ordenado, en general, es aquel que a partir del cual se puede obtener una secuencia ordenada siguiendo uno de los recorridos posibles del árbol, es decir en inorden, preorden o posorden. En estos árboles es importante que la secuencia se mantenga ordenada aunque se añadan o se eliminen nodos. Existen varios tipos de árboles ordenados, a continuación se presentan a nivel informativo: Árboles binarios de búsqueda (ABB): son árboles de orden 2 que mantienen una secuencia ordenada si se recorren en inorden. Árboles AVL: son árboles binarios de búsqueda balanceados: es decir, los niveles de cada rama para cualquier nodo no difieren en más de 1. Árboles perfectamente equilibrados: son árboles binarios de búsqueda en los que el número de nodos de cada rama para cualquier nodo no difieren en más de 1. Son por lo tanto árboles AVL también. Árboles 2-3: son árboles de orden 3, que contienen dos claves en cada nodo y que están también equilibrados. También generan secuencias ordenadas al recorrerlos en inorden. Árboles-B: caso general de árboles 2-3, que para un orden M, contienen M-1 claves”1. 1 http://www.conclase.net/c/edd/index.php?cap=006b. 8 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 2.1 ÁRBOLES BINARIOS Introducción Los árboles binarios son estructuras de datos de tipo jerárquico. En el presente apartado se abordan los temas relacionados con los conceptos básicos de árboles binarios, incluyendo la teoría general de árboles binarios e identificando la forma de recorrerlos. Así como también la documentación de los árboles binarios de búsqueda y la forma de ir insertando los datos en el árbol. 2.1 Conceptualización de Arboles Binarios Este tipo de árbol se caracteriza porque tienen un vértice principal y de él se desprende dos ramas. La rama izquierda y la rama derecha a las que también se les conoce como subárboles. Figura 1Estructura de un árbol binario La rama izquierda y la derecha, también son dos árboles binarios. El Vértice principal se denomina raíz y cada una de las ramas se puede denominar como subárbol izquierdo y subárbol derecho. 9 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 2.2 Representación gráfica de un árbol binario Figura 3. Representación gráfica de un árbol binario La raíz de este árbol es A y el árbol izquierdo está conformado por dos árboles. Uno de raíz B tal como se muestra en la figura 4. Y el otro de raíz I tal como se muestra en la figura 5. Figura 4. Representación gráfica del subárbol izquierdo Los dos subárboles tienen a su vez dos subárboles cada uno, donde C y F son la raíces de los arboles del sub árbol izquierdo. Mientras que las raíces de los subárboles del subárbol derecho son J y M respectivamente, tal como se visualiza en la figura 3. 10 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Figura 5. Representación gráfica del subárbol derecho Nodo: Un árbol binario es un conjunto de elementos cada uno de los cuales se denomina nodo. Un árbol Binario puede tener cero nodos y este caso se dice que está vacío. Puede tener un sólo nodo, y en este caso solamente existe la raíz del árbol o puede tener un número finito de nodos. Cada nodo puede estar ramificado por la izquierda o por la derecha o puede no tener ninguna ramificación. Padre: Un Padre es un nodo que puede o no tener ramificaciones. Un ejemplo se puede visualizar en la figura 6. Figura 2. Representación gráfica de un nodo padre En los tres casos el nodo A es un padre. En el caso 1 es un padre que no tiene hijos. En el caso 2, el nodo A es el padre del nodo B. En el caso 3 el nodo A es padre de los nodos B y C pero no es padre del nodo D. Hijo: En el ejemplo anterior. El caso 1 el nodo A no tiene hijos. En el caso 2,B es un hijo del nodo A y en caso 3, D es hijo de B y el Padre de B es el nodo A. Hermano: Nos referimos al caso 3 del ejemplo anterior. Los hermanos son los hijos de un mismo padre. Los nodos B y C son hermanos. El nodo D no tiene Hermanos. Hoja: Una hoja es un nodo que no tiene ramificaciones. Por ejemplo Figura 7. Representación gráfica de un nodo hoja 11 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS El nodo C es una hoja mientras que el nodo B no se puede considerar como hoja porque tiene una ramificación por la derecha. El nodo D también es una hoja. Nodo no terminal: Un nodo no terminal es aquel que posee por lo menos una ramificación. En el ejemplo anterior, el nodo A o el nodo B son nodos no terminales, mientras el nodo D o el nodo C son nodos terminales. Camino: Un árbol siempre se examina de arriba hacia abajo. Por Ejemplo: Figura 8. Camino del árbol Al nodo C se puede llegar desde el nodo B. Nunca se puede examinar el nodo B a partir del nodo C. Los apuntadores derecho o izquierdo de cualquier nodo apuntan al árbol derecho o izquierdo que siguen a ese nodo. Nunca apuntan a los nodos precedentes. Un Camino, es el conjunto de nodos que tenemos que visitar con el propósito de llegar a un nodo específico. Por ejemplo para llegar al nodo F, es necesario recorrer el camino: A ------- D ------ F Del mismo nodo, para llegar al nodo G debemos recorrer el camino: A ----- D ------- E ------- G Obsérvese que los Caminos se configuran siempre hacia abajo. 12 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Longitud: Longitud es el número de nodos que se deben recorrer para pasar de un nodo a otro. Por ejemplo: Figura 9. Longitud del árbol binario De acuerdo a la figura 64. La longitud entre A y E es 3. La longitud entre G y G es 0. La longitud entre A y B es 1. Obsérvese que no se puede calcular la longitud entre B y G ya que el camino B ----A ---- G no existe. Descendiente: El nodo C es descendiente del nodo A si a partir de A se puede llegar a C a través de un camino según la figura 64, El nodo C es descendiente de A ya que a C podemos llegar por el caminoA -----B ------ C En el Ejemplo anterior, el nodo E es descendiente de D pero el nodo D no es descendiente de G. Ancestro: El nodo A es un ancestro del nodo C si existe un camino entre A y C. Basándonos en el ejemplo anterior, A es un ancestro de C ya que existe un Nivel: Cada nodo tiene un nivel dentro de un árbol binario. Por definición el nodo raíz tiene un nivel 0 y los demás nodos tienen el nivel de su padre más 1. Por esto los nodos que son hijos del nodo raíz tienen un nivel 1. 13 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Figura 10. Nivel del árbol El nodo A, tienen un nivel 0 en tanto que los nodos R y F tienen un nivel 1 Obsérvese que el nivel del nodo G es la longitud del camino desde la raíz hasta el nodo y tiene nivel 3. Grado de un Nodo. El grado de un nodo es el número de hijos. Por ejemplo el grado del nodo A es 2, el grado del nodo T es 1. El grado de un nodo terminal siempre es 0. En los árboles binarios, el grado de un nodo fluctúa entre 0 y 2. Altura: La altura de un árbol binario es el nivel de la hoja o de las hojas que están más distantes de la raíz. Basándose en la figura 65 de la gráfica anterior, la altura del árbol cuya raíz es A, corresponde a la longitud del camino para llegar a la hoja G que es más distante de la raíz, En este caso será 3. 2.3 Clasificación de los árboles binarios 2.3.1 Árbol Binario completo: Un árbol binario completo es aquel en el que todo nodo no terminal tiene sus dos hijos. El siguiente es un árbol binario completo de nivel 3 Figura 11. Representación gráfica de un árbol binario completo. 14 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Obsérvese que todos los nodos no terminales tienen sus dos hijos. El máximo número de nodos que puede tener un árbol de nivel n puede representarse con la siguiente ecuación matemática: 2°+2¹+2²+2³...+2n Si n es 3 entonces: 2°+2¹+2²+2³ = 15 El árbol de la figura 66, es un árbol binario completo de nivel 3, donde el número máximo de nodos es 15 tal como lo indica la fórmula matemática. Árbol binario Igual: Dos árboles son iguales si los dos son vacíos. Existe otro caso en el cual dos árboles son iguales: Figura 12. Representación gráfica de Árbol binario igual Estos árboles son iguales porque sus raíces son iguales y también lo son su respectivo árbol izquierdo y derecho. Para que un árbol sea igual a otro, es necesario que el contenido de cada uno de sus respectivos nodos sea el mismo y que tengan las mismas relaciones de parentesco. 2.3.2 Árbol Binario Semejante: Dos árboles binarios son semejantes si tienen el mismo número de nodos y los valores de los nodos del primer árbol son los mismos que los valores de los nodos del segundo, sin importar la relación de parentesco entre ellos. Por ejemplo: 15 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Figura 13. Representación gráfica de árboles semejantes Estos árboles son semejantes. Contienen los mismos valores en cada uno de sus nodos. 2.3.3 Árbol Binario Isomorfo: Dos árboles binarios son isomorfos si tienen la misma estructura aunque el contenido de cada uno de sus nodos sea diferente. Por ejemplo los siguientes árboles son isomorfos. Figura 14. Representación gráfica de árboles isomorfos Peso: El peso de un árbol en un nodo dado es el número de nodos en el árbol sin contarse el mismo. Por ejemplo teniendo como referente los árboles de la figura 69, se tiene que el peso de cualquiera de los dos árboles cuya raíz es A, corresponde al número de nodos para cada árbol es 6. Mientras que cualquiera de los nodos B y C tienen un peso de 2. 2.4 Formas de Recorrer un Árbol Binario Los árboles binarios, son estructuras de datos no lineales, son considerados como estructuras jerárquicas y como tal su forma de recorrerlos difiere sustancialmente en comparación con las listas enlazadas que son estructuras de datos de tipo lineal. En ese orden de ideas, el recorrido de un árbol binario se lleva a cabo en tres sentidos: Preorden, Inorden y Postorden. A continuación se detalla cada caso. 16 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 2.4.1 Recorrido en Preorden Recorrer un árbol en preorden consiste en primer lugar, examinar el dato del nodo raíz, posteriormente se recorrer el subárbol izquierdo en preorden y finalmente se recorre el subárbol derecho en preorden. Esto significa que para cada subárbol se debe conservar el recorrido en preorden, primero la raíz, luego la parte izquierda y posteriormente la parte derecha. En la figura 15. Se visualiza un árbol binario, perfectamente equilibrado, en el que sus nodos son de tipo carácter. De acuerdo con la definición del recorrido en preorden el resultado sería: Figura 15. Recorrido del árbol binario en preorden Otro ejemplo de recorrido en preorden, donde sus nodos son de tipo numérico para el siguiente árbol binario de la figura 16. Figura 16. Resultado del recorrido en preorden del árbol Una forma de implementar los recorridos de un árbol binario es a través de funciones específicas para dicha tarea. 17 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS void preorden(tarbol *a) { if (a != NULL) { visitar(a); preorden(a->izq); preorden(a->der); } } 2.4.2 Recorrido en Inorden Recorrer un árbol en Inorden consiste en primer lugar en recorrer el subárbol izquierdo en Inorden, luego se examina el dato del nodo raíz, y finalmente se recorre el subárbol derecho en Inorden. Esto significa que para cada subárbol se debe conservar el recorrido en Inorden, es decir, primero se visita la parte izquierda, luego la raíz y posteriormente la parte derecha. He aquí una aplicación un ejemplo: Manos a la obra… Se tiene el árbol binario de la figura 17, con datos de tipo numérico. El recorrido inicia con el subárbol izquierdo, el primer nodo a visitar es el 3 luego se visita el 5 y posteriormente el 7, con esto se garantiza que el recorrido del subárbol izquierdo se hizo en Inorden. Finalizado el recorrido del subárbol izquierdo se visita el nodo de la raíz, que para este caso es el numero 10. Solo queda recorrer el subárbol derecho en Inorden, es decir se visita el 11 luego el 12 y se finaliza con la visita del nodo 15 El resultado completo del recorrido en Inorden para el árbol de la figura 17 es:3 5 - 7 - 10 - 11 - 12 – 15 Tal como se muestra en la figura. 18 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Figura 17. Representación gráfica del recorrido en Inorden Se puede implementar el recorrido en Inorden de un árbol binario es a través de una función específicas para dicha tarea. void inorden(tarbol *a) { if (a != NULL) { inorden(a->izq); visitar(a); inorden(a->der); } } Por último solo queda describir la tercera forma de recorrer un árbol binario. 2.4.3 Recorrido en Postorden Recorrer un árbol en Postorden consiste en primer lugar en recorrer el subárbol izquierdo en Postorden, luego serecorre el subárbol derecho en Postorden y finalmente se visita el nodo raíz. Esto significa que para cada subárbol se debe conservar el recorrido en Postorden, es decir, primero se visita la parte izquierda, luego la parte derecha y por último la raíz. He aquí la aplicación con un ejemplo basado en el árbol de la figura 17: Manos a la obra… El recorrido inicia con el subárbol izquierdo, el primer nodo a visitar es el 3 luego se visita el 7 y posteriormente el 5 que es la raíz, con esto se garantiza que el recorrido del subárbol izquierdo se hizo en Postorden. 19 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Finalizado el recorrido del subárbol izquierdo se inicia la visita al subárbol derecho en Postorden, es decir, se visita el 11 luego el 15 y se finaliza con la visita del nodo 12 que sería la raíz de este subárbol. Solo queda recorrer la raíz del árbol que para este caso es el número10. El resultado completo del recorrido en Postorden para el árbol de la figura 17 es: 3 - 7 - 5 - 11 - 15 – 12 - 10 Tal como se muestra en la siguiente figura 18. Figura 18. Recorrido en Postorden del árbol binario. Se puede implementar el recorrido en Postorden de un árbol binario es a través de una función específicas para dicha tarea. void postorden(arbol *a) { if (a != NULL) { postorden(a->izq); postorden(a->der); visitar(a); } } Como aplicación a los tres recorridos de un árbol binario se presenta el siguiente árbol binario de la figura 19, con datos de tipo carácter con el propósito de identificar los recorridos es Preorden, Inorden, Postorden. 20 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Figura 19. Árbol binario como aplicación a los tres recorridos El resultado que arroja al realizar los tres recorridos es el siguiente: Preorden: P Q S T R U W X V Y Z Inorden: S Q T P W U X R Y V Z Postorden: S T Q P W X U Y Z V R P 2.5 Ábol binario de búsqueda (ABB) Los árboles binarios de búsqueda, son un tipo especial de árbol binario cuya característica radica en la forma ordenada de insertar sus elementos, facilitando así la búsqueda de un nodo en particular. Para puntualizar aun más, se tratarán los árboles binarios de búsqueda, en los que se tiene preestablecido un cierto orden, que seguramente ayudará a encontrar un cierto dato dentro de un árbol con mucha rapidez. La pregunta sería;¿cómo es este orden prefijado o preestablecido? La respuesta es sencilla y entenderlo es aun más, solo se debe cumplir la condición que para cada nodo se tiene que: la rama de la izquierda contendrá elementos menores. la rama de la derecha contendrá elementos mayores. Tal como se ha mantenido la metodología a lo largo del curso, un ejemplo sería la forma de explicarlo. Manos a la obra… Se tienen los siguientes datos de tipo numérico para crear con ellos un árbol binario de búsqueda. 21 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Los datos son: 5 – 3 – 7 – 2 – 4 – 8 - 9 El primer nodo siempre será asignado a la raíz del árbol binario de búsqueda, así que para este caso el 5 es la raíz del árbol. 5 Primer número: 5 (directo) Segundo número: 3 se interroga (3 es menor que 5) la respuesta es sí, entonces va al lado izquierdo de 5. 5 / 3 Tercer número: 7 (7 es mayor que 5) se inserta al lado derecho de 5, con ello se va construyendo el árbol. 5 / \ 3 7 Cuarto número: 2 (2 es menor que 5, y menor que 3) entonces va al lado izquierdo del 3. 5 / \ 3 7 / 2 Quinto número: 4 (4 es menor que 5 pero es mayor que 3) entonces va al lado derecho del 3. Nada complicado. 5 / \ 3 / 2 7 \ 4 Sexto número: 8 (8 es mayor que 5 y mayor que 7) en este caso se ingresa al lado derecho de 7. 22 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 5 / 3 / \ 2 \ 7 \ 4 8 Séptimo número: 9 (9 es mayor que 5, es mayor que 7 y es mayor que 8)en este caso se ingresa al lado derecho del número 8 formando de esta manera el árbol binario de búsqueda. 5 / 3 / \ 2 4 \ 7 \ 8 \ 9 2.5.1 Ventajas de los árboles binarios de búsqueda Para este tipo de árbol es muy evidente la rapidez con que se podría encontrar un el valor de un nodo; para este caso se tienen 7 elementos de tipo numérico no ordenados, lo que en una lista supone que si se busca un dato que casualmente está al final, se harían 7 comparaciones; en este árbol, dado que este árbol es de altura 4, se tienen que realizar 4 comparaciones como máximo. Y si además se hubiera equilibrado el árbol, es decir, irlo reacomodando de modo que siempre tenga la menor altura posible, habría quedado con una altura igual 3. Esto es lo que se hace en la práctica cuando en el árbol se va a hacer muchas más lecturas que escrituras: se reordena internamente después de añadir cada nuevo dato, de modo que la altura sea mínima en cada caso. De este modo, el número máximo de comparaciones que se tendrían que hacer sería representado por la expresión matemática log2(n), lo que supone que si se tienen 500 datos, en una lista se podría llegar a tener que hacer 500 comparaciones, y en un árbol binario de búsqueda, log2(1000) = 10 comparaciones como máximo. La ganancia en velocidad de búsqueda es clara. Habiendo conceptualizado la teoría de un árbol binario de búsqueda, la tarea sería desarrollar un programa en modo gráfico de C++ para que al insertar los datos ingresados por teclado en tiempo de ejecución, se imprima en pantalla la gráfica del árbol binario de búsqueda. 23 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 2.5.2 Operaciones en ABB “Las operaciones que se pueden realizar sobre un árbol binario de búsqueda ABB es parecido al que se realizan sobre otras estructuras de datos lineales, más alguna otra propia de árboles entre ellas están: Buscar un elemento en cualquier posición del árbol Insertar un elemento en cualquier lugar del árbol Borrar un elemento ubicado en cualquier lugar del árbol. Movimientos a través del árbol: Izquierda. Derecha. Raíz. 2.5.3 Borrar un nodo rama con intercambio de un nodo hoja En el árbol de ejemplo, representado en la figura 20, borrar el nodo 4. 1. Se localiza el nodo a borrar ('raíz'). 2. Se busca el nodo más a la derecha del árbol izquierdo de 'raíz', en este caso el 3, al tiempo que se mantiene un puntero a 'Padre' a 'nodo'. 3. Se Intercambian los elementos 3 y 4. 4. Se hace que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL. 5. Se borra el 'nodo'. Figura 20. Borrado de un nodo rama con intercambio de nodo hoja Fuente: http://www.conclase.net/c/edd/index.php?cap=007 2.5.4 Borrar un nodo rama con intercambio de un nodo rama Para este ejemplo se tiene otro árbol. En éste se borrará el elemento 6. 24 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Figura 21. Representación gráfica de un árbol binario de búsqueda Fuente: http://www.conclase.net/c/edd/index.php?cap=007 1. Se localiza el nodo a borrar ('raíz'). 2. Se busca el nodo más a la izquierda del árbol derecho de 'raíz', en este caso el 12, ya que el árbol derecho no tiene nodos a su izquierda, si se opta por la rama izquierda, se estará en un caso análogo. Al mismo tiempo que se mantiene un puntero a 'Padre' a 'nodo'. 3. Se intercambia los elementos 6 y 12. 4. Ahora se tiene que repetir el bucle para el nodo 6 de nuevo, ya que no es posible eliminarlo. Figura 22. Borrado de un nodo rama con intercambio de nodo rama Fuente: http://www.conclase.net/c/edd/index.php?cap=007 5. Se localiza de nuevo el nodo a borrar ('raíz'). 6. Se busca el nodo más a la izquierda del árbol derecho de 'raíz', en este caso el 16, al mismo tiempo que se mantiene un puntero a 'Padre' a 'nodo'. 7. Se hace el intercambio de los elementos 6 y 16. 8. Se hace que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL. 25 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 9. Se procede a borrar el 'nodo'. Figura 23. Intercambio de un nodo rama con intercambio de nodo rama Fuente: http://www.conclase.net/c/edd/index.php?cap=007 Este modo de actuar asegura que el árbol sigue siendo ABB Para aplicar un poco la teoría de árboles binarios, es importante implementar un programa que haciendo uso de apuntadores permita ingresar datos al árbol, consultar datos, visualizar los datos, eliminar datos del árbol y mostrar sus tres recorridos. Para este ejemplo no se hace uso de la aplicación del modo grafico. 2.6 Implementación de un árbol binario con Punteros Programa1.cpp #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <ctype.h> #include <iostream.h> struct arbol { int dato; struct arbol *izq; struct arbol *der; }*raiz; enum{ FALSO=0, VERDADERO }; /*PROTOTIPOS*/ 26 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS void inicializar( void ); int vacio( struct arbol *hoja ); int eshoja( struct arbol *hoja ); struct arbol *insertar( struct arbol *raiz, struct arbol *hoja, int num ); int busqueda( struct arbol *hoja, int num ); int nodos( struct arbol *hoja ); void auxnodos( struct arbol *hoja, int *cont ); struct arbol *borrarx( struct arbol *hoja, int num ); struct arbol *podar( struct arbol *hoja ); void preorden( struct arbol *hoja ); void inorden( struct arbol *hoja ); void posorden( struct arbol *hoja ); void menu_recorridos( void ); void menu_busquedas( void ); void menu_nodos( void ); void menu_podar( void ); void inicializar( void ) { raiz= NULL; } int vacio( struct arbol *hoja ) { if( !hoja ) return VERDADERO; return FALSO; } int eshoja( struct arbol *hoja ) { if( hoja->izq==NULL && hoja->der==NULL ) return VERDADERO; return FALSO; } struct arbol *insertar( struct arbol *raiz, struct arbol *hoja, int num ) { if( !hoja ) { hoja= (struct arbol *) malloc( sizeof (struct arbol) ); hoja->dato= num; hoja->izq= NULL; hoja->der= NULL; if( !raiz ) return hoja; else if( num<raiz->dato ) raiz->izq= hoja; else raiz->der= hoja; 27 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS return hoja; } else if( num<hoja->dato ) insertar( hoja, hoja->izq, num ); else insertar( hoja, hoja->der, num ); return raiz; } int busqueda( struct arbol *hoja, int num ) { while( hoja ) { if( num==hoja->dato ) return VERDADERO; else { if( num<hoja->dato ) hoja= hoja->izq; else hoja= hoja->der; } } return FALSO; } int nodos( struct arbol *hoja ) { int nodos=0; auxnodos( hoja, &nodos ); return nodos; } void auxnodos( struct arbol *hoja, int *cont ) { if( !hoja ) return; (*cont)++; auxnodos( hoja->izq, cont ); auxnodos( hoja->der, cont ); } struct arbol *borrarx( struct arbol *hoja, int num ) { if( hoja->dato==num ) { struct arbol *p, *p2; if( vacio( hoja ) ) { 28 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS free( hoja ); hoja= NULL; return hoja; } else if( hoja->izq==NULL ) { p= hoja->der; free( hoja ); return p; } else if( hoja->der==NULL ) { p= hoja->izq; free( hoja ); return p; } else { p= hoja->der; p2= hoja->der; while( p->izq ) p= p->izq; p->izq= hoja->izq; free( hoja ); return p2; } } else if( num<hoja->dato ) hoja->izq= borrarx( hoja->izq, num ); else hoja->der= borrarx( hoja->der, num ); return hoja; } struct arbol *podar( struct arbol *hoja ) { if( !hoja ) return hoja; podar( hoja->izq ); podar( hoja->der ); free( hoja ); hoja= NULL; return hoja; } /*Recorridos*/ void preorden( struct arbol *hoja ) { 29 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS if( !hoja ) return; cout << hoja->dato ; preorden( hoja->izq ); preorden( hoja->der ); } void inorden( struct arbol *hoja ) { if( !hoja ) return; inorden( hoja->izq ); cout <<hoja->dato ; inorden( hoja->der ); } void posorden( struct arbol *hoja ) { if( !hoja ) return; posorden( hoja->izq ); posorden( hoja->der ); cout <<hoja->dato ; } /*Menus del Arbol*/ void menu_recorridos( void ) { char _op='S'; while( _op!='4' ) { clrscr(); cout << "1. PreOrden." ; cout << "\n2. InOrden." ; cout << "\n3. PosOrden." ; cout << "\n4. Salir." ; cout << "\n\n:: " ; _op= getch(); switch( _op ) { case '1': preorden( raiz ); getch(); break; case '2': 30 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS inorden( raiz ); getch(); break; case '3': posorden( raiz ); getch(); break; } } return; } void menu_busquedas( void ) { int val; cout << "\n\nNumero: " ; cin>> val ; if( busqueda( raiz, val ) ) cout << "\n\nEncontrado.." ; else cout << "\n\nError, No se encuentra." ; getch(); } void menu_nodos( void ) { cout << "\n\nEl Numero de Nodos es " << nodos( raiz ) ; getch(); } void menu_podar( void ) { char _op='A'; int val; while( _op!='3' ) { clrscr(); cout << "1. Podar Un Nodos del Arbol." ; cout << "\n2. Podar Todo el Arbol." ; cout << "\n3. Salir." ; _op= getch(); switch( _op ) { case '1': 31 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS cout << "\n\nNumero: " ; cin>> val ; raiz= borrarx( raiz, val ); cout << "\n\n.... Borrado ...." ; break; case '2': raiz= podar( raiz ); cout << "\n\nArbol Borrado por Completo." ; getch(); break; } } return; } int main() { char _op='A'; int val; inicializar(); while( _op!='S' ) { clrscr(); cout << "IMPLEMENTACION DE UN ARBOL BINARIO \n\n"; cout << "Insertar" ; cout << "\nRecorridos" ; cout << "\nBusquedas" ; cout << "\nNodos" ; cout << "\nPodar" ; cout << "\nSalir" ; cout << "\n\n Ingrese la Opcion : " ; _op= toupper( getch() ); switch( _op ) { case 'I': cout << "\n\nNumero: " ; cin>> val ; if( busqueda( raiz, val ) ) { cout << "\n\nEste numero ya ha sido insertado." ; getch(); break; } raiz= insertar( raiz, raiz, val ); 32 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS break; case 'R': if( vacio( raiz ) ) { cout << "\n\nEl Arbol Aun esta Vacio." ; getch(); break; } menu_recorridos(); break; case 'B': if( vacio( raiz ) ) { cout << "\n\nEl Arbol Aun esta Vacio." ; getch(); break; } menu_busquedas(); break; case 'A': if( vacio( raiz ) ) { cout << "\n\nEl Arbol Aun esta Vacio." ; getch(); break; } case 'N': if( vacio( raiz ) ) { cout << "\n\nEl Arbol Aun esta Vacio." ; getch(); break; } menu_nodos(); break; case 'P': if( vacio( raiz ) ) { cout << "\n\nEl Arbol Aun esta Vacio." ; getch(); break; } menu_podar(); break; } } 33 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS cout << "\n\nPulsa para salir..." ; getchar(); return 0; } El resultado después de la compilación y ejecución del listado, se puede visualizar en la figura 24 que se muestra a continuación. Figura 24. Salida en pantalla del programa1 Después de haber profundizado en la temática de relacionada con la teoría de árboles, árboles binarios solo resta presentar un programa completo funcional donde se da aplicabilidad a la teoría de árboles haciendo buen uso del modo gráfico de C++, lo que permite acercarnos a la programación orientada a Objetos con la Interfaz grafica de usuario. 2.7 Implementación de los árboles binarios en modo gráfico El siguiente programa llamado programa2, muestra la aplicabilidad del modo grafico de C++ al servicio de la teoría general de árboles binarios. Programa2.cpp //Autor: Carlos Javier Guzmán #include <graphics.h> #include <iostream.h> #include <string.h> #include <dos.h> #include <conio.h> #include <stdlib.h> void cajadetexto_a(int x,int y,int ancho,int altura); int iniciagrafica(); int linea_iz(int tx, int px1, int py1, int ty, int px2, int py2); int linea_der(int tx, int px1, int py1, int ty, int px2, int py2); 34 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS int presentacion(); int ordenar(); int texto(); //para textos int verificar(int z); //analiza cuando hijos pueden haber main() { // int z; iniciagrafica(); setbkcolor(DARKGRAY); //color de fondo de pantalla setfillstyle(SOLID_FILL,LIGHTGRAY); //fondo de la ventana grande bar3d(620,470,5,20,10,30);//x/y/px1/py1/an //ventana grande presentacion(); cajadetexto_a(280,30,30,30);//px,py,largo,ancho A outtextxy(292,42,"A"); ordenar(); getch(); } int iniciagrafica() { int gdriver = DETECT, gmode, errorcode; initgraph(&gdriver, &gmode, "c:\\tc\\bgi"); } int ordenar() { int A,B,D,G,C,M,P,x; texto(); //llama la caja de texto outtextxy(55,388,"Cuandos hijos tiene A "); gotoxy(31,25); cin>>x; texto();// llama caja de texto para no sobrescribir A=verificar(x); if(A==1 || A==2) //B { //comienza lado izquierdo setcolor(5); linea_iz(125,276,40, 55,150,39);//izquierdo entre b y a 35 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS cajadetexto_a(137,100,30,30);//px,py,largo,ancho isz 5.1 B outtextxy(150,110,"B"); //b if(A==2) { setcolor(13); linea_der(145,307,40, 55,452,39);//izquierdo entre c y a cajadetexto_a(439,100,30,30);//px,py,largo,ancho derecha 5.3 C outtextxy(452,110,"C"); } outtextxy(55,388,"Cuandos hijos tiene B "); gotoxy(31,25); cin>>x; texto();// llama caja de texto para no spbrescribir B=verificar(x); if(B==1); { setcolor(5); linea_iz(60,133,110, 75,72,109); //izquierda entre d y b cajadetexto_a(60,190,30,30);//px,py,largo,ancho iszquierda 1 D outtextxy(73,200,"D"); //D } if(B==2) //D y G { setcolor(5); linea_iz(60,133,110, 75,72,109); //izquierda entre d y b cajadetexto_a(60,190,30,30);//px,py,largo,ancho iszquierda 1 D outtextxy(73,200,"D"); // D setcolor(5); linea_der(57,164,110, 75,220,109);//izquierdo entre g y b cajadetexto_a(207,190,30,30);//px,py,largo,ancho iszquierda 2 G outtextxy(220,200,"G"); //G } outtextxy(55,388,"Cuandos hijos tiene D "); gotoxy(31,25); cin>>x; texto();// llama caja de texto para no sobrescribir D=verificar(x); if(D==1)//D { 36 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS setcolor(5); linea_iz(34,55,198, 55,22,198); //izquierda entre e y d cajadetexto_a(10,250,30,30);//px,py,largo,ancho iszquierda 1.1 E outtextxy(23,263,"E"); } if(D==2) //E Y F { setcolor(5); linea_iz(34,55,198, 55,22,198); //izquierda entre e y d cajadetexto_a(10,250,30,30);//px,py,largo,ancho iszquierda 1.1 E outtextxy(23,263,"E"); setcolor(5); linea_der(28,87,198, 55,114,197);//izquierdo entre f y d cajadetexto_a(100,250,30,30);//px,py,largo,ancho iszquierda 1.2 F outtextxy(113,263,"F"); } if(B==2) { outtextxy(55,388,"Cuandos hijos tiene G "); gotoxy(31,25); cin>>x; texto();// llama caja de texto para no sobrescribir G=verificar(x); if(G==1) //H { setcolor(5); linea_iz(30,203,199, 45,173,199); //izquierda entre h y g cajadetexto_a(160,250,30,30);//px,py,largo,ancho iszquierda 2.1 H outtextxy(173,263,"H"); setcolor(5); } if(G==2) // H y I { setcolor(5); linea_iz(30,203,199, 45,173,199); //izquierda entre h y g cajadetexto_a(160,250,30,30);//px,py,largo,ancho iszquierda 2.1 H outtextxy(173,263,"H"); setcolor(5); linea_der(28,234,199, 47,261,198);//izquierdo entre i y g cajadetexto_a(250,250,30,30);//px,py,largo,ancho iszquierda 2.2 I 37 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS outtextxy(263,263,"I"); } } } //termina lado izquierdo if(A==2) { outtextxy(55,388,"Cuandos hijos tiene C "); gotoxy(31,25); cin>>x; texto();// llama caja de texto para no sobrescribir C=verificar(x); if(C==1) { setcolor(13); linea_der(55,466,110, 75,520,109);//izquierdo entre c y p setcolor(13); cajadetexto_a(510,190,30,30);//px,py,largo,ancho derecha 4 P outtextxy(522,200,"P"); } if(C==2) { setcolor(13); linea_iz(57,435,110, 75,378,109); //izquierda entre m y c setcolor(13); cajadetexto_a(367,190,30,30);//px,py,largo,ancho dercha 3 M outtextxy(379,200,"M"); setcolor(13); linea_der(55,466,110, 75,520,109);//izquierdo entre c y p setcolor(13); cajadetexto_a(510,190,30,30);//px,py,largo,ancho derecha 4 P outtextxy(522,200,"P"); } outtextxy(55,388,"Cuandos hijos tiene P "); gotoxy(31,25); cin>>x; texto();// llama caja de texto para no sobrescribir P=verificar(x); if(P==1) { 38 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS setcolor(13); linea_der(28,537,199, 47,564,198);//izquierdo entre z y p cajadetexto_a(550,250,30,30);//px,py,largo,ancho derecha 4.2 Z outtextxy(563,263,"Z"); } if(P==2) { setcolor(13); linea_iz(25,506,199, 45,482,199); //izquierda entre q y p cajadetexto_a(470,250,30,30);//px,py,largo,ancho derecha 4.1 Q outtextxy(482,263,"Q"); setcolor(13); linea_der(28,537,199, 47,564,198);//izquierdo entre z y p cajadetexto_a(550,250,30,30);//px,py,largo,ancho derecha 4.2 Z outtextxy(563,263,"Z"); } if(C==2) { outtextxy(55,388,"Cuandos hijos tiene M "); gotoxy(31,25); cin>>x; texto();// llama caja de texto para no sobrescribir M=verificar(x); if(M==1) { setcolor(13); linea_iz(33,364,199, 45,332,199); //izquierda entre n y m cajadetexto_a(320,250,30,30);//px,py,largo,ancho derecha 3.1 N outtextxy(332,263,"N"); } if(M==2) { setcolor(13); linea_iz(33,364,199, 45,332,199); //izquierda entre n y m cajadetexto_a(320,250,30,30);//px,py,largo,ancho derecha 3.1 N outtextxy(332,263,"N"); setcolor(13); linea_der(28,394,199, 47,422,198);//izquierdo entre o y m cajadetexto_a(410,250,30,30);//px,py,largo,ancho derecha 3.2 O outtextxy(422,263,"O"); 39 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS } } } //termina A=2 }//termina funcion ordenar void cajadetexto_a(int x,int y,int ancho,int altura) { setcolor(DARKGRAY); line(x,y,x+ancho-1,y); //linea superior gris oscuro line(x,y,x,y+altura-1);//linea inferior derecha gris oscuro setcolor(LIGHTGRAY); line(x+1,y+altura-1,x+ancho-1,y+altura-1); //linea inferior gris line(x+ancho-1,y+1,x+ancho-1,y+altura-1); //linea derecha gris setcolor(WHITE); line(x,y+altura,x+ancho,y+altura); //linea inferior blanco externo line(x+ancho,y,x+ancho,y+altura); //linea derescha blanco externo setfillstyle(SOLID_FILL,9); bar(x+1,y+1,x+ancho-2,y+altura-2); //pinta el cuadro de blanco } int linea_iz(int tx, int px1, int py1, int ty, int px2, int py2) { for(int i=1; i<tx; i++) { outtextxy(px1-i,py1,"."); delay(15); } for(i=1; i<ty; i++) { outtextxy(px2,i+py2,"."); delay(15); } } int linea_der(int tx, int px1, int py1, int ty, int px2, int py2) { for(int i=1; i<tx; i++) { outtextxy(px1+i,py1,"."); delay(15); 40 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS } for(i=1; i<ty; i++) { outtextxy(px2,i+py2,"."); delay(15); } } int presentacion() { cajadetexto_a(12,25,130,30);//px,py,largo,ancho A cuadro de mensaje arbo cajadetexto_a(482,25,130,30);//px,py,largo,ancho A cuadro de mensaje carlos sleep(1); setcolor(11); outtextxy(15,32,"Arboles"); sleep(1); outtextxy(68,44,"Binarios"); sleep(1); setcolor(11); outtextxy(495,32,"Carlos Javier"); sleep(1); outtextxy(524,44,"Guzman"); } int texto() { cajadetexto_a(50,375,180,30);//px,py,largo,ancho A cajadetexto_a(230,375,30,30);//px,py,largo,ancho A } int verificar(int z) { int n,d; n=z; while(n<=0 || n>=3) { outtextxy(60,386,"Dato errado, ingrese "); outtextxy(64,393,"otro dato "); gotoxy(31,25); cin>>n; 41 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS texto();// llama caja de texto para no sobrescribir } if(n==1 || n==2) { return n; } return n; } 2.7.1 Actividad de verificación Como actividad de verificación, se propone que cada estudiante de forma individual, analice el código que se presenta en el anterior programa en el listado llamado programa2, con el fin de que lo edite y lo lleve al compilador para ver la salida en pantalla, el cual pone en práctica los conocimientos adquiridos en la temática de árboles binarios, en la ejecución del programa. Para finalizar la temática propuesta en el presente apartado, se presenta a continuación una introducción a lo que es el modo gráfico de C++, que será el referente para los inicios de la programación orientada a objetos y la aplicación a la temática de los árboles binarios de búsqueda. 42 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 2.8 Introducción al Modo Gráfico de C++ Después de haber trabajado la segunda unidad con la implementación de estructuras dinámicas lineales con punteros, se recomienda que la tercera unidad se realice por medio del modográfico de C++, teniendo en cuenta que en esta unidad se hará la representación gráfica de los árboles. 2.8.1 Configuración del modo grafico de C++ en Borland C++5.5 La configuración del modo grafico para C++ depende del compilador, cada uno tiene sus propias características, por ejemplo para este caso he utilizado el compilador Borland C++ 5.5, entre tantas versiones que hay disponibles y son de fácil manejo y algo adicional que es de libre uso y ya viene configurado siempre y cuando la descarga la realice del sitio disponible en la caja de herramientas del curso ubicada en el entorno de conocimiento. https://www.dropbox.com/home/Public/Compiladores%20para%20C%2B%2B A continuación se muestra la interfaz gráfica del compilador Borland C++ 5.5, pues no requiere de ningún tipo de configuración adicional ya cuenta con las librerías gráficas. Figura 25. Interfaz gráfica del compilador Borland C++ 5.5. 43 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Solo basta con compilar el programa para que se genere el archivo ejecutable con extensión .exe que es el archivo a ejecutar para visualizar en modo gráfico como salida en pantalla. Es importante saber que el ejecutable se crea en la misma ruta donde tiene guardado el código fuente, es decir, el archivo con extensión .cpp. Para compilar el programa solo tiene que ubicar en la barra de menú del compilador la opción Tools y dar clic en la opción Compile o presione las teclas Ctrl + F7. Para probar si quedó bien instalado el compilador solo tiene que copiar en el editor el siguiente código fuente: Promama 3.cpp #include <graphics.h> #include <conio.h> #include <stdio.h> void main(void) { int monitor=DETECT, modo; initgraph(&monitor,&modo,""); setcolor(YELLOW); line(10,50,50,100); setcolor(WHITE); circle(100,200,30); //setfillstyle(LINE_FILL,RED); floodfill(100,200,WHITE); rectangle(200,100,300,200); setfillstyle(HATCH_FILL,BLUE); floodfill(250,150,WHITE); setcolor(GREEN); settextstyle(GOTHIC_FONT,HORIZ_DIR,3); outtextxy(20,10,"Modo Gráfico de C++"); outtextxy(20,250,"Hola Ingeniero esto es:"); setcolor(CYAN); outtextxy(20,300,"Estructura de datos"); getch(); closegraph(); return; } Progra4.cpp #include <graphics.h> // Encabezado con declaraciones de gráficos 44 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS #include <conio.h> #include <stdio.h> void main(void) { int monitor=DETECT, modo; // Declaracion de tipo de monitor y modo initgraph(&monitor,&modo,""); // Inicializa el modo grafico indicando el monitor y modo utilizado gotoxy(1,23);printf("getmaxx()=%d",getmaxx()); gotoxy(1,24);printf("getmaxy()=%d",getmaxy()); setcolor(YELLOW); // Establece el color amarillo para los trazos line(0,0,50,50); // Dibuja una linea desde 0,0 hasta 50,50 setcolor(WHITE); //Establece el color blanco circle(100,200,30); // Dibuja un circulo el centro está en 100,200 y de // radio=30 pixeles setfillstyle(LINE_FILL,RED); // Establece el relleno de lineas rojas floodfill(100,200,WHITE); // Rellena el contorno desde 100,200 hasta // encontrar un trazo blanco rectangle(200,100,300,200); // Dibuja un rectangulo desde 200,100 hasta // 300,200 setfillstyle(HATCH_FILL,BLUE); // Establece el relleno como cuadricula floodfill(250,150,WHITE); // Rellena el contorno desde 100,200 hasta // encontrar un trazo blanco setcolor(GREEN); //Establece el color verde settextstyle(GOTHIC_FONT,HORIZ_DIR,5); // Establece el font como Gotico // en posicion Horizontal de tamano 5 outtextxy(320,100,"Ingenieros Gothic "); // Despliega el mensaje "Gothic" en 330,100 setcolor(CYAN); //Establece el color celeste //settextstyle(SANS_SERIF_FONT,VERT_DIR,2);// Establece el font como // Sanserif en posicion Vertical de tamano 7 outtextxy(300,200,"Ingenieros Sanserif");// Despliega el mensaje "Sanserif" en 330,200 getch(); closegraph(); // Termina el modo grafico (vuelve a su modo normal) return; } La salida en pantalla de programa4.cpp lo visualiza en la siguiente figura 26. 45 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Figura 26. Salida en pantalla de programa4 Modo grafico de C++. 2.9 Otras opciones de compilador para implementar Modo grafico. 2.9.1 El compilador DevC++: Dev C++ es uno de los más utilizados para el lenguaje C++ y como tal también puede ser configurado con sus librerías graficas para trabajar gráficos, veamos cómo hacerlo. Para poder hacer programas con entorno gráfico en DEV C++ se requiere hacer uso de unas librerías gráficas que no vienen por defecto con él. Los pasos para importar dichas librerías en Dev C++ son los siguientes: 1. Descargue las librerías, sin abrirlas, sólo descárguelas y cópielas en el directorio INCLUDE y LIB de su Dev C++ (dónde está instalado). De la siguiente manera: Librería Ruta para descargar graphics.h libbgi.a http://www.cs.colorado.edu/~main/bgi/dev-c++/graphics.h http://www.cs.colorado.edu/~main/bgi/dev-c++/libbgi.a Ruta para copiar en su equipo C:\Dev-Cpp\include C:\Dev-Cpp\lib Nota: La ruta para copiar la descarga es la ruta por defecto donde se instala Dev C++. Si en el momento de la instalación usted cambió esa ruta, deberá copiar las librerías en la ruta que usted indicó, dentro de los directorios INCLUDE y LIB respectivamente. 46 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 2. Abra Dev C++ y cree un proyecto nuevo. Figura 27. Interfaz Nuevo proyecto 3. Seleccione el tipo: “Console Aplication” y dele el nombre que usted desee. Figura 28. Opciones del proyecto 47 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 4. Seleccione el menú PROYECTO y dentro de él, OPCIONES DE PROYECTO Figura 29. Proyecto nuevo Figura 30. Selección de la consola 48 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS 5. Seleccione la pestaña : ARGUMENTOS Figura 31. Pestaña Argumentos 6. En la columna de la derecha: ENLAZADOR (LINKER) copie tal cual las siguientes líneas (incluyendo los guiones). -lbgi -lgdi32 -lcomdlg32 -luuid -loleaut32 -lole32 Figura 32. Enlazador Linker 49 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS De clic en aceptar y en este momento ya tiene descargadas e importadas las librerías en el proyecto actual. Puede probarlas copiando el siguiente código y compilándolo: #include<graphics.h> int main( ) { initwindow( 700 , 700 , "Mi primera grafica"); circle(200, 200, 100); circle(300, 200, 100); circle(250, 300, 100); getch(); return 0; } Figura 33. Pantalla de edición del código El resultado de la salida en pantalla deberá ser: Figura 34. Salida en pantalla de gráficos 50 TEORÍA GENERAL DE ÁRBOLES COMO FUNDAMENTOS A LAS ESTRUCTURAS DE DATOS JERÁRQUICAS Fuentes Bibliográficas C++ con Clase. Estructuras de datos. Capitulo 6. Árboles. Recuperado de. http://www.conclase.net/c/edd/index.php?cap=006#inicio C++ con Clase. Estructuras de datos. Capitulo 7. Árboles binarios de búsqueda. Recuperado de. http://www.conclase.net/c/edd/index.php?cap=007#inicio 51