Você está na página 1de 14

13.

rvores
W. Celes e J. L. Rangel

Nos captulos anteriores examinamos as estruturas de dados que podem ser chamadas de unidimensionais ou lineares, como vetores e listas. A importncia dessas estruturas inegvel, mas elas no so adequadas para representarmos dados que devem ser dispostos de maneira hierrquica. Por exemplo, os arquivos (documentos) que criamos num computador so armazenados dentro de uma estrutura hierrquica de diretrios (pastas). Existe um diretrio base dentro do qual podemos armazenar diversos subdiretrios e arquivos. Por sua vez, dentro dos sub-diretrios, podemos armazenar outros sub-diretrios e arquivos, e assim por diante, recursivamente. A Figura 13.1 mostra uma imagem de uma rvore de diretrio no Windows 2000.

Figura 13.1: Um exemplo de rvore de diretrio.

Neste captulo, vamos introduzir rvores, que so estruturas de dados adequadas para a representao de hierarquias. A forma mais natural para definirmos uma estrutura de rvore usando recursividade. Uma rvore composta por um conjunto de ns. Existe um n r , denominado raiz, que contm zero ou mais sub-rvores, cujas razes so ligadas diretamente a r. Esses ns razes das sub-rvores so ditos filhos do n pai, r. Ns com filhos so comumente chamados de ns internos e ns que no tm filhos so chamados de folhas, ou ns externos. tradicional desenhar as rvores com a raiz para cima e folhas para baixo, ao contrrio do que seria de se esperar. A Figura 13.2 exemplifica a estrutura de uma rvore.
n raiz

...
Figura 13.2: Estrutura de rvore.

sub-rvores

Observamos que, por adotarmos essa forma de representao grfica, no representamos explicitamente a direo dos ponteiros, subentendendo que eles apontam sempre do pai para os filhos.
Estruturas de Dados PUC-Rio 12-1

O nmero de filhos permitido por n e as informaes armazenadas em cada n diferenciam os diversos tipos de rvores existentes. Neste captulo, estudaremos dois tipos de rvores. Primeiro, examinaremos as rvores binrias, onde cada n tem, no mximo, dois filhos. Depois examinaremos as chamadas rvores genricas, onde o nmero de filhos indefinido. Estruturas recursivas sero usadas como base para o estudo e a implementao das operaes com rvores.

13.1. rvores binrias


Um exemplo de utilizao de rvores binrias est na avaliao de expresses. Como trabalhamos com operadores que esperam um ou dois operandos, os ns da rvore para representar uma expresso tm no mximo dois filhos. Nessa rvore, os ns folhas representam operandos e os ns internos operadores. Uma rvore que representa, por exemplo a expresso (3+6)*(4-1)+5 ilustrada na Figura 13.3. +

* + 3 6 4 1

Figura 13.3: rvore da expresso: (3+6) * (4-1) + 5.

Numa rvore binria, cada n tem zero, um ou dois filhos. De maneira recursiva, podemos definir uma rvore binria como sendo: uma rvore vazia; ou um n raiz tendo duas sub-rvores, identificadas como a sub-rvore da direita (sad) e a sub-rvore da esquerda (sae). A Figura 13.4 ilustra a definio de rvore binria. Essa definio recursiva ser usada na construo de algoritmos, e na verificao (informal) da correo e do desempenho dos mesmos.

Estruturas de Dados PUC-Rio

12-2

raiz
vazia

sae

sad

Figura 13.4: Representao esquemtica da definio da estrutura de rvore binria.

A Figura 13.5 a seguir ilustra uma estrutura de rvore binria. Os ns a, b, c, d, e, f formam uma rvore binria da seguinte maneira: a rvore composta do n a, da subrvore esquerda formada por b e d, e da sub-rvore direita formada por c, e e f. O n a representa a raiz da rvore e os ns b e c as razes das sub-rvores. Finalmente, os ns d, e e f so folhas da rvore.

a b d e c f

Figura 13.5: Exemplo de rvore binria

Para descrever rvores binrias, podemos usar a seguinte notao textual: a rvore vazia representada por <>, e rvores no vazias por <raiz sae sad>. Com essa notao, a rvore da Figura 13.5 representada por:
<a<b<><d<><>>><c<e<><>><f<><>>>>.

