UNIDAD II ARBOLES

2.1 DEFINICIÓN DE UN ÁRBOL:
Un grafo que no tiene ciclos y que conecta a todos los puntos, se llama un árbol. En un grafo con n vértices, los árboles tienen exactamente n - 1 aristas, y hay nn-2 árboles posibles. Su importancia radica en que los árboles son grafos que conectan todos los vértices utilizando el menor número posible de aristas. Un importante campo de aplicación de su estudio se encuentra en el análisis filogenético, el de la filiación de entidades que derivan unas de otras en un proceso evolutivo, que se aplica sobre todo a la averiguación del parentesco entre especies; aunque se ha usado también, por ejemplo, en el estudio del parentesco entre lenguas.
En teoría de grafos, un árbol es un grafo en el que dos vértices están conectados por exactamente un camino. Un bosque es un grafo en el que dos vértices cualquiera están conectados por como máximo un camino. Un árbol a veces recibe el nombre de árbol libre.

Definiciones
Un árbol es un grafo simple unidireccional G que satisface alguna de las siguientes condiciones equivalentes:
    

G es conexo y no tiene ciclos simples. G no tiene ciclos simples y, si se añade alguna arista se forma un ciclo simple. G es conexo y si se le quita alguna arista deja de ser conexo. G es conexo y el grafo completo de 3 vértices K3 no es un menor de G. Dos vértices cualquiera de G están conectados por un único camino simple.

Si G tiene muchos vértices, n, entonces las definiciones anteriores son también equivalentes a cualquiera de las siguientes condiciones:
  

G es conexo y tiene n − 1 aristas. G no tiene aristas simples y tiene n − 1 aristas. La cantidad de hojas de un árbol siempre es mayor o igual a la mitad de la totalidad de los nodos

En gráfico unidireccional simple G se recible el nombre de bosque si no tiene ciclos simples. Un árbol dirigido es un grafo dirigido que sería un árbol si no se consideraran las direcciones de las aristas. Algunos autores restringen la frase al caso en el que todos las aristas se dirigen a un vértice particular, o todas sus direcciones parten de un vértice particular.

Un árbol recibe el nombre de árbol con raíz si cada vértice ha sido designado raíz, en cuyo caso las aristas tienen una orientación natural hacia o desde la raíz. Los árboles con raíz, a menudo con estructuras adicionales como orden de los vecinos de cada vértice, son una estructura clave en informática; véase árbol (programación). • Un árbol dirigido es una estructura jerárquica, organizada y dinámica, Jerárquica porque los componentes están a distinto nivel, Organizada porque importa la forma en que esté dispuesto el contenido y Dinámica porque su forma, tamaño y contenido pueden variar durante la ejecución. Si hay un camino de A hasta B, se dice que A es antecesor de B, y que B es sucesor de A. Padre es el antecesor inmediato de un nodo Hijo, cualquiera de sus descendientes inmediatos. Descendiente de un nodo, es cualquier sucesor de dicho nodo. Hermano de un nodo, es otro nodo con el mismo padre. Generación, es un conjunto de nodos con la misma profundidad. Raíz es el nodo que no tiene ningún predecesor (sin padre). Hoja es el nodo que no tiene sucesores (sin hijos) (Terminal). Los que tienen predecesor y sucesor se llaman nodos interiores. Rama es cualquier camino del árbol. Bosque es un conjunto de árboles desconectados. Nivel o profundidad de un nodo, es la longitud del camino desde la raíz hasta ese nodo. El nivel puede de}irse como 0 para la raíz y nivel (predecesor)+1 para los demás nodos. Los nodos de la misma generación tienen el mismo nivel. Grado de un nodo, es el número de flechas que salen de ese nodo (hijos). El número de las que entran siempre es uno. Grado de un árbol, es el mayor grado que puede hallarse en sus nodos. Longitud del camino entre 2 nodos: es el número de arcos que hay entre ellos.

• • • • • • • • • • • • • • •

Un árbol etiquetado es un árbol en el que cada vértice tiene una única etiqueta. Los vértices de un árbol etiquetado de n vértices reciben normalmente las etiquetas {1,2, ..., n}. Un árbol regular ( homogéneo) es un árbol en el que cada vértice tiene el mismo grado. Véase grafo regular.

Un árbol etiquetado con 6 vértices y 5 aristas

Ejemplo
En árbol de ejemplo mostrado a la derecha tiene 6 vértices y 6 − 1 = 5 aristas. El único camino simple que conecta los vértices 2 y 6 es 2-4-5-6.

Propiedades
Todo árbol es a su vez un grafo bipartito. Todo árbol con sólo un conjunto contable de vértices es además un grafo plano. Todo grafo conexo G admite un árbol de cobertura, que es un árbol que contiene cada vértice de G y cuyas aristas son aristas de G. Dado n vértices etiquetados, hay n n−2 maneras diferentes de conectarlos para construir un grafo. El resultado se llama fórmula de Cayley. El número de árboles con n vértices de grado d1,d2,...,dn es:

que es un coeficiente multinomial.

No se conoce fórmula para el número t(n) de árboles con n vértices de un isomorfismo de grafos. Sin embargo, el comportamiento asintótico de t(n) se conoce; hay números α ≈ 3 y β ≈ 0.5 tales que

INTRODUCCIÓN
Los árboles forman una de las subclases de gráficas que más se utilizan. La ciencia de la computación hace uso de los árboles ampliamente, especialmente para organizar y relacionar datos en una base de datos. Los árboles surgen en problemas teóricos como el tiempo óptimo para ordenar.

2.2 TERMINOLOGÍA Y CARACTERIZACIÓN DE LOS ÁRBOLES
Un árbol T (libre) es una gráfica simple que satisface lo siguiente; si v y w son vértices en T, existe una trayectoria simple única de v a w. Se muestra un ejemplo:

g y determine también la altura del árbol. y así sucesivamente. La altura de un árbol con raíz es el número máximo de nivel que ocurre. el nivel de la raíz es el nivel 0. b.Un árbol con raíz es un árbol en el que un vértice específico se designa como raíz. 2. cada vértice esta en un nivel determinado de manera única. se presenta un ejemplo: Como la trayectoria simple de la raíz a cualquier vértice dado es única. Ejercicio: Construya dos árboles libres uno de 7 vértices y el otro de 5 vértices. Para el vértice a su nivel es 0 Para el vértice b su nivel es 1 Para el vértice g su nivel es 2 La altura del árbol es de 2. los vértices que están debajo de la raíz están en el nivel 1. Ejemplo: Tomando como referencia el gráfico del árbol con raíz determine el nivel del vértice a. luego determine cuantas aristas tiene cada árbol. 3 ÁRBOLES DE EXPANSIÓN . Por lo tanto podemos decir que: el nivel de un vértice v es la longitud de la trayectoria simple de la raíz a v. Así.

c. d.Un árbol T es un árbol de expansión de una gráfica G si T es una subgráfica de G que contiene a todos los vértices de G. f. 2. e. Tomado h como vértice raíz tenemos: . Por búsqueda a lo ancho: permite procesar todos los vértices en un nivel dado antes de moverse al nivel más alto que lo sigue. a de los vértices para determinar un árbol de expansión de la grafica G. considerando el primer vértice de ese orden como raíz. Una grafica G tiene un árbol de expansión si y solo si G es conexa. El árbol de expansión para la grafica G que se presenta. Por búsqueda en profundidad: o conocido también como de regreso. se muestra con línea seguida. Existen dos métodos para encontrar el árbol de expansión de una grafica G: 1. g. Ejemplo Utilice la búsqueda a profundidad con el orden h. b. primero se selecciona un orden de los vértices.

al recorrer el árbol se lo hace desde un Vo a un Vf por las aristas cuyos pesos sean menores y la suma del recorrido sea menor. Para encontrar el árbol de expansión mínima se debe recorrer todos los vértices del árbol en el que la suma de los pesos de sus aristas sea mínima.Árboles de expansión mínimo Un árbol de expansión comprende un grafo que posee nodos. Utilizando el algoritmo de la ruta más corta. Algoritmo de la ruta más corta en un árbol Se lo obtiene aplicando el algoritmo de Dijkstra. Un árbol de expansión mínima de G es un árbol de expansión de G con peso mínimo. Ejemplo: Determine el árbol de expansión mínimo para la gráfica de la página 405 del texto base ejercicio 4. arcos cada uno con longitud (peso) no negativa. Luego de haber recorrido las diferentes alternativas de la gráfica propuesta en el texto básico obtenemos como resultado la que se muestra: . no se incluyen ciclos en la solución. no es necesario que se abarque todos los vértices.

