You are on page 1of 26

ARBOLES GENERALES

1. INTRODUCCIN.
Hasta ahora las estructuras de datos que hemos estudiado eran de tipo lineal, o
sea,exista una relacin de anterior y siguiente entre los elementos que la
componan(cada elemento tendr uno anterior y otro posterior , salvo los casos de
primero y ltimo).Pues bien, aqu se va a estudiar una estructuracin de los datos
ms compleja: los rboles.
Este tipo de estructura es usual incluso fuera del campo de la informtica.El
lector seguramente conoce casos como los rboles gramaticales para analizar
oraciones,los rboles genealgicos ,representacin de jerarquas,etc...La
estructuracin en rbol de los elementos es fundamental dentro del campo de la
informtica aplicndose en una amplia variedad de problemas como veremos ms
adelante.
En principio podemos considerar la estructura de rbol de manera intuitiva como
una estructura jerrquica.Por tanto,para estructurar un conjunto de elementos
ei en rbol, deberemos escoger uno de ellos e1 al que llamaremos raz del
rbol.Del resto de los elementos se selecciona un subconjunto
e2,...,ek estableciendo una relacin padre-hijo entre la raz y cada uno de dichos
elementos de manera que e1 es llamado el padre de e2,de e3,...ek y cada uno de
ellos es llamado un hijo de e1.Iterativamente podemos realizar la misma
operacin para cada uno de estos elementos asignando a cada uno de ellos un
nmero de 0 o ms hijos hasta que no tengamos ms elementos que insertar.El
nico elemento que no tiene padre es e1,la raz del rbol.Por otro lado hay un
conjunto de elementos que no tienen hijos aunque s padre que son llamados
hojas.Como hemos visto la relacin de paternidad es una relacin uno a muchos.
Para tratar esta estructura cambiaremos la notacin:

Las listas tienen posiciones.Los rboles tienen nodos.

Las listas tienen un elemento en cada posicin.Los rboles tienen una


etiqueta en cada nodo (algunos autores distinguen entre rboles con y sin
etiquetas.Un rbol sin etiquetas tiene sentido aunque en la inmensa
mayora de los problemas necesitaremos etiquetar los nodos. Es por ello
por lo que a partir de ahora slo haremos referencia a rboles etiquetados).

Usando esta notacin,un rbol tiene uno y slo un nodo raz y uno o ms nodos
hoja.
Desde un punto de vista formal la estructura de datos rbol es un caso particular
de grafo, ms concretamente,en la teora de grafos se denota de forma similar
comorbol dirigido. A pesar de ello,la definicin formal ms usual de rbol en
ciencias de la computacin es la recursiva:

El caso bsico es un rbol con un nico nodo.Lgicamente este nodo es a


la vez raz y hoja del rbol.

Para construir un nuevo rbol a partir de un nodo nr y k rboles


A1 ,A2,...,Ak de races n1,n2,...,nk con N1,N2,...,Nk elementos cada uno
establecemos una relacin padre-hijo entre nr y cada una de las races de
los k rboles.El rbol resultante de N=1 + N1 + ... + Nk nodos tiene como
raz el nodo nr, los nodos n1,n2,...,nk son los hijos de nr y el conjunto de
nodos hoja est formado por la unin de los k conjuntos hojas iniciales.
Adems a cada uno de los Ai se les denota subrboles de la raz.

Ejemplo: Consideremos el ejemplo de la siguiente figura.

Podemos observar que cada uno de los identificadores representa un nodo y la


relacin padre-hijo se seala con una lnea.Los rboles normalmente se presentan
en forma descendente y se interpretan de la siguiente forma:

E es la raz del rbol.

S1,S2,S3 son los hijos de E.

S1,D1 componen un subrbol de la raz.

D1,T1,T2,T3,D3,S3 son las hojas del rbol.

etc...

Adems de los trminos introducidos consideraremos la siguiente


terminologa:

1. Grado de salida o simplemente grado.Se denomina grado de un


nodo al nmero de hijos que tiene.As el grado de un nodo hoja es
cero.En la figura anterior el nodo con etiqueta E tiene grado 3.

2. Caminos.Si n1,n2,...,nk es una sucesin de nodos en un rbol tal que