Pela definio, uma sub-rvore de uma rvore binria sempre especificada como sendo a sae ou a sad de uma rvore maior, e qualquer das duas sub-rvores pode ser vazia. Assim, as duas rvores da Figura 13.6 so distintas.

a b

a b

Figura 13.6: Duas rvores binrias distintas.

Isto tambm pode ser visto pelas representaes textuais das duas rvores, que so, respectivamente: <a <b<><>> <> > e <a <> <b<><>> >.
Estruturas de Dados PUC-Rio 12-3

Uma propriedade fundamental de todas as rvores que s existe um caminho da raiz para qualquer n. Com isto, podemos definir a altura de uma rvore como sendo o comprimento do caminho mais longo da raiz at uma das folhas. Por exemplo, a altura da rvore da Figura 13.5 2, e a altura das rvores da Figura 13.6 1. Assim, a altura de uma rvore com um nico n raiz zero e, por conseguinte, dizemos que a altura de uma rvore vazia negativa e vale -1. Exerccio: Mostrar que uma rvore binria de altura h tem, no mnimo, h+1 ns, e, no mximo, 2h+1 1. Representao em C Anlogo ao que fizemos para as demais estruturas de dados, podemos definir um tipo para representar uma rvore binria. Para simplificar a discusso, vamos considerar que a informao que queremos armazenar nos ns da rvore so valores de caracteres simples. Vamos inicialmente discutir como podemos representar uma estrutura de rvore binria em C. Que estrutura podemos usar para representar um n da rvore? Cada n deve armazenar trs informaes: a informao propriamente dita, no caso um caractere, e dois ponteiros para as sub-rvores, esquerda e direita. Ento a estrutura de C para representar o n da rvore pode ser dada por:
struct arv { char info; struct arv* esq; struct arv* dir; };

Da mesma forma que uma lista encadeada representada por um ponteiro para o primeiro n, a estrutura da rvore como um todo representada por um ponteiro para o n raiz. Como acontece com qualquer TAD (tipo abstrato de dados), as operaes que fazem sentido para uma rvore binria dependem essencialmente da forma de utilizao que se pretende fazer da rvore. Nesta seo, em vez de discutirmos a interface do tipo abstrato para depois mostrarmos sua implementao, vamos optar por discutir algumas operaes mostrando simultaneamente suas implementaes. Ao final da seo apresentaremos um arquivo que pode representar a interface do tipo. Nas funes que se seguem, consideraremos que existe o tipo Arv definido por:
typedef struct arv Arv;

Como veremos as funes que manipulam rvores so, em geral, implementadas de forma recursiva, usando a definio recursiva da estrutura. Vamos procurar identificar e descrever apenas operaes cuja utilidade seja a mais geral possvel. Uma operao que provavelmente dever ser includa em todos os casos a inicializao de uma rvore vazia. Como uma rvore representada pelo endereo do n raiz, uma rvore vazia tem que ser representada pelo valor NULL. Assim, a funo que inicializa uma rvore vazia pode ser simplesmente:

Estruturas de Dados PUC-Rio

12-4

Arv* inicializa(void) { return NULL; }

Para criar rvores no vazias, podemos ter uma operao que cria um n raiz dadas a informao e suas duas sub-rvores, esquerda e direita. Essa funo tem como valor de retorno o endereo do n raiz criado e pode ser dada por:
Arv* cria(char c, Arv* sae, Arv* sad){ Arv* p=(Arv*)malloc(sizeof(Arv)); p->info = c; p->esq = sae; p->dir = sad; return p; }