Por otro lado. Árbol de expansión Un árbol de expansión (aristas azules gruesas) de un grafo de rejilla. . cada vértice está en el árbol. todos los puentes de G deben estar contenidos en T. un árbol de expansión de G es una selección de aristas de G que forman un árbol que cubre todos los vértices. un árbol de expansión T de un grafo conexo. En el campo matemático de la teoría de grafos. Informalmente. Esto es. pero no hay ciclos. sumatoria mínima. Ejercicio: Realice el mismo ejercicio propuesta anteriormente utilizando el algoritmo de Prim. no dirigido G es un árbol compuesto por todos los vértices y algunas (quizá todas) de las aristas de G.Si realizamos la suma de sus pesos es de 35.

Otra definición. como el máximo árbol de expansión. esos ciclos forman una base del espacio de ciclos. es la de un bosque de expansión es un subgrafo que es a la vez bosque (es decir. un bosque de expansión es un subgrafo que consiste en un árbol de expansión en cada componente conexo del grafo (equivalentemente. Ciclos fundamentales y cortes fundamentales Si se añade una sola arista a un árbol de expansión. o como el mínimo conjunto de aristas que conecta todos los vértices. existe el concepto de corte fundamental. el árbol de expansión con el menor número de hojas (relacionado con el problema del camino hamiltoniano). el árbol de expansión con el máximo número de hojas (estrechamente relacionado con el problema del menos conjunto dominante y conexo). MDST por sus siglas en inglés). En ciertos campos de la teoría de grafos es útil encontrar el mínimo árbol de expansión de un grafo ponderado. un grafo con E aristas tiene E-V+1 ciclos fundamentales.Un árbol de expansión de un grafo conexo G puede ser también definido como el mayor conjunto de aristas de G que no contiene ciclos. los vértices se dividen en dos conjuntos disjuntos (desconectados). De manera dual a la noción de ciclo fundamental. Hay un ciclo fundamental distinto para cada arista. La dualidad entre cortes y ciclos fundamentales se manifiesta al observar que las aristas de un ciclo que no pertenece al árbol de expansión sólo pueden aparecer en los cortes de otras aristas del ciclo. el máximo árbol que cubre al menos k vértices.  . hay exactamente V-1 cortes fundamentales en un grafo. cualquier árbol de expansión tiene V-1 aristas. la generalización a subgrafos disconexos de árboles de expansión minimales. hay una correspondencia biyectiva (uno a uno) entre ciclos fundamentales y aristas ausentes del árbol de expansión. En cualquier árbol de expansión dado. Bosques de expansión Un bosque de expansión es un tipo de subgrafo que generaliza el concepto de árbol de expansión. es un subgrafo libre de ciclos maximal). se crea un ciclo: los ciclos de ese tipo se denominan ciclos fundamentales. uno por cada arista del árbol de expansión. incluye a todos los vértices). y viceversa: las aristas en un corte sólo pueden aparecer en aquellos ciclos no contenidos en la arista correspondiente al corte. También se han abordado otros problemas de optimización relacionados con los árboles de expansión. no contiene ciclos) y de expansión (es decir. Hay dos definiciones de uso común:  Según la primera. y así. Por tanto. El corte fundamental se define como el conjunto de aristas que deben ser eliminados de un grafo G para llegar a la misma división. así como la que se emplea habitualmente al tratar los bosques mínimos de expansión. es decir. Esta definición es frecuente en informática y optimización. el árbol de expansión de mínimo diámetro o el árbol de expansión de la mínima dilación. Al eliminar una arista del árbol de expansión. Para un grafo conexo con V vértices. empleada en teoría de grafos. el mínimo árbol de expansión con k aristas por vértice como máximo (árbol de expansión de mínimo grado.

entonces t(G)=1. y es un elemento de uso frecuente en estructuras de datos en distintos lenguajes de programación. La fórmula de Cayley puede ser demostrada mediante el teorema de matriz-árbol de Kirchhoff o mediante el código de Prüfer. Árboles de expansión uniforme Un árbol de expansión escogido aleatoriamente. . entonces el número t(G) satisface la recurrencia de supresión-contracción: t(G) = t(G − e) + t(G / e) donde G-e es el multigrafo que se obtiene al eliminar la arista e. entonces se verifica que son también corolarios del teorema matriz-árbol. Si G es el grafo hipercúbico n-dimensions Qn. entonces se cumple t(G) = pq − 1qp − 1. Depth-First Search (DFS. Trivialmente. Estas fórmulas Si G es un multigrafo y e es una arista de G. La fórmula de Cayley es una fórmula para obtener el número de árboles de expansión en un grafo completo Kn con n vértices. Para un grafo genérico G. y G/e es la contracción de G sobre e. La fórmula establece que t(Kn) = nn − 2. Si G es un grafo completo bipartido Kp. Otro algoritmo relevante está basado en la búsqueda priorizando la amplitud (Breadth-First Search. con igual probabilidad. el número t(G) puede obtenerse a través del teorema de matriz-árbol de Kirchhoff. Algoritmos El algoritmo clásico para los árboles de expansión. Este modelo ha sido ampliamente investigado en los ámbitos de la Probabilidad y la Física matemática. Si G es un ciclo Cn con n vértices. búsqueda priorizando la profundidad en español). fue diseñado por Robert Tarjan. entonces t(G)=n. es fácil calcular t(G) directamente. Otra prueba de la fórmula de Cayley es la existencia de exactamente nn − 2 árboles etiquetados con n vértices.Conteo de árboles de expansión El número t(G) de árboles de expansión de un grafo conexo es un invariante importante. .q. en la que las múltiples aristas de esta contracción no son eliminadas. entre todos los árboles de expansión se denomina árbol de expansión uniforme (AEU). BFS). si G es un árbol. En algunos casos.

Puede haber más de un árbol recubridor posible. Cada arista tiene asignado un peso proporcional entre ellos. como con la compañía de cable en el ejemplo anterior. un árbol recubridor mínimo de ese grafo es un subgrafo que tiene que ser un árbol y contener todos los vértices del grafo inicial. . Algunos de estos caminos podrán ser más caros que otros. Estos caminos serían representados por las aristas con mayores pesos. en particular. si todos los pesos son iguales. etc. Cada punto representa un vértice. cada arista está etiquetada con su peso. que en este caso equivale a su longitud. . todo árbol recubridor será mínimo. Esto ocurre en muchas situaciones de la realidad. donde es extraño que dos caminos tengan exactamente el mismo coste. Todo grafo tiene un bósque recubridor mínimo. distancia. Dado un grafo conexo. La demostración de esto es trivial y se puede hacer por inducción..Árbol recubridor mínimo Un ejemplo de árbol recubridor mínimo. Un árbol recubridor para este grafo sería un subconjunto de estos caminos que no tenga ciclos pero que mantenga conectadas todas las casas. y se usa para asignar un peso total al árbol recubridor mínimo computando la suma de todos los pesos de las aristas del árbol en cuestión. si cada arista tiene un peso distinto existirá sólo un árbol recubridor mínimo. Un ejemplo sería una compañía de cable trazando cable a una nueva vecindad. porque podría haber más de un árbol recubridor mínimo. En el caso de un empate. El árbol recubridor mínimo será el de menos coste. Si está limitada a trazar el cable por ciertos caminos. entonces se hará un grafo que represente los puntos conectados por esos caminos. por ser más largos. Un árbol recubridor mínimo o un árbol expandido mínimo es un árbol recubridor que pesa menos o igual que otros árboles recubridores. Esto también se generaliza para los bósques recubridores. De todas formas. que es un número representativo de algún objeto.

el algoritmo es también conocido como algoritmo DJP o algoritmo de Jarnik.Si los pesos son positivos. en una cola de prioridad donde la prioridad es la distancia. no dirigido y cuyas aristas están etiquetadas. El algoritmo fue diseñado en 1930 por el matemático Vojtech Jarnik y luego de manera independiente por el científico computacional Robert C. En otras palabras. Pseudocódigo del algoritmo  Estructura de datos auxiliar: Q = Estructura de datos Cola de prioridad (se puede implementar con un heap) JARNIK (Grafo G. Prim en 1957 y redescubierto por Dijkstra en 1959. las aristas a considerar son aquellas que inciden en vértices que ya pertenecen al árbol.distancia> del grafo por cada u en V[G] hacer distancia[u] = INFINITO padre[u] = NULL Añadir(cola. La distancia la ponemos a infinito y el padre de cada nodo a NULL // Encolamos. Descripción conceptual El algoritmo incrementa continuamente el tamaño de un árbol. Algoritmo de Prim El algoritmo de Prim es un algoritmo perteneciente a la teoría de los grafos para encontrar un árbol recubridor mínimo en un grafo conexo. entonces el algoritmo encontrará el árbol recubridor mínimo para uno de los componentes conexos que forman dicho grafo no conexo. donde el peso total de todas las aristas en el árbol es el mínimo posible. todas las parejas <nodo. comenzando por un vértice inicial al que se le van agregando sucesivamente vértices cuya distancia a los anteriores es mínima. Esto significa que en cada paso. Por esta razón. . Si el grafo no es conexo.distancia[u]>) distancia[s]=0 mientras cola != 0 do // OJO: Se entiende por mayor prioridad aquel nodo cuya distancia[u] es menor.<u. u = extraer_minimo(cola) //devuelve el minimo y lo elimina de la cola. nodo_fuente s) // Inicializamos todos los nodos del grafo. el árbol recubridor mínimo es el subgrafo de menor costo posible conectando todos los vértices. el algoritmo encuentra un subconjunto de aristas que forman un árbol con todos los vértices. ya que los subgrafos que contienen ciclos necesariamente tienen más peso total. El árbol recubridor mínimo está completamente construido cuando no quedan más vértices por agregar.

getNumber (). } } .distance>d) { table [n1]. while (p. while (!queue. v) Actualizar(cola.getNumber (). ++v) if (v != s) result. queue.known) { table [n0].por cada v adyacente a 'u' hacer si ((v ∈ cola) && (distancia[v] > peso(u. v < n.predecessor = n0. queue.addEdge (v. PriorityQueue queue = new BinaryHeap (g. Enumeration p = v0. for (int v = 0. int d = wt.intValue ().getEmanatingEdges ().getNumberOfEdges()).addVertex (v). if (!table [n0].<v. int n1 = v1.distance = d. ++v) table [v] = new Entry (). int s) { int n = g. for (int v = 0.getMate (v0).getValue (). int n0 = v0. Int wt = (Int) edge.distance = 0.known = true. v < n. v1)).enqueue ( new Association (new Int (0).distancia[v]>) Código en JAVA public class Algorithms { public static Graph PrimsAlgorithm (Graph g. if (!table[n1]. table [s].isEmpty ()) { Association assoc = (Association) queue. Vertex v1 = edge.getWeight (). Entry[] table = new Entry [n]. for (int v = 0.getNumberOfVertices (). table [n1].getVertex (s))). g. v)) entonces padre[v] = u distancia[v] = peso(u.dequeueMin(). return result. table [v].enqueue ( new Association (new Int (d).known && table[n1]. ++v) result. v < n.predecessor).hasMoreElements ()) { Edge edge = (Edge) p. } } } } Graph result = new GraphAsLists (n).nextElement (). Vertex v0 = (Vertex) assoc.

f también se podría haber agregado y se hubiese agregado en vez de e si su peso fuera menor que el de e. En la iteración que e se agrega a Y. siempre habrá un camino para todo nodo. Ya que Y1 es el árbol recubridor mínimo de G hay un camino en Y1 que une los dos extremos. Ejemplo de ejecución del algoritmo Image Descripción No visto En el grafo En el árbol .Demostración Sea G un grafo conexo y ponderado. que no está en Y1 y sea V el conjunto de nodos conectados por las aristas agregadas antes que e. se debe encontrar una arista que conecte un nodo del subgrafo a otro nodo fuera del subgrafo. Ya que G es conexo. se debe encontrar una arista f uniendo un nodo en V a uno que no está en V. Si se repiten los pasos mencionados anteriormente. Si es el árbol recubridor mínimo. Ya que f no se agregó se concluye: Sea Y2 el grafo obtenido al remover f y agregando . y el peso total de sus aristas no es mayor que el de Y1. eventualmente se obtendrá el árbol recubridor mínimo de G que es igual a Y. sea e la primera arista agregada durante la construcción de Y. La salida Y del algoritmo de Prim es un árbol porque las aristas y los nodos agregados a Y están conectados. entonces también es un árbol recubridor mínimo de G y contiene a e y todas las aristas agregadas anteriormente durante la construcción de V. Si no. Es fácil mostrar que Y2 conexo tiene la misma cantidad de aristas que Y1. Sea Y el árbol recubridor mínimo de G. Entonces un extremo de e está en V y el otro no. Esto demuestra que Y es el árbol recubridor mínimo de G. Mientras que uno se mueve por el camino. En toda iteración del algoritmo de Prim.

F. D. E. De estos. F El algoritmo continua. En este punto la arista DB es marcada en rojo porque sus dos extremos ya están en el árbol y por lo tanto no podrá ser utilizado. y el vértice D ha sido elegido arbitrariamente como el punto de partida. D El próximo vértice a elegir es el más cercano a D o A. B . G A. C B. B. F A. G A. Ninguna de las aristas está marcada. El vértice B. 6 es el valor más pequeño. No es un árbol ya que requiere que no haya ciclos y en este grafo los hay. B está a 9 de distancia de D y a 7 de A. F D El segundo vértice es el más cercano a D: A está a 5 de distancia. y F está a 6. B a 9. es el siguiente marcado. así que marcamos el vértice F y a la arista DF. E. así que marcamos la arista DA. D. G valor más pequeño.Este es el grafo ponderado de partida. E. null C. B. E a 15 y F a 6. que está a una distancia de 7 de A. G A. C. 5 es el C. E. E está a 15. Los números cerca de las aristas indican el peso.

E. Si el grafo no es conexo. y G está a 11 de distancia de F. Otras dos aristas fueron marcadas en rojo porque ambos vértices que unen fueron agregados al árbol. incluyen todos los vértices y donde el valor total de todas las aristas del árbol es el mínimo. C está a 8 de distancia de B. null null A. Cada punto representa un vértice. y se marca con el arco EC. . D. D. Se usa el Algoritmo para buscar las distancias más cortas (árbol expandido) que conectan todos los puntos o vértices. El arco BC también se marca con rojo. E. E y G. Un ejemplo de árbol expandido mínimo. El algoritmo de Kruskal es un ejemplo de algoritmo voraz. F. entonces busca un bosque expandido mínimo (un árbol expandido mínimo para cada componente conexa). así que se agrega EG al árbol. formando un árbol. Se elige C.Aquí hay que elegir entre C. B. E está más cerca. G A. busca un subconjunto de aristas que. F. G Algoritmo de Kruskal El algoritmo de Kruskal es un algoritmo de la teoría de grafos para encontrar un árbol recubridor mínimo en un grafo conexo y ponderado. Es decir. C G es el único vértice pendiente. D. null G A. B. C. C. En este caso con un peso de 39. el cual puede ser un árbol por sí mismo. E Sólo quedan disponibles C y G. Todos los vértices están ya marcados. el árbol de expansión mínimo se muestra en verde. y G a 9 de distancia de E. C está a 5 de distancia de E. entonces null marcamos el vértice E y la arista EB. E está a 7 de distancia de B. y está más cerca de E que de F. F. B.

14 if C(v) ≠ C(u) then 15 Add edge (v. vector< vector<int> > arbol(cn).v) ← Q. 48–50 en 1956. 17 return tree T Código en C++ // Declaraciones en el archivo . v is the minimum weighted route from/to v 9 (u. el cual forma un árbol de expansión mínimo del grafo.h int cn. INF). 16 Merge C(v) and C(u) into one cluster. el bosque tiene un solo componente. 5 Define a tree T ← Ø //T will ultimately contain the edges of the MST 6 // n es el número total de vértices 7 while T has fewer than n-1 edges do 8 // edge u. . se desecha la arista Al acabar el algoritmo. using the weights as keys. i < cn. pp. Pseudocódigo 1 function Kruskal(G) 2 for each vertex v in G do 3 Define an elementary cluster C(v) ← {v}. v solo si T no contiene una arista que una u y v.Funciona de la siguiente manera:    se crea un bosque B (un conjunto de árboles). union C(v) and C(u). that is.removeMin() 10 // previene ciclos en T. 11 // Nótese que el cluster contiene más de un vértice si una arista une un par de 12 // vértices que han sido añadidos al árbol. and let C(u) be the cluster containing u. //matriz de adyacencia // Devuelve la matriz de adyacencia del arbol minimo. y fue escrito por Joseph Kruskal.u) to T. i++){ arbol[i] = vector<int> (cn. //cantidad de nodos vector< vector<int> > ady. // indica a que arbol pertenece el nodo for(int i = 0. pertenece[i] = i. 4 Initialize a priority queue Q to contain all edges in G. 13 Let C(v) be the cluster containing v. vector< vector<int> > Grafo :: kruskal(){ vector< vector<int> > adyacencia = this->ady. Este algoritmo fue publicado por primera vez en Proceedings of the American Mathematical Society. suma u. combinando los dos árboles en un solo árbol o en caso contrario. donde cada vértice del grafo es un árbol separado se crea un conjunto C que contenga a todas las aristas del grafo mientras C es no vacío o eliminar una arista de peso mínimo de C o si esa arista conecta dos árboles diferentes se añade al bosque. vector<int> pertenece(cn).

Lo siguiente es usar una estructura de datos sobre conjuntos disjuntos (disjoint-set data structure) para controlar qué vértices están en qué componentes. el algoritmo de Kruskal muestra una complejidad O(m log m) o. j < cn. arcos++. i++) for(int j = 0. k++) if(pertenece[k] == temp) pertenece[k] = pertenece[nodoA]. así que log n es O(log m). equivalentemente. O(m log n). Es necesario hacer orden de O(m) operaciones ya que por cada arista hay dos operaciones de búsqueda y posiblemente una unión de conjuntos. } } return arbol. while(arcos < cn){ // Encontrar el arco minimo que no forma ciclo y guardar los nodos y la distancia. } Complejidad del algoritmo m el número de aristas del grafo y n el número de vértices. // Todos los nodos del arbol del nodoB ahora pertenecen al arbol del nodoA. Los tiempos de ejecución son equivalentes porque:   m es a lo sumo n2 y log n2 = 2logn es O(log n). int temp = pertenece[nodoB]. if(pertenece[nodoA] != pertenece[nodoB]){ arbol[nodoA][nodoB] = min. pertenece[nodoB] = pertenece[nodoA]. int min = INF.} int nodoA. cuando se ejecuta sobre estructuras de datos simples. k < cn. esto permite que el paso "eliminar una arista de peso mínimo de C" se ejecute en tiempo constante. nodoB = j. n ≤ 2m. ignorando los vértices aislados. } // Si los nodos no pertenecen al mismo arbol agrego el arco al arbol minimo. j++) if(min > adyacencia[i][j] && pertenece[i] != pertenece[j]){ min = adyacencia[i][j]. int nodoB. nodoA = i. los cuales forman su propia componente del árbol de expansión mínimo. arbol[nodoB][nodoA] = min. for(int k = 0. i < cn. for(int i = 0. Se puede conseguir esta complejidad de la siguiente manera: primero se ordenan las aristas por su peso usando una ordenación por comparación (comparison sort) con una complejidad del orden de O(m log m). int arcos = 1. Incluso una .

Ninguna de las aristas está resaltada. el algoritmo puede usar estructuras de datos de conjuntos disjuntos más complejas para ejecutarse en tiempos del orden de O(m α(n)). Ya que e fue considerada por el algoritmo antes que f. Esto prueba que Y debe ser un árbol expandido de peso mínimo. Por tanto. Y1+e tiene un ciclo y existe una arista diferente f en ese ciclo que también conecta C1 y C2. . Los números de las aristas indican su peso. Y2 es un árbol expandido mínimo con más aristas en común con Y que las que tiene Y1. Demostración de la corrección Sea P un grafo conexo y valuado y sea Y el subgrafo de P producido por el algoritmo. Otros algoritmos para este problema son el algoritmo de Prim y el algoritmo de Boruvka. Ejemplo: Este es el grafo original. Y es un árbol expandido de P. sea e la primera arista considerada por el algoritmo que está en Y y que no está en Y1. Por tanto. el peso de e es al menos igual que que el peso de f y ya que Y1 es un árbol expandido mínimo. contradiciendo las hipótesis que se habían establecido antes para Y1. ésta debe conectar vértices de dos árboles diferentes y no vértices dentro de un subárbol. Con la condición de que las aristas estén ordenadas o puedan ser ordenadas en un tiempo lineal (por ejemplo. donde α es la inversa (tiene un crecimiento extremadamente lento) de la función de Ackermann. Ya que Y1 es un árbol. Y no puede ser disconexa ya que la primera arista que une dos componentes de Y debería haber sido añadida por el algoritmo. mediante el ordenamiento por cuentas o con el ordenamiento Radix). Entonces Y2=Y1+e-f es también un árbol expandido. los pesos de esas dos aristas deben ser de hecho iguales. el cual tiene el mayor número de aristas en común con Y. Por tanto. Si Y1=Y entonces Y es un árbol de expansión mínimo. Y no puede tener ciclos porque cada vez que se añade una arista. Sean C1 y C2 las componentes de P que conecta la arista e. la complejidad total es del orden de O(m log m) = O(m log n). Por otro lado. Sea Y1 el árbol expandido de peso mínimo de P.estructura de datos sobre conjuntos disjuntos simple con uniones por rangos puede ejecutar las operaciones mencionadas en O(m log n).

La siguientes aristas más pequeñas son AB y BE. ambas con peso 7. porque formaría un ciclo ABD si se hubiera elegido. por lo que se resalta como segunda arista. . con peso 5.AD y CE son las aristas más cortas. y se resalta. La arista BD se resalta en rojo. ahora es CE la arista más pequeña que no forma ciclos. La siguiente arista. DF con peso 6. y AD se ha elegido arbitrariamente. AB se elige arbitrariamente. por tanto se resalta. con peso 5. ha sido resaltada utilizando el mismo método. Sin embargo.

2. Si el vértice tiene un hijo se designa como un hijo izquierdo o como derecho (pero no ambos). y FE (formaría el ciclo FEBAD). un hijo se designa como hijo izquierdo y el otro como hijo derecho. además.4 ÁRBOLES BINARIOS Están entre los tipos de árboles binarios especiales con raíz.El proceso continúa marcando las aristas. y se ha encontrado el árbol expandido mínimo. Muchas otras aristas se marcan en rojo en este paso: BC (formaría el ciclo BCE). un hijo o dos hijos. Si un vértice tiene dos hijos. el proceso termina con la arista EG de peso 9. Ejemplo . su posición en el árbol los identifica. DE (formaría el ciclo DEBA). Finalmente. Un árbol binario completo es un árbol binario en el que cada vértice tiene dos o cero hijos. BE con peso 7. Formalizando se dice que un árbol binario es un árbol con raíz en el que cada vértice tiene ningún hijo. Donde cada hijo se designa como un hijo izquierdo o un hijo derecho. su característica es que todo vértice tiene cuando mucho dos hijos.

Un árbol binario con enraizado es como un grafo que tiene uno de sus vértices. es decir que no almacena ningún dato. y nunca más de dos hijos. con un nodo raíz cuyo valor es 2. se usa la siguiente definición: «Un árbol binario es un grafo conexo. Si rehusamos el requerimiento de la conectividad. . cada vértice tendrá un único padre. Con la raíz escogida. permitiendo múltiples componentes conectados en el grafo. Definición de teoría de grafos Un árbol binario sencillo de tamaño 9 y altura 3. Usos comunes de los árboles binarios son los árboles binarios de búsqueda. los montículos binarios y Codificación de Huffman. acíclico y no dirigido tal que el grado de cada vértice no es mayor a 3». Árbol binario En ciencias de la computación. entonces este es llamado un nodo externo. de grado no mayor a 2. En el caso contrario el hijo es llamado un nodo interno. llamado raíz. Si algún hijo tiene como referencia a null.La altura de este árbol es de 2. un árbol binario es una estructura de datos en la cual cada nodo siempre tiene un hijo izquierdo y un hijo derecho. De esta forma sólo existe un camino entre un par de nodos. No pueden tener más de dos hijos (de ahí el nombre "binario"). llamaremos a esta última estructura un bosque. En teoría de grafos.

Este método se beneficia de un almacenamiento más compacto y una mejor localidad de referencia. En un árbol binario cada nodo puede tener cero. Algunas de ellas son: Estructura con manejo de memoria dinámica. La información de la ubicación del nodo en el árbol es implícita a cada posición del arreglo. La estructura para este caso sería por tanto: int árbol[NUMERO_DE_NODOS]. . Un árbol binario lleno es un árbol en el que cada nodo tiene cero o dos hijos. struct celda *izdo. Un árbol binario perfecto es un árbol binario lleno en el que todas las hojas (vértices con cero hijos) están a la misma profundidad (distancia desde la raíz. } tArbol. En el caso de un árbol binario casi-completo (o un árbol completo). tArbol árbol[NUMERO_DE_NODOS]. se encuentra en la posición truncamiento((i-1)/2) (suponiendo que la raíz está en la posición cero). typedef struct celda *arbolbin. sus hijos se encuentran en las posiciones 2i+1 y 2i+2. también llamada altura). A veces un árbol binario perfecto es denominado árbol binario completo. puede utilizarse un sencillo arreglo de enteros con tantas posiciones como nodos deba tener el árbol. hDerecho. particularmente durante un recorrido en preorden. }. uno o dos hijos (subárboles). para alguna n. Un árbol binario es un árbol en el que ningún nodo puede tener más de dos subárboles. Se conoce el nodo de la izquierda como hijo izquierdo y el nodo de la derecha como hijo derecho. *dcho. int hIzquierdo.Tipos de árboles binarios     Un árbol binario es un árbol con raíz en el que cada nodo tiene como máximo dos hijos. Así. siendo puntA el puntero que apunta al árbol de tipo tArbol: struct celda { telemento dato. Estructura con arreglo indexado: typedef struct tArbol { int clave. mientras que su padre (si tiene). Implementación en C Un árbol binario puede declararse de varias maneras. si un nodo está en la posición i. Otros definen un árbol binario completo como un árbol binario lleno en el que todas las hojas están a profundidad n o n-1.

5 RECORRIDO DE UN ÁRBOL Existen tres métodos extras que permiten recorrer un árbol.+ A B .A * .derecha) Recorrido entreorden o inorden: considera para el recorrido del árbol el siguiente orden (izquierda -raíz .2. ellos son: Recorrido preorden: considera para el recorrido del árbol el siguiente orden (raíz izquierda .derecha) Recorrido postorden: considera para el recorrido del árbol el siguiente orden (izquierda – derecha ..* C D / E F A ENTREORDEN (inorden): A + B – C * D – E / F * A POSTORDEN: A B + C D * E F / .raíz) Respuesta: PREORDEN: * .

.

Recorridos sobre árboles binarios Recorridos en profundidad El método de este recorrido es tratar de encontrar de la cabecera a la raíz en nodo de unidad binaria. Ahora pasamos a ver la implementación de los distintos recorridos: .

} } Implementación en pseudocódigo de forma iterativa: push(s. void preorden(tArbol *a) { if (a != NULL) { tratar(a). el subárbol derecho. //realizamos operaciones sobre el nodo p SI (D(p) <> NULL) //preguntamos si p tiene árbol derecho ENTONCES push(s.D(p)).raíz). FIN-SI SI (I(p) <> NULL) //preguntamos si p tiene árbol izquierdo ENTONCES push(s.I(p)). nodo izquierda.NULL). //insertamos el nodo raíz MIENTRAS (s <> NULL) HACER p = pop(s). //insertamos en una pila (stack) el valor NULL. 5. 5 y 2. preorden(a->hDerecho). 2. 11. En el árbol de la figura el recorrido en preorden sería: 2. //Realiza una operación en nodo preorden(a->hIzquierdo). 5. 6. después el derecho y por último el nodo actual. En el árbol de la figura el recorrido en postorden sería: 2. nodo raíz. nodo derecho. nodo derecha. 7. 7. 6. 4. 9 y 4. FIN-SI FIN-MIENTRAS Recorrido en postorden En este caso se trata primero el subárbol izquierdo.Recorrido en preorden En este tipo de recorrido se realiza cierta acción (quizás simplemente imprimir por pantalla el valor de la clave de ese nodo) sobre el nodo actual y posteriormente se trata el subárbol izquierdo y cuando se haya concluido. 11. para asegurarnos de que esté vacía push(s. 9. 5. Otra forma para entender el recorrido con este método seria seguir el orden: nodo raíz. . Otra forma para entender el recorrido con este método seria seguir el orden: nodo izquierdo. //sacamos un elemento de la pila tratar(p).

después el nodo actual y por último el subárbol derecho. el recorrido por niveles no es de naturaleza recursiva. Implementación en C: void arbol_recorrido_anch (tipo_Arbol* A) { tipo_Cola cola_nodos. // este es un puntero llevara el recorrido . que sólo contiene el nodo raíz. 5. inorden(a->hDerecho). 6. Esquema de implementación: void inorden(tArbol *a) { if (a != NULL) { inorden(a->hIzquierdo). Así. se comenzaría tratando el nivel 1. 2. postorden(a->hDerecho). el 3 y así sucesivamente. tratar(a). Al contrario que en los métodos de recorrido en profundidad. // esta cola esta implementada previamente. En el árbol de la figura el recorrido en inorden sería: 2. seguidamente el nivel 2. 5. almacena punteros (posiciones de nodos de arbol) tipo_Pos nodo_actual. 2. //Realiza una operación en nodo } } Recorrido en inorden En este caso se trata primero el subárbol izquierdo. se debe utilizar una cola para recordar los subárboles izquierdos y derecho de cada nodo. 9. Por ello.void postorden(tArbol *a) { if (a != NULL) { postorden(a->hIzquiedo). } } //Realiza una operación en nodo Recorridos en amplitud (o por niveles) En este caso el recorrido se realiza en orden por los distintos niveles del árbol. En el árbol de la figura el recorrido en amplitud sería: 2. 7. El esquema algoritmo para implementar un recorrido por niveles es exactamente el mismo que el utilizado en la versión iterativa del recorrido en preorden pero cambiando la estructura de datos que almacena los nodos por una cola. Otra forma para entender el recorrido con este método seria seguir el orden: nodo izquierda. 5. 6. tratar(a). 11 y 4. 7. En un ABB (Árbol binario de búsqueda) este recorrido daría los valores de clave ordenados de menor a mayor. nodo raíz. 5. 11. 4 y 9. nodo derecha.

cola_inicializa(&cola_nodos). los árboles binarios son construidos típicamente con una estructura de nodos y punteros en la cual se almacenan datos. también contiene un puntero a un único nodo. en este caso se imprime if (nodo_actual->izq != null) // si existe. Los árboles binarios también pueden ser almacenados como una estructura de datos implícita en vectores. En ocasiones. este método no . y si el árbol es un árbol binario completo. y necesario cola_enqueue(A. En un lenguaje con registros y referencias.".if (vacio(A)) // sie el arbol esta vacio. Si un nodo tiene menos de dos hijos. En la figura adjunta se puede observar la estructura de dicha implementación. nodo_actual->info). salimos return. cada uno de estos nodos tiene una referencia o puntero a un nodo izquierdo y a un nodo derecho denominados hijos. if (nodo_actual->der != null) // si existe. ponemos el hijo derecho en la cola cola_enqueue(nodo_actual->der. } // al vaciarse la cola se han visitado todos los nodos del arbol } Métodos para almacenar árboles binarios Los árboles binarios pueden ser construidos a partir de lenguajes de programación de varias formas. // se encola la raiz while (!vacia(&cola_nodos)) { // mientras la cola no se vacie se realizara el recorrido nodo_actual = cola_dequeue(&cola_nodos) // de la cola saldran los nodos ordenados por nivel printf("%c. // obvio. algunos de los punteros de los hijos pueden ser definidos como nulos para indicar que no dispone de dicho nodo. &cola_nodos). // se "procesa" el nodo donde va el recorrido. &cola_nodos). ponemos el hijo izquierdo en la cola cola_enqueue(nodo_actual->izq. &cola_nodos).

mientras que sus padres (si los tiene) se encuentra en el índice (partiendo de que la raíz tenga índice cero). El árbol binario puede ser pensado como el árbol original inclinado hacia los lados. C. o un árbol doblemente encadenado. Por ejemplo. y el nodo sólo tiene un puntero al comienzo o la cabeza de esta lista. E. Tomaremos como notación la siguiente: si un nodo tiene un índice i. Cada nodo N ordenado en el árbol corresponde a un nodo N 'en el árbol binario. F. y el hijo derecho de N' es el nodo correspondiente al siguiente hermano de N. Una manera de pensar acerca de esto es que los hijos de cada nodo estén en una lista enlazada. sin ningún tipo de letras en aquellos nodos que tienen un hijo izquierdo. es decir. a través de su campo izquierdo. en el árbol de la izquierda. Un ejemplo de transformar el árbol n-ario a un árbol binario Cómo pasar de árboles n-arios a árboles FLOFO. Puede ser convertido en el árbol binario de la derecha. el cual en particular es usado en Lisp para representar árboles generales como árboles binarios. el hijo de la izquierda de N’ es el nodo correspondiente al primer hijo de N. D. encadenados junto con el campo derecho. con los bordes negros izquierdos representando el primer hijo y los azules representado los siguientes hermanos. Sin embargo. Las hojas del árbol de la izquierda serían escritas en Lisp como: (((M N) H I) C D ((O) (P)) F (L)) Que se ejecutará en la memoria como el árbol binario de la derecha. Codificación de árboles n-arios como árboles binarios Hay un mapeo uno a uno entre los árboles generales y árboles binarios. Esta representación como árbol binario de un árbol general. G). sus hijos se encuentran en índices 2i + 1 y 2i + 2. la A tiene 6 hijos (B. Este método tiene como ventajas el tener almacenados los datos de forma más compacta y por tener una forma más rápida y eficiente de localizar los datos en particular durante un preoden transversal.desaprovecha el espacio en memoria. desperdicia mucho espacio en memoria. . se conoce a veces como un árbol binario primer hijo hermano. el próximo nodo en orden entre los hijos de los padres de N.

puesto que Pascal no admite determinar si un puntero es mayor o menor que otro. Por tanto. * Todas las claves del subárbol derecho al nodo son mayores que la clave del nodo.Árbol binario de búsqueda Un árbol binario de búsqueda es aquel que es: .Una estructura vacía o . suponer que el tipo de datos de la clave es un puntero (da igual a lo que apunte). la . Cuestión: ¿Qué hay que hacer para obtener una lista de los números ordenada de mayor a menor? Una ventaja fundamental de los árboles de búsqueda es que son en general mucho más rápidos para localizar un elemento que una lista enlazada. son más rápidos para insertar y borrar elementos. En el ejemplo de la figura 5 las claves son números enteros. Si el árbol está perfectamente equilibrado -esto es.de estructuras tipo árbol. Esto se cumple también para todos los subárboles. Dada la raíz 4. Un ejemplo de árbol binario de búsqueda: Figura 5 Al definir el tipo de datos que representa la clave de un nodo dentro de un árbol binario de búsqueda es necesario que en dicho tipo se pueda establecer una relación de orden. las claves del subárbol izquierdo son menores que 4. Si se hace el recorrido de este árbol en orden central se obtiene una lista de los números ordenada de menor a mayor. * Ambos subárboles son árboles binarios de búsqueda. llamados subárboles y además cumplen lo siguiente: * Todas las claves del subárbol izquierdo al nodo son menores que la clave del nodo. Si se codifica el árbol en Pascal no se puede establecer una relación de orden para las claves. y las claves del subárbol derecho son mayores que 4. Por ejemplo. disjuntos.Un elemento o clave de información (nodo) más un número finito -a lo sumo dos.

5. Se inserta la clave 2 en el subárbol derecho de 1.diferencia entre el número de nodos del subárbol izquierdo y el número de nodos del subárbol derecho es a lo sumo 1. Operaciones básicas sobre árboles binarios de búsqueda .6 Se crea un árbol cuya raíz tiene la clave 1. donde se emplearía búsqueda dicotómica para localizar un elemento.2. que sin llegar a cumplir al 100% el criterio de árbol perfectamente equilibrado.entonces el número de comparaciones necesarias para localizar una clave es aproximadamente de logN en el peor caso. Además. int elem) { if (a == NULL) return FALSE. A continuación se inserta la clave 3 en el subárbol derecho de 2. suponer que se tiene un árbol vacío.Búsqueda Si el árbol no es de búsqueda. Ahora bien. else if (a->clave < elem) return buscar(a->der. hasta encontrar su ubicación. elem). insertar la clave 7 en el árbol de la figura 5 requiere avanzar por el árbol hasta llegar a la clave 8.4. por ejemplo. elem). pero más eficiente que el de borrado en un array ordenado. El algoritmo de borrado en árboles es algo más complejo. Existen variaciones sobre estos árboles. De todas formas es poco probable que se de un caso de este tipo en la práctica. Simplemente hay que descender a lo largo del árbol a izquierda o derecha dependiendo del elemento que se busca. Aprovechando las propiedades del árbol de búsqueda se puede acelerar la localización. Continuando las inserciones se ve que el árbol degenera en una lista secuencial. Si las claves a introducir llegan de forma más o menos aleatoria entonces la implementación de operaciones sobre un árbol binario de búsqueda que vienen a continuación son en general suficientes. evitan problemas como el de obtener una lista degenerada. else if (a->clave > elem) return buscar(a->izq.de que no necesita hacer una reubicación de los elementos de la estructura para que esta siga ordenada después de la inserción. Ejemplo: 1.Inserción . boolean buscar(tarbol *a. } . es necesario emplear uno de los recorridos anteriores sobre el árbol para localizarlo. como los AVL o Red-Black (no se tratan aquí). e introducir la nueva clave en el subárbol izquierdo a 8. Suponer que se van a ir introduciendo las claves de forma ascendente. que admite claves de tipo entero.3. Dicho algoritmo funciona avanzando por el árbol escogiendo la rama izquierda o derecha en función de la clave que se inserta y la clave del nodo actual. else return TRUE. reduciendo drásticamente su eficacia para localizar un elemento. El resultado es idéntico al de una búsqueda secuencial. el algoritmo de inserción en un árbol binario de búsqueda tiene la ventaja sobre los arrays ordenados. para todos los nodos.

void insertar(tarbol **a. ¿Puede ser cualquier hoja? No. } else if ((*a)->clave < elem) insertar(&(*a)->der. y borrar a continuación dicha hoja. una vez encontrado el nodo a borrar: 1) El nodo no tiene descendientes. Se borra dicho nodo.Borrado La operación de borrado si resulta ser algo más complicada. Se recuerda que el árbol debe seguir siendo de búsqueda tras el borrado.La inserción tampoco es complicada. Ejemplo: en el árbol de la figura 5 se borra el nodo cuya clave es -1. else if ((*a)->clave > elem) insertar(&(*a)->izq. Pueden darse tres casos. de esta manera los nuevos enlaces mantienen la coherencia. resulta practicamente idéntica a la búsqueda. elem). Simplemente se borra. Se sustituirá la clave 4 por la clave 2. Al borrar dicho nodo es necesario mantener la coherencia de los enlaces. . Es más. 2) El nodo tiene al menos un descendiente por una sola rama. debe ser la que contenga una de estas dos claves: · la mayor de las claves menores al nodo que se borra. Suponer que se quiere borrar el nodo 4 del árbol de la figura 5. Suponer que se quiere borrar el nodo 4 del árbol de la figura 5. y su primer descendiente se asigna como hijo del padre del nodo borrado. (*a)->izq = (*a)->der = NULL. } . además de seguir manteniendo la estructura como un árbol binario de búsqueda. elem). El árbol resultante es: 3) El nodo tiene al menos un descendiente por cada rama. Si el elemento a insertar ya existe entonces no se hace nada. Se sustituirá la clave 4 por la clave 5. · la menor de las claves mayores al nodo que se borra. int elem) { if (*a == NULL) { *a = (arbol *) malloc(sizeof(arbol)). (*a)->clave = elem. La solución consiste en sustituir la información del nodo que se borra por el de una de las hojas. Cuando se llega a un árbol vacío se crea el nodo en el puntero que se pasa como parámetro por referencia.

/* se sustituye por la mayor de las menores */ free(aux). if (*a == NULL) /* no existe la clave */ return.6 ARBOLES DE DECISIÓN Y EL TIEMPO MÍNIMO PARA EL ORDENAMIENTO: Árbol de decisión Un árbol de decisión es un modelo de predicción utilizado en el ámbito de la inteligencia artificial.El algoritmo de borrado que se implementa a continuación realiza la sustitución por la mayor de las claves menores. elem). A continuación se muestra gráficamente el proceso de borrar el nodo de clave 4: Codificación: el procedimiento sustituir es el que desciende por el árbol cuando se da el caso del nodo con descencientes por ambas ramas. tarbol **aux). y después avanzar siempre a la derecha hasta encontrar un nodo hoja. tarbol *aux. } } 2. int elem) { void sustituir(tarbol **a. (aunque se puede escoger la otra opción sin pérdida de generalidad). if ((*a)->izq == NULL) *a = (*a)->der. &aux). elem). else if ((*a)->clave > elem) borrar(&(*a)->izq. Dada una base de datos se construyen diagramas de construcciones lógicas. else sustituir(&(*a)->izq. if ((*a)->clave < elem) borrar(&(*a)->der. void borrar(tarbol **a. else if ((*a)->der == NULL) *a = (*a)->izq. Para lograr esto es necesario descender primero a la izquierda del nodo que se va a borrar. else if ((*a)->clave == elem) { aux = *a. muy .

· Reduce el numero de variables independientes. Un árbol de decisión tiene unas entradas las cuales pueden ser un objeto o una situación descrita por medio de un conjunto de atributos y a partir de esto devuelve una respuesta la cual en últimas es una decisión que es tomada a partir de las entradas. podemos decir que los árboles de decisión son diagramas de decisiones secuenciales nos muestran sus posibles resultados. tiene un valor que puede ser comprado o vendido. El árbol de decisión suele contener nodos internos. Un nodo de probabilidad indica que debe ocurrir un evento aleatorio de acuerdo a la naturaleza del problema. refiriéndonos al ámbito empresarial. Se utilizan más los valores discretos por simplicidad. para la resolución de un problema. Un nodo interno contiene un test sobre algún valor de una de las propiedades. permitiendo la clasificación de nuevos casos siempre y cuando no existan modificaciones sustanciales en las condiciones bajo las cuales se generaron los ejemplos que sirvieron para su construcción. este tipo de nodos es redondo. los demás son cuadrados. Las ventajas de un árbol de decisión son: · Resume los ejemplos de partida. · Es una magnifica herramienta para el control de la gestión empresarial. Éstos ayudan a las empresas a determinar cuales son sus opciones al mostrarles las distintas decisiones y sus resultados. La opción que evita una pérdida o produce un beneficio extra tiene un valor. Los árboles de decisión se pueden usar para generar sistemas expertos. La habilidad de crear una opción. cuando se utilizan valores discretos en las funciones de una aplicación se denomina clasificación y cuando se utilizan los continuos se denomina regresión. Un nodo hoja representa el valor que devolverá el árbol de decisión y finalmente las ramas brindan los posibles caminos que se tienen de acuerdo a la decisión tomada. nodos hojas y arcos. Los valores que pueden tomar las entradas y las salidas pueden ser valores discretos o continuos. por lo tanto. Los árboles de decisión se utilizan en cualquier proceso que implique toma de decisiones. búsquedas binarias y árboles de juegos. Los Árboles de decisión son una técnica que permite analizar decisiones secuenciales basada en el uso de resultados y probabilidades asociadas. Un árbol de decisión lleva a cabo un test a medida que este se recorre hacia las hojas para alcanzar así una decisión. De forma más concreta. que sirven para representar y categorizar una serie de condiciones que ocurren de forma sucesiva. · Proporciona un alto grado de comprensión del conocimiento utilizado en la toma de decisiones. nodos de probabilidad. ejemplos de estos procesos son: .similares a los sistemas de predicción basados en reglas. · Explica el comportamiento respecto a una determinada tarea de decisión. · Facilita la interpretación de la decisión adoptada.

. · Sistemas Expertos · Árboles de juegos Los árboles de decisión generalmente son binarios. que nos indicara que el elemento no se encuentra en el árbol. . .Comparamos si el numero que estamos buscando es igual a la raíz. es decir que cuentan con dos opciones.Si no es igual se compara nuevamente el numero para saber si es mayor o menor que la raíz con lo que se despreciaría la mitad del árbol volviendo la búsqueda mas rápida. si es igual se devuelve la raíz y se termina la búsqueda.Si es menor recorremos la búsqueda hacia el lado izquierdo.Si es mayor se realiza la búsqueda hacia el lado derecho del árbol. Los pasos anteriores se realizan hasta encontrar el elemento buscado. el cual lo tomamos como si fuera una raíz y comparamos de la misma forma que la primera raíz. En el Árbol anterior realizaremos una búsqueda binaria con un árbol de decisión.· Búsqueda binaria. . hasta encontrar el siguiente elemento del árbol. aunque esto no significa que no puedan existir árboles de 3 o mas opciones BÚSQUEDA BINARIA Búsqueda binaria es el método en el cual la búsqueda se realiza partiendo el árbol en dos. Supongamos que se desea buscar un numero X en el árbol. o llegar a null. . el cual volvemos a comparar como lo hicimos con la raíz.

el mejor movimiento siguiente esta determinado por la consideración de todos los movimientos posibles y las posiciones resultantes.Un ejemplo de la implantación de esta función es considerando el numero de renglones. Entonces la función se mejorara en gran medida. columnas y diagonales restantes abiertas para un jugador menos el numero de las mismas para su oponente.ÁRBOLES DE JUEGOS Los árboles de juegos son una aplicación de los árboles de decisión. Ahora se introduce la posibilidad de prever varios movimientos. sin embargo la cuarta posición es sin duda mejor. Este árbol se conoce como árbol de juego cuya profundidad es igual a la profundidad de dicho árbol. por ejemplo la siguiente posición en un juego y sus posibles continuaciones : Dada un posición del tablero. Tal análisis no conduce sin embargo al mejor movimiento. se inicia con cualquier posición y se determinan todos los posibles movimientos en un árbol hasta un determinado nivel de previsión. como se ve en el ejemplo anterior cuando las cuatro primeras posibilidades dan todas el mismo valor de evaluación. . mas buena es esta posición). por lo que se debe mejorar esta función. Tomemos por ejemplo el conocido juego del gato y consideremos una función evalúa que acepta una posición del tablero y nos devuelve un valor numérico (entre mas grande es este valor.

puesto que se genera el árbol de acuerdo al nivel de previsión y cada jugador va diciendo que jugada le conviene mas de acuerdo a la evaluación de una determinada posición. ya que el hombre puede dejar pasar sin querer un detalle. . pues esta será la que perjudique mas a + y convendrá a -.deberá seleccionar la jugada que tenga el menor valor . . es claro que como el árbol empieza con el turno de +. De acuerdo al árbol anterior el mejor primer turno para + será la cruz en el centro. Así es como funciona un árbol de juego que es una aplicación de un árbol de decisión. ÁRBOLES DE DECISIÓN UTILIZADOS EN SISTEMAS EXPERTOS Los árboles de decisión se usan en los sistemas expertos porque son mas precisos que el hombre para poder desarrollar un diagnostico con respecto a algo. en esta fase se ve que el turno que sigue es de -. por lo que el jugador decidirá hacer este movimiento. y el turno del jugador 2 como -. A continuación se presenta un ejemplo de un sistema experto y de cómo puede llegar a diagnosticar que se emplee un fármaco X en una persona con presión arterial . en cambio la maquina mediante un sistema experto con un árbol de decisión puede dar un resultado exacto. Una deficiencia de este es que puede llegar a ser mas lento pues analiza todas las posibilidades pero esto a su vez es lo que lo vuelve mas preciso que al hombre. entonces el árbol estará evaluado de acuerdo a la conveniencia de +.Designamos el turno del jugador 1 como +.

5.Tiene presión alta.Tiene presión arterial baja. El árbol de decisión es un diagrama que representan en forma secuencial condiciones y acciones.. y NO es alérgico a antibióticos. la necesidad de describir condiciones y acciones llevan a los analistas a identificar de manera formal las decisiones que actualmente deben tomarse. Uso de árboles decisiones. 4. Los árboles también obligan a los analistas a considerar la consecuencia de las decisiones. Ellos proveen una visión gráfica de la toma de decisión necesaria. No le se le administra el fármaco X si: 1. es alérgico a los antibióticos y SI tiene otras alergias 2. De esta forma.Tiene presión arterial media y su índice de colesterol es alto. El . solo un camino será seguido dependiendo del valor actual de la variable evaluada. qué acciones deben ser tomadas y el orden en la cual la toma de decisión será efectuada. su azúcar en la sangre es bajo. Cada vez que se ejecuta un árbol de decisión. Se ha demostrado que los árboles de decisión son eficaces cuando es necesario describir problemas con más de una dimensión o condición.. en segundo lugar y así sucesivamente. en las que el objetivo es determinar el valor combinado de un conjunto de variables... Árboles de decisión. y basándose en el valor de cada una de ellas. 3. los árboles indican los conjuntos de datos que la gerenciarequiere para formular decisiones o tomar acciones.Tiene presión arterial media y su índice de colesterol es bajo. es decir. Se recomienda el uso del árbol de decisión cuando el número de acciones es pequeño y no son posibles todas las combinaciones. Un árbol de decisión sirve para modelar funciones discretas. muestraqué condiciones se consideran en primer lugar. También son útiles para identificar los requerimientos de datos críticos que rodean al proceso de decisión... Primero que todo. especifican las variables que son evaluadas. su azúcar en la sangre es alto. determinar la acción a ser tomada. El desarrollo de árboles de decisión beneficiado analista en dos formas.Tiene presión arterial alta. sin importar que este dependa de variables cuantitativas o cualitativas. Este método permite mostrar la relación que existe entre cada condición y el grupo de acciones permisibles asociado con ella.Tiene presión arterial alta y su azúcar en la sangre es bajo. 2.Se le administra un fármaco X al paciente si: 1..Tiene presión alta. es alérgico a antibióticos y NO tiene otras alergias. es difícil para ellos pasar por alto cualquier etapa del proceso de decisión. Los árboles de decisión son normalmente construidos a partir de la descripción de la narrativa de un problema. su azúcar en la sangre es alto.

El árbol de decisiones de un sistema complejo con muchas secuencias de pasos y combinaciones de condiciones puede tener un tamaño considerable. Si los árboles de decisión se construyen después de completar el análisis de flujo de datos. ya que se van comparando de dos en dos los elementos de la tabla. imaginando que deseamos realizar una ordenación creciente: 1.Se compara el primer elemento con el segundo.analista debe identificar y elaborar una lista de todos los datos utilizados en el proceso de decisión. Si nosotros deseamos ordenar dicha tabla de menor a mayor (ascendente) al realizar la comparación entre dos elementos se produce el intercambio en el momento en el que el primer elemento es mayor que el segundo. entonces el analista debe tener la certeza de identificar con precisión cada dato necesario para tomar la decisión. pero a la vez es uno de los menos eficaces. El elemento sube por la tabla. entonces es momento de considerar las tablas de decisión. Así hasta que llegamos . de ahí proviene su nombre. intercambiando también si es necesario. Ejemplo de Árbol de Decisión. Este método se basa en la ordenación por cambio de elementos. Métodos de Ordenamiento Método de la burbuja (BubleSort) Es uno de los métodos más extendidos y más fáciles. al igual que una burbuja en un recipiente. Si están desordenados se intercambian. En estos casos los analistas corren el riesgo de no determinar qué políticas o estrategias de la empresa son la guía para la toma de decisiones específicas. Los árboles de decisión no siempre son la mejor herramienta para el análisis de decisiones. Luego se mira el segundo con el tercero.. El gran número de ramas que pertenecen a varias trayectorias constituye más un problema que una ayuda para el análisis. Cuando aparecen estos problemas. entonces es posible que los datos críticos se encuentren definidos en el diccionariode datos (el cual describe los datos utilizados por el sistema y donde se emplean). Los pasos a seguir utilizando este método son los siguientes. Si únicamente se usan árboles de decisiones. aunque el árbol de decisión no muestra todo los datos. De esta forma el elemento más grande pasa a estar en el último lugar de la tabla.

Mientras Indice2 <> TotalElem .Fin Si 9.40.10. y se realizan dos búsquedas: una de izquierda a derecha. y otra de derecha a izquierda. 1.Repetimos lo mismo que antes pero ahora con todos los elemento. quedando: {9. Ejemplo con Algoritmo. y la segunda el valor 9. Su hace menos 1 pasadas porque el primero de los objetos. pero ya se han cruzado. el 9.Repetir 3.40. ya está ordenado.Ordenado = Verdadero 4.Fin Mientras 11.Si Tabla(Indice2) > Tabla(Indice + 1) Entonces 6.Ordenado = Falso 8.10. Se intercambian: {21.9. Para terminar la división.Ahora tenemos dividido el array en dos arrays más pequeños: el {9.Indice2 = Indice2 + 1 10.10. buscando un elemento mayor que el pivote. Verdadero o Falso. así que paramos.4..35} <-. buscando un elemento menor que el pivote.40. Este método se basa en la táctica "divide y vencerás" .35} <-.4.4. Para hacer esta división. se intercambian. Este método finaliza en el momento en el que se han realizado tantas pasadas como objetos .10. Normalmente se toma como pivote el primer elemento de array.. y se repetiría el mismo proceso * El Metodo Quick Sort*/ . 3. Por ejemplo.Si seguimos la búsqueda. la primera encuentra el valor 40.1 o Ordenado = Verdadero Método de ordenación rápida (Quicksort).Repetimos el primer paso pero esta vez con otro elemento menos.9.1 hacer 5. y se mueven todos los elementos menores que este pivote a su izquierda.Indice = 1 2. Cuando se han encontrado los dos.Intercambiar Tabla(Indice2). y se sigue realizando la búsqueda hasta que las dos búsquedas se encuentran. De esta forma tenemos en la última posición de nuestra tabla el elemento más grande.Hasta que Indice > TotalElem .9. que consiste en ir subdividiendo el array en arrays más pequeños. mayor que pivote. La búsqueda de izquierda a derecha encuentra el valor 40. Tabla(Indice2 + 1) 7. para dividir el array {21.1 hay en la lista. A continuación se aplica el mismo método a cada una de las dos partes en las que queda dividido el array. Para comprobar que no se ha realizado ningún tipo de cambio necesitaremos insertar una variable de tipo booleana que solo permitirá dos valores. se toma un valor del array como pivote.se toma como pivote el 21.35} <-.35}.al último elemento. se coloca el pivote en su lugar (en el número encontrado por la segunda búsqueda. ya que este también está ordenado. 2. menor que el pivote. como es lógico si pensamos que los demás ya están ordenados. que ya está ordenado. y ordenar éstos.35}. menos el último.4} y el {40. los pasos serían: {21. y los mayores a su derecha. y la búsqueda de derecha a izquierda encuentra el valor 10.21.4.40.10.

int j = de. j--. i++. } pause(i. } if ( i <= j) { int aux = a[i]. }while (i <= j). int mitad = a [(iz+de)/2].j). if( j > iz ) QuickSort( a.7 ISOMORFISMOS DE ÁRBOLES Dos graficas simples G1 y G2 son isomorfas si y solo si existe una función f uno a uno y sobre del conjunto de vértices de G1 al conjunto de vértices de G2 que preserva la relación de adyacencia en el sentido de que los vértices vi y vj son adyacentes en G1 si y solo si los vértices f(vi) y f(vj) son adyacentes en G2. iz.public class QuickAl extends Metodo { public void QuickSort(int a[]. int de) throws Exception { int i = iz. int iz. } 2. j ). do { while(a[i] < mitad) { i++. } while(a[j] > mitad) { j--. if( i < de ) QuickSort( a. a[i] = a[j]. i. a[j] = aux. de ). Ejemplos a) .

Existe isomorfismo porque: f(a) = 1. tienen las mismas propiedades. El descubrimiento de Platón de que la forma es lo que importa se recoge en matemáticas con el concepto de isomorfismo. ambas son indistinguibles. Dos estructuras matemáticas entre las que existe una relación de isomorfismo se llaman isomorfas. f(b) = 3. f(e) = 5 b) Los árboles con raíz no son isomorfos. y cualquier enunciado es simultáneamente cierto o falso. Cuando entre dos estructuras hay un isomorfismo. f(d) = 4. . relaciones. f(c) = 2 . que hay en X en las que hay en Y. El concepto matemático de isomorfismo (del griego iso-morfos: Igual forma) pretende captar la idea de tener la misma estructura. pues existe una invariante debido a que el árbol T1 tiene un vértice de grado 2 en el nivel 1 y T2 no. etc. Una aplicación f:X→Y entre dos conjuntos dotados del mismo tipo de estructura es un isomorfismo cuando cada elemento de Y proviene de un único elemento de X y f transforma las operaciones. Por eso en matemáticas las estructuras deben clasificarse salvo isomorfismos.

 Características del isomorfismo El descubrimiento de un isomorfismo entre dos estructuras significa esencialmente que el estudio de cada una puede reducirse al de la otra. si X es un número real positivo con el producto e Y es un número real con la suma. f es un isomorfismo. que suele ser más simple. entonces a cada punto del espacio podemos asociarles sus tres coordenadas cartesianas. cómo cuando comparten aristas medianto sockets o threads. Algoritmo de Kruskal . lo que nos da dos puntos de vista diferentes sobre cada cuestión y suele ser esencial en su adecuada comprensión. Otro ejemplo: si en el espacio E elegimos una unidad de longitud y tres ejes mutuamente perpendiculares que concurren en un punto. y este método de abordar los problemas geométricos es el corazón de la llamada geometría analítica. Cuando en E consideramos la distancia que define la unidad de longitud fijada y en R³ consideramos la distancia que define la raíz cuadrada de la suma de los cuadrados de las diferencias. Este descubrimiento fundamental de Descartes permite enunciar cualquier problema de la geometría del espacio en términos de sucesiones de tres números reales. el logaritmo ln:X→Y es un isomorfismo. porque ln(ab)=ln(a)+ln(b) y cada número real es el logaritmo de un único número real positivo. aquellos sobre los que está hecha la comparación. que será común tanto cuando ambos procesos no comparten aristas. obteniendo así una aplicación f:E→R³ en el conjunto de las sucesiones de tres números reales. También significa una analogía como una forma de inferencia lógica basada en la asunción de que dos cosas son la misma en algunos aspectos. Esto significa que cada enunciado sobre el producto de números reales positivos tiene (sin más que sustituir cada número por su logaritmo) un enunciado equivalente en términos de la suma de números reales.Ejemplos de isomorfismos  Por ejemplo. Algoritmos simples de Kruskal y Prim A continuación se detalla el algoritmo seguido por los procesos de Kruskal y Prim.

Salida: Las aristas de un árbol generador minimal. el algoritmo de Kruskal va generando diferentes bosques con las aristas que va seleccionando y posteriormente se van uniendo hasta formar el árbol de expansión mínimo. Algoritmo de Prim Pseudocódigo del algoritmo: . mientras (i < N) hacer escoger la arista de peso mínimo A de entre todas las que aún no han sido escogidas.Pseudocódigo del algoritmo: Entrada: Un grafo ponderado conexo con todos sus pesos diferentes. fsi fmientras Por lo tanto. i := i + 1. como podemos ver. si A no forma ciclo con las que ya forman parte de la Salida entonces añadir A a la Salida. N := tamaño del grafo de Entrada en número de vértices. i : = 1.

que estamos en la primera iteración entonces escoge la arista A de menor peso. fsi fmientras En este caso podemos observar que el algoritmo de Prim a cada iteración va formando un árbol que va creciendo hasta completar el árbol de expansión mínimo del grafo de entrada. . i := i + 1. N := tamaño del grafo de Entrada en número de vértices. Salida: Las aristas de un árbol generador minimal. si la Salida aún está vacía. es decir. fsi si A no forma ciclo con las que ya forman parte de la Salida entonces añadir A a la Salida. mientras (i < N) hacer escoger la arista de peso mínimo A de entre todas las que aún no han sido escogidas y son incedentes a alguna que ya forma parte de la Salida.Entrada: Un grafo ponderado conexo con todos sus pesos diferentes. i : = 1.