ni es el padre de ni+1 para 1<=i<=k-1 ,entonces esta sucesin se
llama un camino del nodo ni al nodo nk.La longitud de un camino es
el nmero de nodos menos uno, que haya en el mismo.Existe un
camino de longitud cero de cada nodo a s mismo.Ejemplos sobre la
figura anterior:
E,S2,D2,T3 es un camino de E a T3 ya que E es padre
de S2,ste es padre de D2,etc.

S1,E,S2 no es un camino de S1 a S2 ya que S1 no es padre


de E.

3. Ancestros y descendientes.Si existe un camino,del nodo a al


nodo b ,entonces a es un ancestro de b y b es un descendiente
de a.En el ejemplo anterior los ancestros de D2 son D2,S2 y E y sus
descendientes D2,T1,T2 y T3(cualquier nodo es a la vez ancestro y
descendiente de s mismo). Un ancestro o descendiente de un
nodo,distinto de s mismo,se llama un ancestro propio o
descendiente propio respectivamente.Podemos definir en trminos
de ancestros y descendientes los conceptos de raz,hoja y subrbol:

En un rbol,la raz es el nico nodo que no tiene ancestros


propios.

Una hoja es un nodo sin descendientes propios.

Un subrbol de un rbol es un nodo,junto con todos sus


descendientes.

Algunos autores prescinden de las definiciones de ancestro propio y


descendiente propio asumiendo que un nodo no es ancestro ni
descendiente de s mismo.

4. Altura.La altura de un nodo en un rbol es la longitud del mayor de


los caminos del nodo a cada hoja.La altura de un rbol es la altura
de la raz.Ejemplo: en la figura anterior la altura de S2 es 2 y la del
rbol es 3.

5. Profundidad.La profundidad de un nodo es la longitud del nico


camino de la raz a ese nodo.Ejemplo: en la figura anterior la
profundidad de S2 es 1.

6. Niveles.Dado un rbol de altura h se definen los niveles 0...h de


manera que el nivel i est compuesto por todos los nodos de
profundidad i.

7. Orden de los nodos.Los hijos de un nodo usualmente estn


ordenados de izquierda a derecha.Si deseamos explcitamente
ignorar el orden de los dos hijos, nos referiremos a un rbol como
un rbol no-ordenado.
La ordenacin izquierda-derecha de hermanos puede ser extendida
para comparar cualesquiera dos nodos que no estn relacionados
por la relacin ancestro-descendiente.La regla a usar es que
si n1 y n2 son hermanos y n1 est a la izquierda de n2, entonces todos
los descendientes de n1 estn a la izquierda de todos los
descendientes de n2.

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 mtodos tiles en que
podemos sistemticamente recorrer todos los nodos de un rbol.Los tres
recorridos ms importantes se denominan preorden,inorden y
postorden aunque hay otros recorridos como es el recorrido por niveles.
Si consideramos el esquema general de un rbol tal como muestra la figura
siguiente,los recorridos se definen como sigue:

8. El listado en preorden es:


Si el rbol tiene un nico elemento, dicho elemento es el
listado en preorden.

Si el rbol tiene ms de un elemento,es decir,una estructura


como muestra la figura 2,el listado en preorden es listar el
nodo raz seguido del listado en preorden de cada uno de los
subrboles hijos de izquierda a derecha.

9. El listado en inorden es:


Si el rbol tiene un nico elemento,dicho elemento es el
listado en inorden.

Si el rbol tiene una estructura como muestra la figura 2,el


listado en inorden es listar el subrbol A1 en inorden,y listar
el nodo raz seguido del listado en inorden de cada uno de los
subrboles hijos de izquierda a derecha restantes.

10. El listado en postorden es:


Si el rbol tiene un nico elemento,dicho elemento es el
listado en postorden.

Si el rbol tiene una estructura como muestra la figura 2,el


listado en postorden es listar en postorden cada uno de los
subrboles hijos de izquierda a derecha seguidos por el nodo
raz.

11. El listado por niveles es: desde i=0 hasta la altura h del rbol,listar
de izquierda a derecha los elementos de profundidad i.Como
podemos observar,un nodo n1 aparece antes que n2 en el listado por
niveles si la profundidad de n1 es menor que la profundidad
de n2 usando el orden de los nodos definido anteriormente para el
caso en que tengan la misma profundidad.
Como ejemplo de listados veamos el resultado que se obtendra sobre el
rbol A de la figura 3.
Los resultados de los listados de preorden,postorden e inorden son los
siguientes:

12. Listado preorden.


A=Ar=rAvAs=rvAuAwAs= rvuAwAs=rvuwAxAyAzAs=
rvuwxAyAzAs=rvuwxyAzAs=rvuwxyzAs =rvuwxyzsApAq=rvuwxyzspA
q=rvuwxyzspq.

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.

Por ltimo,el listado por niveles de este rbol es el


siguiente:r,v,s,u,w,p,q,x,y,z.
Finalmente es interesante conocer que un rbol no puede,en
general,recuperarse con uno solo de sus recorridos.Por ejemplo:Dada la

lista en inorden:vwyxzrtupsq,los rboles de la figura 4 tienen ese mismo


recorrido en inorden.

2. UNA APLICACIN: ARBOLES DE EXPRESIN.


Una importante aplicacin de los rboles en la informtica es la representacin de
rboles sintcticos,es decir,rboles que contienen las derivaciones de una
gramtica necesarias para obtener una determinada frase de un lenguaje.
Podemos etiquetar los nodos de un rbol con operandos y operadores de manera
que un rbol represente una expresin.Por ejemplo. en la figura 5 se representa
un rbol con la expresin aritmtica (x-y)*(z/t).

Para que un rbol represente una expresin,hay que tener en cuenta que:

Cualquier hoja est etiquetada con uno y slo un operando.

Cualquier nodo interior n est etiquetado por un operador.

En los rboles de expresin,la sucesin del preorden de etiquetas nos da lo que