As duas funes inicializa e cria representam os dois casos da definio recursiva de rvore binria: uma rvore binria (Arv* a;) vazia (a = inicializa();) ou composta por uma raiz e duas sub-rvores (a = cria(c,sae,sad);). Assim, com posse dessas duas funes, podemos criar rvores mais complexas. Exemplo: Usando as operaes inicializa e cria, crie uma estrutura que represente a rvore da Figura 13.5. O exemplo da figura pode ser criada pela seguinte seqncia de atribuies.
Arv* */ Arv* */ Arv* */ Arv* */ Arv* */ Arv* */ a1= cria('d',inicializa(),inicializa()); a2= cria('b',inicializa(),a1); a3= cria('e',inicializa(),inicializa()); a4= cria('f',inicializa(),inicializa()); a5= cria('c',a3,a4); a = cria('a',a2,a5 ); /* sub-rvore com 'd' /* sub-rvore com 'b' /* sub-rvore com 'e' /* sub-rvore com 'f' /* sub-rvore com 'c' /* rvore com raiz 'a'

Alternativamente, a rvore poderia ser criada com uma nica atribuio, seguindo a sua estrutura, recursivamente:
Arv* a = cria('a', cria('b', inicializa(), cria('d', inicializa(), inicializa()) ), cria('c', cria('e', inicializa(), inicializa()), cria('f', inicializa(), inicializa()) ) );

Para tratar a rvore vazia de forma diferente das outras, importante ter uma operao que diz se uma rvore ou no vazia. Podemos ter:

Estruturas de Dados PUC-Rio

12-5

int vazia(Arv* a) { return a==NULL; }

Uma outra funo muito til consiste em exibir o contedo da rvore. Essa funo deve percorrer recursivamente a rvore, visitando todos os ns e imprimindo sua informao. A implementao dessa funo usa a definio recursiva da rvore. Vimos que uma rvore binria ou vazia ou composta pela raiz e por duas sub-rvores. Portanto, para imprimir a informao de todos os ns da rvore, devemos primeiro testar se a rvore vazia. Se no for, imprimimos a informao associada a raiz e chamamos (recursivamente) a funo para imprimir os ns das sub-rvores.
void imprime (Arv* a) { if (!vazia(a)){ printf("%c ", a->info); imprime(a->esq); imprime(a->dir); } }

/* mostra raiz */ /* mostra sae */ /* mostra sad */

Exerccio: (a) simule a chamada da funo imprime aplicada arvore ilustrada pela Figura 13.5 para verificar que o resultado da chamada a impresso de a b d c e f. (b) Repita a experincia executando um programa que crie e mostre a rvore, usando o seu compilador de C favorito. Exerccio: Modifique a implementao de imprime, de forma que a sada impressa reflita, alm do contedo de cada n, a estrutura da rvore, usando a notao introduzida anteriormente. Assim, a sada da funo seria: <a<b<><d<><>>><c<e<><>><f<><>>>>. Uma outra operao que pode ser acrescentada a operao para liberar a memria alocada pela estrutura da rvore. Novamente, usaremos uma implementao recursiva. Um cuidado essencial a ser tomado que as sub-rvores devem ser liberadas antes de se liberar o n raiz, para que o acesso s sub-rvores no seja perdido antes de sua remoo. Neste caso, vamos optar por fazer com que a funo tenha como valor de retorno a rvore atualizada, isto , uma rvore vazia, representada por NULL.
Arv* libera (Arv* a){ if (!vazia(a)){ libera(a->esq); libera(a->dir); free(a); } return NULL; }

/* libera sae */ /* libera sad */ /* libera raiz */

Devemos notar que a definio de rvore, por ser recursiva, no faz distino entre rvores e sub-rvores. Assim, cria pode ser usada para acrescentar (enxertar) uma sub-rvore em um ramo de uma rvore, e libera pode ser usada para remover (podar) uma sub-rvore qualquer de uma rvore dada. Exemplo: Considerando a criao da rvore feita anteriormente:
Estruturas de Dados PUC-Rio 12-6

Arv* a = cria('a', cria('b', inicializa(), cria('d', inicializa(), inicializa()) ), cria('c', cria('e', inicializa(), inicializa()), cria('f', inicializa(), inicializa()) ) );

Podemos acrescentar alguns ns, com:


a->esq->esq = cria('x', cria('y',inicializa(),inicializa()), cria('z',inicializa(),inicializa()) );

E podemos liberar alguns outros, com:


a->dir->esq = libera(a->dir->esq);

Deixamos como exerccio a verificao do resultado final dessas operaes. importante observar que, anlogo ao que fizemos para a lista, o cdigo cliente que chama a funo libera responsvel por atribuir o valor atualizado retornado pela funo, no caso uma rvore vazia. No exemplo acima, se no tivssemos feito a atribuio, o endereo armazenado em r->dir->esq seria o de uma rea de memria no mais em uso. Exerccio: Escreva uma funo que percorre uma rvore binria para determinar sua altura. O prottipo da funo pode ser dado por:
int altura(Arv* a);

