Ing. En Sistemas Computacionales
Estructura de Datos
Unidad V Estructuras no linealesestáticas y dinámicas.
(Árboles y grafos)
Ing. Néstor Alejandro Carrillo López
ArbolesUn árbol es un conjunto finito de nodos:
1. Si la colección es vacía, se dice que el árbol es vacio
2. En caso contrario, un árbol A consiste de un nodo especial llamado raíz y n (sub)arboles no vacios T1,T2,…,Tn. La raíz de A se conecta con la raíz de cada Ti por un arco dirigido.
Relaciones entre nodosTodo nodo nj, exceptuando el raíz, esta
conectado exclusivamente a otro nodo nk
donde:• nj es el padre de nk (Ej., B es el padre de E)
• nk es uno de los hijos de nj (Ej., E es un hijo de B)
• Nodos con el mismo padre son “hermanos” (Ej., B , C y D)
• Nodos sin hijos son llamados “hojas” (Ej., G)
Árboles binarios
• Un árbol binario es unárbol en el cual cadanodo puede tener comomáximo dos hijos
• Un árbol binario sedefine como:– un árbol vacio, o– un nodo raíz con unsubárbol izquierdo y unsubárbol derecho
Representación en Memoria
Hay dos formas tradicionales de representar unárbol binario en memoria:
• Por medio de datos tipo punteros tambiénconocidos como variables dinámicas o listas.
• Por medio de arreglos(estáticas).
Sin embargo, la más utilizada es la primera, puestoque es la más natural para tratar este tipo deestructuras.
Representación en Memoria
• Los nodos del árbol binario seránrepresentados como registros que contendráncomo mínimo tres campos. En un campo sealmacenará la información del nodo. Los dosrestantes se utilizarán para apuntar al subárbolizquierdo y derecho del subárbol en cuestión.
• Cada nodo se representa gráficamente de lasiguiente manera:
Declaración de árbol binario• Se definirá el árbol con un dato de tipo objecto (puede ser cualquier
otra tipo de datos) y dos hijos: izquierdo (izq) y derecho (der). Para representar los enlaces con los hijos se utilizan punteros. El árbol vacío se representará con un puntero nulo.
• La clase nodo binario puede declarar de la siguiente manera:
Class NodoB{ Object dato; NodoB izq;NodoB der;
NodoB (){ this (null);} NodoB ( Object o ) { this(o,null,null);}NodoB(Object o, NodoB i, NodoB d) {dato=0; izq=i; der=d;}
}
Declaración de árbol binario• Se definirá el árbol con un dato de tipo objecto (puede ser cualquier otra tipo de datos)
y dos hijos: izquierdo (izq) y derecho (der). Para representar los enlaces con los hijos se utilizan punteros. El árbol vacío se representará con un puntero nulo.
• La clase nodo binario puede declarar de la siguiente manera:
public class NodoBinario {//atributosObject dato;NodoBinario izquierdo;NodoBinario derecho;
//constructorespublic NodoBinario() { this(null); }
public NodoBinario(Object elDato){ this( elDato, null, null); }
public NodoBinario(Object elDato, NodoBinario menor, NodoBinario mayor){ dato=elDato; izquierdo=menor; derecho=mayor; }
Operaciones básicas en arboles
• Crear un árbol vacio
• Verificar si el árbol esta vacio
• Insertar un nodo
• Eliminar un nodo
• Recorrer un árbol
Recorridos de arboles
• Procedimientos que visitan todos los nodos de un árbol efectuando una acción sobre cada uno.
• Existen dos formas posibles de recorrer un árbol no vacio
Amplitud: el proceso se realiza horizontalmente desde la raíz a todos sus hijos, luego a los hijos de sus hijos y así sucesivamente
Profundidad: se sigue un camino desde la raíz a través de un hijo antes de proseguir al siguiente hijo
Ejemplo de recorrido en amplitud
Recorridos en profundidad
• Existen tres formas posibles de recorrer en profundidad un árbol no vacio, según cuando la raíz sea visitada
Recorrido Características
Pre orden se visita la raíz;se recorre el subárbol izquierdo;se recorre el subárbol derecho;
inorden se recorre el subárbol izquierdo;se visita la raíz;se recorre el subárbol derecho;
Post-orden se recorre el subárbol izquierdo;se recorre el subárbol derecho;se visita la raíz;
Recorridos en profundidad
• Pre orden
se visita la raíz;
se recorre el subárbol izquierdo;
se recorre el subárbol derecho;
Recorridos en profundidad
• Recorrido inorden
se recorre el subárbol izquierdo;
se visita la raíz;
se recorre el subárbol derecho;
Recorridos en profundidad• Post-orden
se recorre el subárbol izquierdo;
se recorre el subárbol derecho;
se visita la raíz;
Carga (Nodo)• 1. leer información (INFO)• 2. Hacer NODO^.INFO <- INFO• 3. Escribir “Existe nodo por la izquierda?”• 4. Leer respuesta• 5. Si respuesta es afirmativa• entonces• CREA (OTRO) {Crear un nuevo nodo}• Hacer NODO^.IZQ<-OTRO• Regresar a CARGA con NODO^.IZQ• {Llamada recursiva}• si no• Hacer NODO^.IZQ<-Null• 6. {Fin del condicional del paso 5}• 7. Escribir “Existe nodo por derecha?”• 8. Leer respuesta• 9. Si respuesta es afirmativa• entonces• CREA (OTRO) {Crea un nuevo nodo}• Hacer NODO^.DER <-OTRO• Regresar a CARGAR con NODO^.DER• {Llamada recursiva}• si no• Hacer NODO^.DER<- Null• 10. {Fin de condicional del paso 9}•
Algoritmo de preordenPREORDEN(NODO){El algoritmo realiza el recorrido preorden en un árbol binario.
NODO es un dato de tipo puntero }{INFO, IZQ Y DER son campos del registro nodo. INFO es una
variable de tipo carácter. IZQ y DER son variables de tipo puntero}
1. Si NODO <> Null entoncesvisitar el NODO {Escribir NODO^.INFO}
Regresar a PREORDEN con NODO^.IZQ{Llamada recursiva a PREORDEN con la rama izquierda del nodo en cuestión}Regresar a PREORDEN con NODO^.DER{Llamada recursiva a PREORDEN con la rama derecha del nodo en cuestión}
2. {Fin de condicional del paso 1}
INORDEN (NODO){El algoritmo realiza el recorrido inorden en un árbol binario.
NODO es un registro de tipo puntero}{INFO, IZQ y DER son campos del registro nodo. INFO es una
variable de tipo carácter. IZQ y DER son variables de tipo puntero}
1. Si NODO <> Null entoncesRegresar a INORDEN con NODO^.IZQ
{Llamada recursiva a INORDEN con la rama izquierda del nodo en cuestion}Visitar el NODO {Escribir NODO^.INFO}Regresar a INORDEN con NODO^.DER{Llamada recursiva a INORDEN con la rama derecha del nodo en cuestión}
2. {Fin de condicional del paso 1}
POSTORDEN(NODO){El algoritmo realiza el recorrido postorden en un árbol binario. NODO es
un dato de tipo puntero}{INFO, IZQ y DER son campos del registro nodo. INFO es una variable de
tipo carácter IZQ y DER son variables de tipo puntero}1. Si NODO<>Null entonces
Regresa POSTORDEN con NODO^.IZQ{Llamada recursiva a POSTORDEN con la rama izquierda del nodo en cuestión}
Regresar a POSTORDEN con NODO^.DER{Llamada recursiva a POSTORDEN con la rama derecha del nodo en
cuestion}
Visitar el NODO {Escribir NODO^.INFO}2. {Fin de condicional del paso 1}
Grafos• Un grafo G es un par (V,E), tal que:
V: conjunto de nodos
E: conjunto de arcos conectando a los nodos en V
Un arco e = (u,v) es un par de nodos
Grafos dirigidos y no dirigidos
• Dirigido (o Digrafo)
Cada linea tiene una direcciona su sucesor
Note que <vi, vj> ≠ <vj, vi>
• No dirigido
Las lineas no tienen direccion
Note <vi, vj> = <vj, vi>。
Operaciones en grafos
• Considere un grafo G y dos nodos x y y
-añade(G, x,y): añade en G un arco de x a y, si no existe
- borra(G, x,y): suprime un arco de x a y, si existe
- adyacente(G, x,y): verifica si hay un arco de x a y en G
- vecinos(G, x): lista todos los nodos y tal que hay un arco entre x y y
Operaciones en grafos
• En los grafos que tienen valores asociados a sus arcos, también se tienen:
- asigna_valor(G, x,y,v): asigna el valor asociado al arco (x,y) a v.
-obtener_valor(G, x,y): regresa el valor asociado al arco (x,y).