se conoce como la forma prefijo de una expresin, en la que el operador precede
a su operando izquierdo y su operando derecho.En el ejemplo de la figura 5,el
preorden de etiquetas del rbol es *-xy/zt .
Anlogamente,la sucesin postorden de las etiquetas de un rbol expresin nos
da lo que se conoce como la representacin postfijo de una expresin.As en el
ejemplo,la expresin postfijo del rbol es xy-zt/*.
Finalmente,el inorden de una expresin en un rbol de expresin da la expresin
infijo en s misma,pero sin parntesis.En el ejemplo,la sucesin inorden del rbol
anterior es x-y*z/t.

3. EL TIPO DE DATO ABSTRACTO "ARBOL".

La estructura de rbol puede ser tratada como un tipo de dato abstracto.A


continuacin presentaremos varias operaciones sobre rboles y veremos como los
algoritmos de rboles pueden disearse en trminos de estas operaciones.Al igual
que con otros TDA,existe una gran variedad de operaciones que pueden llevarse
a cabo sobre rboles.
Como podremos observar,cuando se construye una instancia de este tipo,tiene al
menos un elemento, es decir,hasta ahora no hemos hablado de la existencia de un
rbol vaco .Realmente, segn la definicin que vimos,efectivamente el nmero
mnimo de nodos de un rbol es 1.En las implementaciones usaremos un valor
especial ARBOL_VACIO para el caso en que el rbol no contenga nodos,al igual
que en listas existe el concepto de lista vaca.
De igual forma es necesario expresar en algunos casos que un nodo no existe
para lo cual tambin usaremos otro valor especial NODO_NULO.Un ejemplo de
su uso puede ser cuando intentemos extraer el nodo hijo a la izquierda de un
nodo hoja.
A continuacin mostramos el conjunto de primitivas que nosotros
consideraremos:
1. CREAR_RAIZ(u).Construye un nuevo nodo r con etiqueta u y sin
hijos.Se devuelve el rbol con raz r,es decir,un rbol con un nico nodo.

2. DESTRUIR(T).Libera los recursos que mantienen el rbol T de forma


que para volver a usarlo se debe de asignar un nuevo valor con la
operacin de creacin.

3. PADRE(n,T).Esta funcin devuelve el padre del nodo n en el


rbol T .Si n es la raz ,que no tiene padre,devuelve NODO_NULO(un
valor que ser usado para indicar que hemos intentado salirnos del
rbol).Como precondicin n no es NODO_NULO (por tanto T no es
vaco).
.

4. HIJO_IZQDA(n,T).Devuelve el descendente ms 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 precondicin n no es NODO_NULO.

5. HERMANO_DRCHA(n,T).Devuelve el descendiente a la derecha del


nodo n en el rbol T ,definido para ser aquel nodo m con el mismo padre
que n ,es decir, padre p,de tal manera que m cae inmediatamente a la
derecha de n en la ordenacin de los hijos de p (Por ejemplo,vase el rbol
de la figura 6). Devuelve NODO_NULO si n no tiene hermano a la
derecha.Como precondicin n no es NODO_NULO.

6. ETIQUETA(n,T).Devuelve la etiqueta del nodo n en el


rbol T (manejaremos rboles etiquetados,sin embargo no es obligatorio
definir etiquetas para cada rbol).Como precondicin n no es
NODO_NULO.

7. REETIQUETA(e,n,T).Asigna una nueva etiqueta e al nodo n en el


rbol T.Como precondicin n no es NODO_NULO.

8. RAIZ(T).Devuelve el nodo que est en la raz del rbol T o


NODO_NULO si T es el rbol vaco.

9. INSERTAR_HIJO_IZQDA(n,Ti,T).Inserta el rbol Ti como hijo a la


izquierda del nodo n que pertenece al rbol T.Como precondicin n no es
NODO_NULO y Ti no es el rbol vaco.

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
precondicin n no es NODO_NULO y Td no es el rbol vaco.

11. PODAR_HIJO_IZQDA(n,T).Devuelve el subrbol con raz hijo a la


izquierda de n del rbol T el cual se ve privado de estos nodos.Como
precondicin n no es NODO_NULO.

12. PODAR_HERMANO_DRCHA(n,T).Devuelve el subrbol con raz


hermano a la derecha de n del rbol T el cual se ve privado de estos
nodos.Como precondicin n no es NODO_NULO.
A continuacin veremos cmo implementar el TDA rbol y posteriormente
implementaremos los algoritmos de
recorrido:PREORDEN,POSTORDEN,INORDEN.
IMPLEMENTACIN DE RBOLES.

UNA IMPLEMENTACIN MATRICIAL


Sea A un rbol en el cual los nodos se etiquetan 0,1,2,...,n-1,es decir,cada nodo
contiene un campo de informacin que contendr estos valores.La representacin
ms simple de A que soporta la operacin PADRE es una matriz lineal P en la
cual el valor de P[i] es un valor o un cursor al padre del nodo i.La raz
de A puede distinguirse dndole un valor nulo o un valor a l mismo como
padre.Por ejemplo.,podemos usar un esquema de cursores donde P[i]=j si el
nodo j es el padre del nodoi,y P[i]=-1 (suponemos que NODO_NULO=-1) si el
nodo i es la raz.La definicin del tipo sera:

#define MAXNODOS 100


#define NODO_NULO -1

/*Por ejemplo*/

typedef int nodo;


matriz*/
typedef int *ARBOL;

/*Indica una casilla de la

Esta representacin usa la propiedad de los rboles de que cada nodo tiene un
nico padre.Con esta representacin 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 nmero de nodos en el camino.Podemos
soportar tambin el operador ETIQUETA aadiendo 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:Vase el rbol de la
figura 7:

La representacin de padre por cursores no facilita las operaciones que requieren


informacin de hijos.Dado un nodo n ,es costoso determinar los hijos de n o la
altura de n.Adems,la representacin por cursores del padre no especifica el
orden de los hijos de un nodo.Por tanto,operaciones como HIJO_IZQDA y
HERMANO_DRCHA no estn bien definidas.Podramos imponer un orden
artificial,por ejemplo,numerando los hijos de cada nodo despus de numerar el
padre,y numerar los hijos en orden creciente de izquierda a derecha.
Nota:Tngase en cuenta que aunque esta implementacin no parece muy
adecuada, es posible ampliarla con la utilizacin de nuevos campos de
cursores.Por ejemplo:Podemos aadir dos matrices adicionales para almacenar
para cada nodo tanto el hijo a la izquierda como el hermano a la derecha.
IMPLEMENTACIN DE RBOLES POR LISTAS DE HIJOS
Una forma til e importante de representar rboles es formar para cada nodo una
lista de sus hijos.Las listas pueden representarse por cualquier mtodo,pero como
el nmero de hijos que cada nodo puede tener puede ser variable,las
representaciones por listas enlazadas son las ms 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 trminos de un tipo de
dato abstracto tLista (de nodos) y damos una implementacin particular de
listas,puede verse como las abstracciones encajan.
#include
#define MAXNODOS 100
#define NODO_NULO -1

/*Definidas apropiadamente*/
/*Por ejemplo*/