Uma outra funo que podemos considerar percorre a rvore buscando a ocorrncia de um determinado caractere c em um de seus ns. Essa funo tem como retorno um valor booleano (um ou zero) indicando a ocorrncia ou no do caractere na rvore.
int busca (Arv* a, char c){ if (vazia(a)) return 0; /* rvore vazia: no encontrou */ else return a->info==c || busca(a->esq,c) || busca(a->dir,c); }

Note que esta forma de programar busca, em C, usando o operador lgico || (ou) faz com que a busca seja interrompida assim que o elemento encontrado. Isto acontece porque se c==a->info for verdadeiro, as duas outras expresses no chegam a ser avaliadas. Analogamente, se o caractere for encontrado na sub-rvore da esquerda, a busca no prossegue na sub-rvore da direita. Podemos dizer que a expresso:
return c==a->info || busca(a->esq,c) || busca(a->dir,c);

equivalente a:

Estruturas de Dados PUC-Rio

12-7

if (c==a->info) return 1; else if (busca(a->esq,c)) return 1; else return busca(a->dir,c);

Finalmente, considerando que as funes discutidas e implementadas acima formam a interface do tipo abstrato para representar uma rvore binria, um arquivo de interface arvbin.h pode ser dado por:
typedef struct arv Arv; Arv* Arv* int void Arv* int inicializa (void); cria (char c, Arv* e, Arv* d); vazia (Arv* a); imprime (Arv* a); libera (Arv* a); busca (Arv* a, char c);

Ordens de percurso em rvores binrias A programao da operao imprime, vista anteriormente, seguiu a ordem empregada na definio de rvore binria para decidir a ordem em que as trs aes seriam executadas: Entretanto, dependendo da aplicao em vista, esta ordem poderia no ser a prefervel, podendo ser utilizada uma ordem diferente desta, por exemplo:
imprime(a->esq); imprime(a->dir); printf("%c ", a->info); /* mostra sae */ /* mostra sad */ /* mostra raiz */

Muitas operaes em rvores binrias envolvem o percurso de todas as sub-rvores, executando alguma ao de tratamento em cada n, de forma que comum percorrer uma rvore em uma das seguintes ordens: pr-ordem: trata raiz, percorre sae, percorre sad; ordem simtrica: percorre sae, trata raiz, percorre sad; ps-ordem: percorre sae, percorre sad, trata raiz. Para funo para liberar a rvore, por exemplo, tivemos que adotar a ps-ordem:
libera(a->esq); libera(a->dir); free(a); /* libera sae */ /* libera sad */ /* libera raiz */

Na terceira parte do curso, quando tratarmos de rvores binrias de busca, apresentaremos um exemplo de aplicao de rvores binrias em que a ordem de percurso importante a ordem simtrica. Algumas outras ordens de percurso podem ser definidas, mas a maioria das aplicaes envolve uma dessas trs ordens, percorrendo a sae antes da sad. Exerccio: Implemente verses diferentes da funo imprime, percorrendo a rvore em ordem simtrica e em ps-ordem. Verifique o resultado da aplicao das duas funes na rvore da Figura 13.5.
Estruturas de Dados PUC-Rio 12-8

13.2. rvores genricas


Nesta seo, vamos discutir as estruturas conhecidas como rvores genricas. Como vimos, numa rvore binria o nmero de filhos dos ns limitado em no mximo dois. No caso da rvore genrica, esta restrio no existe. Cada n pode ter um nmero arbitrrio de filhos. Essa estrutura deve ser usada, por exemplo, para representar uma rvore de diretrios. Como veremos, as funes para manipularem uma rvore genrica tambm sero implementadas de forma recursiva, e sero baseadas na seguinte definio: uma rvore genrica composta por: um n raiz; e zero ou mais sub-rvores. Estritamente, segundo essa definio, uma rvore no pode ser vazia, e a rvore vazia no sequer mencionada na definio. Assim, uma folha de uma rvore no um n com sub-rvores vazias, como no caso da rvore binria, mas um n com zero subrvores. Em qualquer definio recursiva deve haver uma condio de contorno, que permita a definio de estruturas finitas, e, no nosso caso, a definio de uma rvore se encerra nas folhas, que so identificadas como sendo ns com zero sub-rvores. Como as funes que implementaremos nesta seo sero baseadas nessa definio, no ser considerado o caso de rvores vazias. Esta pequena restrio simplifica as implementaes recursivas e, em geral, no limita a utilizao da estrutura em aplicaes reais. Uma rvore de diretrio, por exemplo, nunca vazia, pois sempre existe o diretrio base o diretrio raiz. Como as sub-rvores de um determinado n formam um conjunto linear e so dispostas numa determinada ordem, faz sentido falarmos em primeira sub-rvore (sa1), segunda sub-rvore (sa2), etc. Um exemplo de uma rvore genrica ilustrado na Figura 13.7.

