Documentos de Académico
Documentos de Profesional
Documentos de Cultura
1. INTRODUCCIÓN.
Hasta ahora las estructuras de datos que hemos estudiado eran de tipo lineal, o
sea,existía una relación de anterior y siguiente entre los elementos que la
componían(cada elemento tendrá uno anterior y otro posterior , salvo los casos de
primero y último).Pues bien, aquí se va a estudiar una estructuración de los datos
más compleja: los árboles.
Usando esta notación,un árbol tiene uno y sólo un nodo raíz y uno o más nodos
hoja.
etc...
RECORRIDOS DE UN ÁRBOL.
En una estructura lineal resulta trivial establecer un criterio de movimiento
por la misma para acceder a los elementos, pero en un árbol esa tarea no
resulta tan simple.No obstante, existen distintos métodos útiles en que
podemos sistemáticamente recorrer todos los nodos de un árbol.Los tres
recorridos más importantes se denominan preorden,inorden y
postorden aunque hay otros recorridos como es el recorrido por niveles.
13.Listado postorden.
A=Ar=AvAsr=AuAwvAsr= uAwvAsr=uAxAyAzwvAsr=
uxAyAzwvAsr=uxyAzwvAsr=uxyzwvAsr=
uxyzwvApAqsr=uxyzwvpAqsr=uxyzwvpqsr.
14.Listado inorden.
A=Ar=AvrAs=AuvAwrAs= uvAwrAs=uvAxwAyAzrAs=uvxw
AyAzrAs=uvxwyAzrAs=uvxwyzrAs=
uvxwyzrApsAq=uvxwyzrpsAq=uvxwyzrpsq.
.
4. HIJO_IZQDA(n,T).Devuelve el descendente más a la izquierda en el
siguiente nivel del nodo n en el árbol T, y devuelve NODO_NULO si n no
tiene hijo a la izquierda.Como precondición n no es NODO_NULO.
10.INSERTAR_HERMANO_DRCHA(n,Td,T).Inserta el árbol Td como
hermano a la derecha del nodo n que pertenece al árbol T.Como
precondición n no es NODO_NULO y Td no es el árbol vacío.
IMPLEMENTACIÓN DE ÁRBOLES.
Esta representación usa la propiedad de los árboles de que cada nodo tiene un
único padre.Con esta representación el padre de un nodo puede encontrarse en
tiempo constante.Un camino hacia arriba en el árbol puede seguirse atravesando
el árbol en tiempo proporcional al número de nodos en el camino.Podemos
soportar también el operador ETIQUETA añadiendo otra matriz L ,tal que L[i] es
la etiqueta del nodo i ,o haciendo que los elementos de la matriz A sean registros
consistiendo en un entero(cursor)y una etiqueta.EJEMPLO:Véase el árbol de la
figura 7:
La representación de padre por cursores no facilita las operaciones que requieren
información de hijos.Dado un nodo n ,es costoso determinar los hijos de n o la
altura de n.Además,la representación por cursores del padre no especifica el
orden de los hijos de un nodo.Por tanto,operaciones como HIJO_IZQDA y
HERMANO_DRCHA no están bien definidas.Podríamos imponer un orden
artificial,por ejemplo,numerando los hijos de cada nodo después de numerar el
padre,y numerar los hijos en orden creciente de izquierda a derecha.
Una forma útil e importante de representar árboles es formar para cada nodo una
lista de sus hijos.Las listas pueden representarse por cualquier método,pero como
el número de hijos que cada nodo puede tener puede ser variable,las
representaciones por listas enlazadas son las más apropiadas.La figura 8 sugiere
como puede representarse el árbol del ejemplo de la figura 7:
Hay una matriz de celdas de cabecera indexadas por nodos ,que suponemos
numerados 0,1,2,...,n-1. Cada punto de cabecera apunta a una lista enlazada de
elementos que son nodos.Los elementos sobre una lista encabezada
por cabecera[i] son los hijos de i(por ejemplo, 9 y 4 son los hijos de 8).Si
desarrollamos la estructura de datos que necesitamos en términos de un tipo de
dato abstracto tLista (de nodos) y damos una implementación particular de
listas,puede verse como las abstracciones encajan.
#include /*Definidas apropiadamente*/
#define MAXNODOS 100 /*Por ejemplo*/
#define NODO_NULO -1
L=T.cabecera[n];
if(PRIMERO(L)==FIN(L))
return NODO_NULO; /*No tiene hijos*/
else
return RECUPERA(PRIMERO(L),L); /*Recupera el primero(izqda)*/
}
Al igual que ocurre en los TDA estudiados (Listas,Pilas o Colas), un nodo puede
ser declarado de forma que la estructura del árbol pueda ir en aumento mediante
la obtención de memoria de forma dinámica,haciendo una petición de memoria
adicional cada vez que se quiere crear un nuevo nodo.
#define ARBOL_VACIO NULL
#define NODO_NULO NULL
nodo RaizAr(tArbol T)
{
return T;
}
return raiz;
}
void Destruir(tArbol T)
{
if(T){
destruir(T->hizqda);
destruir(T->herdrcha);
free(T);
}
}
Ti->herdrcha=n->hizqda;
Ti->padre=n;
n->hizqda=Ti;
}
if(n==raizAr(T)){
error("Memoria Insuficiente.");
}
Td->herdrcha=n->herdrcha;
Td->padre=n->padre;
n->herdrcha=Td;
}
Taux=n->hizqda;
if(Taux!=ARBOL_VACIO){
n->hizqda=Taux->herdrcha;
Taux->padre=NODO_NULO;
Taux->herdrcha=NODO_NULO;
}
return Taux;
}
Taux=n->herdrcha;
if(Taux!=ARBOL_VACIO){
n->herdrcha=Taux->herdrcha;
Taux->padre=NODO_NULO;
Taux->herdrcha=NODO_NULO;
}
return Taux;
}
Como vemos hemos implementado creaRaiz de manera que el árbol devuelto es
un único nodo.Es posible construir en C un procedimiento con un número
variable de parámetros:
Recordemos que los recorridos de un árbol pueden ser de una forma directa en
Preorden, Inorden y Postorden.A continuación veremos la implementación de
estos tres recorridos. Así mismo,veremos un procedimiento de lectura de un árbol
en preorden.
PREORDEN
1. Visitar la raíz.
En esta función hemos supuesto que existe una rutina Escribir que tiene como
parámetro de entrada un valor de tipo tEtiqueta que se encarga de imprimir en la
salida estándar.Por ejemplo,si hemos realizado typedef int tEtiqueta la función
podría ser la siguiente:
void Escribir(tEtiqueta et)
{
fprintf(stdout,"%d",(int)et);
}
Por otro lado,en los programas C hemos usado el operador de desigualdad entre
un dato de tipo nodo y la constante ARBOL_VACIO.Para hacerlo más
independiente de la impementación sería conveniente programar una función que
podríamos llamar Arbol_Vacio que se añadiría como una nueva primitiva que nos
devuelve si el subárbol que cuelga del nodo es un árbol vacío.
m=raizAr(T);
do{
if(m!=NODO_NULO){
Escribir(etiquetaAr(n,T));
PUSH(m,P);
m=hizqdaAr(m,T);
}
else if(!VACIA(P)){
m=herdrchaAr(TOPE(P),T);
POP(P);
}
}while(!VACIA(P));
INORDEN
2. Visitar la raíz.
c=hizqdaAr(n,T);
if(c!=NODO_NULO){
InordenArbol(c,T);
Escribir(etiquetaAr(n,T));
for(c=herdrchaAr(c,T);c!=NODO_NULO;c=herdrchaAr(c,T))
InordenArbol(c,T);
}
else Escribir(etiquetaAr(n,T));
}
POSTORDEN
3. Visitar la raíz.
for(c=hizqdaAr(n,T);c!=NODO_NULO;c=herdrchaAr(c,T))
PostordenArbol(c,T);
Escribir(etiquetaAr(n,T));
}
LECTURA
if(comparar(etHijo,FINAL)){
Hijo=creaRaiz(etHijo);
insertar_hijo_izqda(n,Hijo,T);
Lectura2(hizqdaAr(n,T),T);
}
if(comparar(etHermano,FINAL)){
Hermano=creaRaiz(etHermano);
insertar_hermano_drcha(n,Hermano,T);
Lectura2(herdrchaAr(n,T),T);
}
}
tArbol Lectura()
{
tArbol T;
tEtiqueta et;