typedef int nodo;


typedef struct {
tLista cabecera[MAXNODOS];
tEtiqueta etiquetas[MAXNODOS];
nodo raiz;
}ARBOL;

Suponemos que la raz de cada rbol est almacenada explcitamente en el campo


raz.El -1 en el campo raz se usa para representar el rbol nulo o vaco.La
siguiente funcin muestra el cdigo para la operacin HIJO_IZQDA:
nodo HIJO_IZQDA(nodo n,ARBOL T)
{
tLista L;
L=T.cabecera[n];
if(PRIMERO(L)==FIN(L))
return NODO_NULO;
else
return RECUPERA(PRIMERO(L),L);

/*No tiene hijos*/


/*Recupera el primero(izqda)*/

Las dems operaciones son tambin fciles de implementar utilizando la anterior


estructura para el tipo de dato y usando las primitivas del TDA Lista.
Nota:Las funciones PRIMERO,FIN y RECUPERA usadas en el ejemplo anterior
pertenecen al TDA Lista anteriormente estudiado.
IMPLEMENTACIN DE RBOLES BASADA EN CELDAS
ENLAZADAS
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 obtencin de memoria de forma dinmica,haciendo una peticin de memoria
adicional cada vez que se quiere crear un nuevo nodo.
#define ARBOL_VACIO NULL
#define NODO_NULO NULL
typedef int tEtiqueta
/*Algn tipo adecuado*/
typedef struct tipocelda{
struct tipocelda *padre,*hizqda,*herdrchaAr;
tEtiqueta etiqueta;
}*nodo;
typedef nodo tArbol;

Observemos que bajo esta implementacin cada nodo de un rbol contiene 3


punteros: padre que apunta al padre,hizqda que apunta al hijo izquierdo y

herdrcha que apunta al hermano a la derecha del nodo.Para esta implementacin


de rbol vamos a presentar las funciones primitivas de las que hablbamos al
principio.Suponemos que para referenciar el nodo i la variable puntero apuntar a
ese nodo.Suponemos tambin unas variables de tipo nodo y que la variable T de
tipo rbol apunta a la raz del rbol.
nodo PadreAr(nodo n,tArbol T)
{
return n->padre;
}
nodo HizqdaAr(nodo n,tArbol T)
{
return n->hizqda;
}
nodo HerdrchaAr(nodo n,tArbol T)
{
return n->herdrchaAr;
}
tEtiqueta EtiquetaAr(nodo n,tArbol T)
{
return n->etiqueta;
}
void ReEtiquetaAr(tEtiqueta e,nodo n,tArbol T)
{
n->etiqueta=e;
}
nodo RaizAr(tArbol T)
{
return T;
}
tArbol Crea0(tEtiqueta et)
{
tArbol raiz;
raiz=(tArbol)malloc (sizeof(struct tipocelda));
if (!raiz){
error("Memoria Insuficiente.");
}
raiz->padre=NULL;
raiz->hizqda=NULL;
raiz->etiqueta=et;
return raiz;
}
void Destruir(tArbol T)
{
if(T){

destruir(T->hizqda);
destruir(T->herdrcha);
free(T);
}
}
void Insertar_hijo_izqda(nodo n,tArbol Ti,tArbol T)
{
Ti->herdrcha=n->hizqda;
Ti->padre=n;
n->hizqda=Ti;
}
void Insertar_hermano_drcha(nodo n,tArbol Td,tArbol T)
{
if(n==raizAr(T)){
error("Memoria Insuficiente.");
}
Td->herdrcha=n->herdrcha;
Td->padre=n->padre;
n->herdrcha=Td;
}
tArbol Podar_hijo_izqda(nodo n,tArbol T)
{
tArbol Taux;
Taux=n->hizqda;
if(Taux!=ARBOL_VACIO){
n->hizqda=Taux->herdrcha;
Taux->padre=NODO_NULO;
Taux->herdrcha=NODO_NULO;
}
return Taux;
}
tArbol Podar_hermano_drcha(nodo n,tArbol T)
{
tArbol 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 nmero
variable de parmetros:

El primero de los parmetros una etiqueta para el nodo raz.

Los restantes parmetros de tipo tArbol que se insertarn como


subrboles(hijos) del nodo raz.

Los podemos realizar mediante la implementacin de un nmero de parmetros


indeterminado y haciendo uso del tipo va_list que podemos encontrar en el
fichero cabecera stdarg.h.El procedimiento podra ser el siguiente:
tArbol CreaRaiz(tEtiqueta et,tArbol T1,...,tArbol Tn,NULL)
{
va_list ap;
nodo n,aux,raiz;
/*Reservamos memoria para el nodo raiz*/
raiz=(nodo)malloc(sizeof(struct tipocelda));
if(!raiz){
error("Memoria Insuficiente.");
}
/*Inicializamos el nodo raiz*/
raiz->padre=NULL;
raiz->hizqda=NULL;
raiz->herdrcha=NULL;
raiz->etiqueta=et;
/*Un bucle para insertar los subarboles*/
va_start(ap,et);
/*Inicio de argumentos*/
for(;;){
n=(nodo)va_arg(ap,nodo);
if(n==NULL)break;
/*No quedan mas hijos*/
if(raiz->hizqda)aux->herdrcha=n;
else raiz->hizqda=n;
aux=n;
aux->herdrcha=NULL;
aux->padre=raiz;
}
va_end(ap);
/*Final de argumentos*/
return(tArbol)raiz;
}

La llamada a la funcin tendra como parmetros una etiqueta para el nodo raz
del rbol resultante y una lista de nodos que podra ser vaca en cuyo caso el
rbol que resulta tiene un nico nodo:su raz con etiqueta et. Por ltimo,despus
de dicha lista,es necesario un parmetro adicional(NULL) que indica el final de
la lista tras cuya lectura el procedimiento dejara de aadir ms hijos al nodo raz
que se est construyendo.
IMPLEMENTACIN DE LOS RECORRIDOS DE UN RBOL
Recordemos que los recorridos de un rbol pueden ser de una forma directa en
Preorden, Inorden y Postorden.A continuacin veremos la implementacin de
estos tres recorridos. As mismo,veremos un procedimiento de lectura de un rbol
en preorden.
PREORDEN
1. Visitar la raz.

2. Recorrer el subrbol ms a la izquierda en preorden.

3. Recorrer el subrbol de la derecha en preorden.

Vamos a escribir dos procedimientos uno recursivo y otro no recursivo que


toman un rbol y listan las etiquetas de sus nodos en preorden.Supongamos que
existen los tipos nodo y tArbol con etiquetas del tipo tEtiqueta definidos
anteriormente en la implementacin por punteros.El siguiente procedimiento
muestra un procedimiento recursivo que , dado el nodo n,lista las etiquetas en
preorden del subrbol con raz en n.
void PreordenArbol(nodo n,tArbol T)
{
Escribir(etiquetaAr(n,T));
for(n=hizqdaAr(n,T);n!=NODO_NULO;n=herdrchaAr(n,T))
PreordenArbol(n,T);
}

En esta funcin hemos supuesto que existe una rutina Escribir que tiene como
parmetro de entrada un valor de tipo tEtiqueta que se encarga de imprimir en la
salida estndar.Por ejemplo,si hemos realizado typedef int tEtiqueta la funcin
podra 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 ms
independiente de la impementacin sera conveniente programar una funcin que
podramos llamar Arbol_Vacio que se aadira como una nueva primitiva que nos
devuelve si el subrbol que cuelga del nodo es un rbol vaco.
Para el procedimiento no recursivo,usaremos una pila para encontrar el camino
alrededor del rbol.El tipo PILA es realmente pila de nodos,es decir,pila de
posiciones de nodos. La idea bsica subyacente al algoritmo es que cuando
estamos en la posicin p,la pila alojar el camino desde la raz a p,con la raz en
el fondo de la pila y el nodo p a la cabeza.El programa tiene dos modos de
operar.En el primer modo desciende por el camino ms a la izquierda en el
rbol,escribiendo y apilando los nodos a lo largo del camino,hasta que encuentra
una hoja.A continuacin el programa entra en el segundo modo de operacin en
el cual vuelve hacia atrs por el camino apilado en la pila,extrayendo los nodos
de la pila hasta que se encuentra un nodo en el camino con un hermano a la
derecha.Entonces el programa vuelve al primer modo de operacin,comenzando
el descenso desde el inexplorado hermano de la derecha.El programa comienza
en modo uno en la raz y termina cuando la pila est vaca.
void PreordenArbol(tArbol T)
{
pila P;
/*Pila de posiciones:tElemento de la pila es el tipo nodo*/
nodo m;
P=CREAR(); /*Funcion de creacion del TDA PILA*/
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));
DESTRUIR(P);

/*Funcion del TDA PILA*/

INORDEN
1. Recorrer el subrbol ms a la izquierda en inorden.

2. Visitar la raz.

3. Recorrer el subrbol del siguiente hijo a la derecha en inorden.


Vamos a escribir un procedimiento recursivo para listar las etiquetas de sus
nodos en inorden.
void InordenArbol(nodo n,tArbol T)
{
nodo c;
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
1. Recorrer el subrbol ms a la izquierda en postorden.

2. Recorrer el subrbol de la derecha en postorden.

3. Visitar la raz.

El procedimiento recursivo para listar las etiquetas de sus nodos en postorden es


el siguiente:
void PostordenArbol(nodo n,tArbol T)
{
nodo c;
for(c=hizqdaAr(n,T);c!=NODO_NULO;c=herdrchaAr(c,T))
PostordenArbol(c,T);
Escribir(etiquetaAr(n,T));
}

LECTURA
A continuacin veremos un procedimiento que nos realizar la lectura de los
nodos de un rbol introducindolos en preorden.La funcin implementada se
llamaLectura aunque se listan dos funciones(la rutina Lectura2 es una funcin
auxiliar que es usada por la primera).
void Lectura2(nodo n,tArbol T)
{
tEtiqueta etHijo,etHermano;
tArbol Hijo,Hermano;
fprintf(stdout,"Introduce hijo_izqda de:
Escribir(etiquetaAr(n,T));
Leer(&etHijo);
if(comparar(etHijo,FINAL)){
Hijo=creaRaiz(etHijo);
insertar_hijo_izqda(n,Hijo,T);
Lectura2(hizqdaAr(n,T),T);
}

");

fprintf(stdout,"Introduce her_drcha de:


Escribir(etiquetaAr(n,T));
Leer(&etHermano);

");

if(comparar(etHermano,FINAL)){
Hermano=creaRaiz(etHermano);
insertar_hermano_drcha(n,Hermano,T);
Lectura2(herdrchaAr(n,T),T);
}
}
tArbol Lectura()
{
tArbol T;
tEtiqueta et;
fprintf(stdout,"En caso de que no exista el hijo_izqdo o el"
"hermano_derecho introducir el valor: ");
Escribir(FINAL);
/*FINAL actua de centinela*/
fprintf(stdout,"\nIntroduce la raiz del arbol: ");
Leer(&et);
T=creaRaiz(et);
Lectura2(raizAr(T),T);
}

Es interesante observar 5 puntos en esta rutina:

Hemos supuesto que existe una funcin Leer que tiene como parmetro de
entrada un puntero a una zona de memoria que almacena un valor de
tipo tEtiqueta,y que sirve para leer de la entrada estndar un dato de ese
tipo y almacenarlo en dicha zona de memoria.

Existe una variable FINAL que contiene un valor para la etiqueta que "no
es legal" para indicar la inexistencia de un hijo a la izquierda y/o de un
hermano a la derecha.

Suponemos que existe una funcin comparar que tiene como parmetros
de entrada dos variables de tipo tEtiqueta y que devuelve un valor entero
distinto de 0 en caso de que las variables sean distintas segn el criterio
implementado en la funcin.

Las sentencias insertar_hijo_izqda(...);Lectura2(...);no son


intercambiables,es decir,si hubieramos programado esas sentencias en otro
orden (Lectura2(...);insertar_hijo_izqda(...);) la funcin de lectura no
funcionara correctamente.La comprobacin de que esta afirmacin es
correcta se deja como ejercicio al lector.

En la segunda sentencia if ocurre una situacin similar al punto anterior.

Se puede completar la rutina de lectura para que prescinda de la lectura de


un posible hermano a la derecha de la raz simplemente preguntndonos
si n es la raz del rbol T.

You might also like