Figura 13.7: Exemplo de rvore genrica.

Nesse exemplo, podemos notar que o a rvore com raiz no n a tem 3 sub-rvores, ou, equivalentemente, o n a tem 3 filhos. Os ns b e g tem dois filhos cada um; os ns c e i tem um filho cada, e os ns d, e, h e j so folhas, e tem zero filhos.

Estruturas de Dados PUC-Rio

12-9

De forma semelhante ao que foi feito no caso das rvores binrias, podemos representar essas rvores atravs de notao textual, seguindo o padro: <raiz sa1 sa2 ... san>. Com esta notao, a rvore da Figura 13.7 seria representada por:
a = <a <b <c <d>> <e>> <f> <g <h> <i <j>>>>

Podemos verificar que a representa a rvore do exemplo seguindo a seqncia de definio a partir das folhas:
a1 = <d> a2 = <c a1> = <c a3 = <e> a4 = <b a2 a3> = a5 = <f> a6 = <h> a7 = <j> a8 = <i a7> = <i a9 = <g a6 a8> = a = <a a4 a5 a9> <d>> <b <c <d>> <e>>

<j>> <g <h> <i <j>>> = <a <b <c <d>> <e>> <f> <g <h> <i <j>>>>

Representao em C Dependendo da aplicao, podemos usar vrias estruturas para representar rvores, levando em considerao o nmero de filhos que cada n pode apresentar. Se soubermos, por exemplo, que numa aplicao o nmero mximo de filhos que um n pode apresentar 3, podemos montar uma estrutura com 3 campos para apontadores para os ns filhos, digamos, f1 , f2 e f3 . Os campos no utilizados podem ser preenchidos com o valor nulo NULL, sendo sempre utilizados os campos em ordem. Assim, se o n n tem 2 filhos, os campos f1 e f2 seriam utilizados, nessa ordem, para apontar para eles, ficando f3 vazio. Prevendo um nmero mximo de filhos igual a 3, e considerando a implementao de rvores para armazenar valores de caracteres simples, a declarao do tipo que representa o n da rvore poderia ser:
struct arv3 { char val; struct no *f1, *f2, *f3; };

A Figura 13.8 indica a representao da rvore da Figura 13.7 com esta organizao. Como se pode ver no exemplo, em cada um dos ns que tem menos de trs filhos, o espao correspondente aos filhos inexistentes desperdiado. Alm disso, se no existe um limite superior no nmero de filhos, esta tcnica pode no ser aplicvel. O mesmo acontece se existe um limite no nmero de ns, mas esse limite ser raramente alcanado, pois estaramos tendo um grande desperdcio de espao de memria com os campos no utilizados.

Estruturas de Dados PUC-Rio

12-10

Figura 13.8: rvore com no mximo trs filhos por n.

Uma soluo que leva a um aproveitamento melhor do espao utiliza uma lista de filhos: um n aponta apenas para seu primeiro (prim) filho, e cada um de seus filhos, exceto o ltimo, aponta para o prximo (prox) irmo. A declarao de um n pode ser:
struct arvgen { char info; struct arvgen *prim; struct arvgen *prox; };

A Figura 13.9 mostra o mesmo exemplo representado de acordo com esta estrutura. Uma das vantagens dessa representao que podemos percorrer os filhos de um n de forma sistemtica, de maneira anloga ao que fizemos para percorrer os ns de uma lista simples.

Estruturas de Dados PUC-Rio

12-11

Figura 13.9: Exemplo usando lista de filhos.

Com o uso dessa representao, a generalizao da rvore apenas conceitual, pois, concretamente, a rvore foi transformada em uma rvore binria, com filhos esquerdos apontados por prim e direitos apontados por prox . Naturalmente, continuaremos a fazer referncia aos ns nos termos da definio original. Por exemplo, os ns b, f e g continuaro a ser considerados filhos do n a, como indicado na Figura 13.7, mesmo que a representao usada na Figura 13.9 os coloque a distncias variveis do n pai. Tipo abstrato de dado Para exemplificar a implementao de funes que manipulam uma rvore genrica, vamos considerar a criao de um tipo abstrato de dados para representar rvores onde a informao associada a cada n um caractere simples. Nessa implementao, vamos optar por armazenar os filhos de um n numa lista encadeada. Podemos definir o seguinte conjunto de operaes: cria: cria um n folha, dada a informao a ser armazenada; insere: insere uma nova sub-rvore como filha de um dado n; imprime: percorre todos os ns e imprime suas informaes; busca: verifica a ocorrncia de um determinado valor num dos ns da rvore; libera: libera toda a memria alocada pela rvore. A interface do tipo pode ento ser definida no arquivo arvgen.h dado por:
typedef struct arvgen ArvGen; ArvGen* void void int void cria (char c); insere (ArvGen* a, ArvGen* sa); imprime (ArvGen* a); busca (ArvGen* a, char c); libera (ArvGen* a);

Estruturas de Dados PUC-Rio

12-12

A estrutura arvgen , que representa o n da rvore, definida conforme mostrado anteriormente. A funo para criar uma folha deve alocar o n e inicializar seus campos, atribuindo NULL para os campos prim e prox, pois trata-se de um n folha.
ArvGen* cria { ArvGen *a a->info = a->prim = a->prox = return a; } (char c) =(ArvGen *) malloc(sizeof(ArvGen)); c; NULL; NULL;

A funo que insere uma nova sub-rvore como filha de um dado n muito simples. Como no vamos atribuir nenhum significado especial para a posio de um n filho, a operao de insero pode inserir a sub-rvore em qualquer posio. Neste caso, vamos optar por inserir sempre no incio da lista que, como j vimos, a maneira mais simples de inserir um novo elemento numa lista encadeada.
void insere (ArvGen* a, ArvGen* sa) { sa->prox = a->prim; a->prim = sa; }

Com essas duas funes, podemos construir a rvore do exemplo da Figura 13.7 com o seguinte fragmento de cdigo:
/* cria ns como folhas */ ArvGen* a = cria('a'); ArvGen* b = cria('b'); ArvGen* c = cria('c'); ArvGen* d = cria('d'); ArvGen* e = cria('e'); ArvGen* f = cria('f'); ArvGen* g = cria('g'); ArvGen* h = cria('h'); ArvGen* i = cria('i'); ArvGen* j = cria('j'); /* monta a hierarquia */ insere(c,d); insere(b,e); insere(b,c); insere(i,j); insere(g,i); insere(g,h); insere(a,g); insere(a,f); insere(a,b);

Para imprimir as informaes associadas aos ns da rvore, temos duas opes para percorrer a rvore: pr-ordem, primeiro a raiz e depois as sub-rvores, ou ps-ordem, primeiro as sub-rvores e depois a raiz. Note que neste caso no faz sentido a ordem simtrica, uma vez que o nmero de sub-rvores varivel. Para essa funo, vamos optar por imprimir o contedo dos ns em pr-ordem:
void imprime (ArvGen* a) { ArvGen* p; printf("%c\n",a->info); for (p=a->prim; p!=NULL; p=p->prox) imprime(p); }
Estruturas de Dados PUC-Rio 12-13

A operao para buscar a ocorrncia de uma dada informao na rvore exemplificada abaixo:
int busca (ArvGen* a, char c) { ArvGen* p; if (a->info==c) return 1; else { for (p=a->prim; p!=NULL; p=p->prox) { if (busca(p,c)) return 1; } } return 0; }

A ltima operao apresentada a que libera a memria alocada pela rvore. O nico cuidado que precisamos tomar na programao dessa funo a de liberar as subrvores antes de liberar o espao associado a um n (isto , usar ps-ordem).
void libera (ArvGen* a) { ArvGen* p = a->prim; while (p!=NULL) { ArvGen* t = p->prox; libera(p); p = t; } free(a); }

Exerccio: Escreva uma funo com o prottipo


ArvGen* copia(ArvGen*a);

para criar dinamicamente uma cpia da rvore. Exerccio: Escreva uma funo com o prottipo
int igual(ArvGen*a, ArvGen*b);

para testar se duas rvores so iguais.

Estruturas de Dados PUC-Rio

12-14

Você também pode gostar