Você está na página 1de 14

ESTRUTURAS DE DADOS NO LINEARES

Anteriormente fizemos revises sobre estruturas lineares (pilha e fila)., isto , estruturas que guardam coleces de objectos que so acedidos sequencialmente. Efectivamente so chamadas lineares porque cada objecto tem um nico sucessor. Em muitas aplicaes a organizao dos objectos apresenta-se no linear, dado que qualquer membro pode apresentar mltiplos sucessores. Estudaremos rvores e grafos.

RVORES
Neste tipo de estruturas os elementos no se ligam entre si atravs de uma relao anterior-seguinte (caso das estruturas lineares), mas existe uma relao organizacional mais rica, uma relao hierrquica, so portanto estruturas hierarquizadas. Este tipo de estrutura representa por exemplo, o organigrama de uma empresa, uma rvore genealgica, ...um livro, por exemplo, tambm podemos consider-lo como estruturado em rvore, ver a figura abaixo:

L iv r o

P r e f c io

P a rte A

P a rte B

R e fe r n c ia s

C a p t u lo 1

C a p t u lo 2

C a p tu lo 3

C a p t u lo 4

C a p t u lo 5

C a p t u lo 6

1 .1

1 .2

1 .3

4 .1

4 .2

Definio e Terminologia A terminologia deste tipo de estrutura uma terminologia intuitiva que se baseia em rvores de famlia, com os termos "pai", "filho", "ascendentes", "descendentes"... rvore assim um tipo abstracto de dados que guarda os elementos (ns) hierarquicamente. Na representao grfica de rvores os ns ligam-se por ramos.... Com excepo do elemento de topo, cada elemento tem um elemento pai e zero ou mais elementos filhos. O elemento de topo designado por raiz. Assim, este elemento no tem elemento pai nem obviamente ascendentes. Por sua vez os elementos que no possuem filhos so designados por folhas. Os outros ns da rvore dizem-se interiores. Por sua vez cada elemento numa rvore a raiz da subrvore que definida pelo n e todos os descendentes do n.

Exemplo: descendentes do n 70 so 60 e 75. O movimento de um n para os seus descendentes faz-se atravs de um nico caminho. Os ascendentes de um n X so todos os ns que existem no caminho desde esse n at raiz. Exemplo: ascendentes do n 85 so 90 e 80. Define-se ainda por profundidade de um n o nmero de ramos existentes no caminho entre o n e a raiz, ou recorrendo a uma definio recursiva teremos: Profundidade do n (X) = 0 se X raiz 1 + Profundidade do n (pai(X)), nos outros casos

Exemplo: Profundidade do n 85 2. Entende-se por altura de uma rvore a mxima profundidade apresentada pelos ns. Chamamos grau de um n ao nmero de filhos que esse n tem. Chamamos grau de uma rvore ao mximo dos graus dos seus ns. Dizemos que uma rvore ordenada se existe uma ordem entre os filhos de cada n, de tal maneira que podemos identificar os filhos de um n como sendo o primeiro, o segundo, ... e essa ordem importante, no indiferente, para a definio da nossa estrutura. Tal ordem determinada pelo uso que pretendemos fazer da rvore .

RVORES BINRIAS

rvores binrias so rvores ordenadas em que cada n interno tem no mximo 2 filhos (fillho esquerdo e fillho direito) Outra definio possvel poder ser: rvores binrias so rvores que ou so nulas ou so constitudas por um n raiz e duas subrvores binrias, a subrvore esquerda e a subrvore direita (por sua vez cada uma destas subrvores ou so nulas ou constitudas por um n raiz e duas subrvores binrias, a a subrvore esquerda e a subrvore direita,)...

Propriedades Uma rvore binria com n elementos tem n-1 ramos. Uma rvore binria de altura h tem no mnimo h elementos e no mximo 2 h+1 -1 Uma rvore binria com 2 h+1 -1 elementos diz-se cheia. A altura de uma rvore binria com n elementos (n>0) no mximo n-1 e no mnimo log 2 (n+1) -1 , uma vez que: n= 2 h+1 -1 2 h+1 = n + 1 log 2 (2 h+1 ) = log 2 (n + 1) h = log 2 (n + 1) - 1 Numa rvore binria cheia o nmero de ns folha igual ao numero de ns internos + 1. Mtodos de travessia Temos vrias maneiras de percorrer ou visitar todos os ns de uma rvore binria de forma sistemtica.. - visita simtrica - visita em preordem - visita em posordem - visita por nvel

Visita simtrica A forma de percorrer os ns da rvore de forma simtrica corresponde a visitar simtricamente a subrvore esquerda seguida da visita ao n (por exemplo, escrever contedo do n ou qualquer outra operao que pretendamos sobre esse n), seguida da visita simtrica subrvore direita. Assim o algoritmo capaz de executar o que foi dito, poder ser recursivo e traduzir-se- da seguinte forma: Algoritmo recursivo: Visita-Simtrica (arvore) Se (arvore no nula) Ento Visita-Simtrica (subrvore esquerda) Visita-N Visita-Simtrica (subrvore direita) Fse Fim Algoritmo Se a Visita-N for escrever o contedo do n, ao aplicarmos este algoritmo rvore acima, obteremos a seguinte sequncia de valores : 60 70 75 80 85 90 95 Poder-se-ia usar um algoritmo iterativo, em vez do anteriormente descrito, mas nesse caso teramos que usar uma estrutura auxiliar do tipo stack, onde seriam colocados os apontadores para os ns da rvore que percorremos quando descemos pela subrvore esquerda . Depois far-se- pop da stack para visitarmos a subrvore direita. Algoritmo iterativo Visita-simtrica r=raiz Repete Enquanto ( r=/= Nulo ) // descer pelos apontadores da esquerda e colocar os ns na stack Push (r) r=r->esq Fenquanto Se (stack no vazia) // tira o ltimo n da stack, visita-o e avana para a subrvore direita Ento r=pop

Visita-N r=r->dir Fse At (stack vazia e r=Nulo) Fim Algoritmo Visita em preordem A forma de percorrer os ns da rvore em preordem, corresponde a visitar o n, seguidas das visitas em preordem da subrvore esquerda e da subrvore direita. Algoritmo recursivo: Visita-Preordem (arvore) Se arvore no nula Ento Visita-N Visita-Preordem (subrvore esquerda) Visita-Preordem (subrvore direita) Fse Fim Algoritmo Se a Visita-N for escrever o contedo do n, ao aplicarmos este algoritmo rvore acima, obteremos a seguinte sequncia de valores : 80 70 60 75 90 85 95 Do mesmo modo que no caso anterior este tipo de percorrer a rvore binria pode ser feito utilizando um algoritmo iterativo como abaixo se indica: Algoritmo iterativo Visita-Preordem r=raiz Repete Enquanto ( r=/= Nulo ) // descer pelos apontadores da esquerda e colocar os ns na stack Visita-N Push (r) r=r->esq Fenquanto Se (stack no vazia) // tira o ltimo n da stack, avana para a subrvore direita Ento r=pop r=r->dir Fse At (stack vazia e r=Nulo) Fim Algoritmo

Visita em posordem A forma de percorrer os ns da rvore em posordem, corresponde a visitar o n, no fim, isto , depois de ter feito a visita em posordem subrvore esquerda e a visita em posordem subrvore direita. Algoritmo recursivo: Visita-Posordem (arvore) Se (arvore no nula) Ento Visita-Posordem (subrvore esquerda) Visita-Posordem (subrvore direita) Visita-N Fse Fim Algoritmo Se a Visita-N for escrever o contedo do n, ao aplicarmos este algoritmo rvore acima, obteremos a seguinte sequncia de valores : 60 75 70 85 95 90 80 Tal como nas visitas anteriores podemos elaborar um algoritmo no recursivo para a visita em posordem, utilizando tambm uma stack auxiliar. No entanto, h mais um pormenor que preciso atender. S poder ser feito o pop definitivo de um elemento da stack depois de a esse elemento (n da rvore) ter sido feita a visita em posordem subrvore esquerda e subrvore direita. Ser deixado como exerccio a elaborao desse algoritmo sugerindo-se que na stack incluam alm do apontador para n mais um campo que indica se a esse n j foram ou no visitadas as duas subrvores. Visita por nveis A forma de percorrer os ns da rvore por nveis poder ser feita utilizando como estrutura auxiliar uma fila e nesse caso a sequncia de valores, da rvore usada nas visitas anteriores, ser a seguinte: 80 70 90 60 75 85 95 Algoritmo Visita-por-niveis r=raiz Se (r no Nula) Ento junta-fila (r) Fse Enquanto (fila no vazia) Retira -fila (r) Visita-No Se (r->esq no Nulo) Ento junta-fila (r->esq) Fse

Se (r->dir no Nula) Ento junta-fila (r->dir) Fse Fenquanto Fim Algoritmo NOTA 1 Toda a rvore n-ria possvel converter em rvore binria Para fazer isto basta seguir a seguinte regra: na rvore binria o n esquerda o que na rvore n-ria era o filho mais esquerda, se existirem filhos, e o n direita o que na rvore n-ria era o irmo seguinte (se existir).

Podemos considerar o seguinte algoritmo para executar a referida converso, desde que os elementos da rvore n-ria sejam dados em preordem. Para converter rvore da figura acima aplicando o algoritmo que a seguir se descreve, os contedos dos ns deveriam ser dados na seguinte sequncia : A, B, F, G, C, D, H, I, J, E e ao mesmo tempo indicado o nvel em que cada n se encontra na rvore original. Algoritmo Converso n-ria-binria -cria n raiz -push (raiz, nvel) // usar-se- uma stack auxiliar Repete Ler n corrente (contedo e nvel) Cria n para rvore binria e atribui-lhe o contedo Se nvel do n corrente > nvel do n da stack Ento Liga apontador esquerdo do n da stack (pai) ao n criado

Seno Retira da stack todos os ns com nvel > que o nvel do n criado Liga apontador direito do n da stack ao n criado Retira da stack Fse Push(n criado,nvel) At no haver mais ns. Fim Algoritmo

NOTA 2 A implementao de rvores binrias pode fazer-se usando alocao dinmica de memria, em que ser reservado espao na memria para colocar cada n. Cada n ser constitudo por um campo informao e dois campos do tipo apontador para n. Pode ainda fazer-se a implementao em memria esttica utilizando 3 vectores, um vector com a informao dos ns da rvore e outros dois, vector esquerdo e vector direito que contm respectivamente, os ndice onde se encontram no vector informao o n que est esquerda e o n que est direita. Implementao dinmica Implementao esttica

Acima encontram-se representadas graficamente as duas implementaes da mesma rvore.

NOTA 3

Neste tipo de estruturas (arvores nrias e rvores binrias), embora se utilizem em algumas casos, como indicado no ponto referente a aplicaes, no trazem qualquer benefcio na procura, insero ou eliminao de um determinado elemento, uma vez que a construo da estrutura no obedece a nenhum critrio que possa facilitar esse tipo de aces. Os algoritmos referentes a pesquisa, insero e eliminao, apresentam uma complexidade temporal de ordem N.

Aplicaes Este tipo de estrutura tem uma larga aplicao em computao. Um exemplo dessa utilizao so as rvores de deciso, usadas em situaes em que se pretende chegar a uma concluso dentro de um determinado domnio, atravs de respostas do tipo "sim" ou "no", s questes que so formuladas. A cada n interno est associada uma pergunta, e se a resposta for "sim" avanaremos para o filho esquerdo , caso seja "no" para o direito. A cada folha corresponde uma concluso.

Outra aplicao possvel a representao de expresses aritmticas em que aos ns internos associamos operadores e s folhas associamos variveis ou constantes. Cada n tem um valor associado, se for folha o valor da constante ou da varivel, se for interno o valor que resulta efectuando a operao, que o operador representa, aos valores dos seus filhos.

* + 3 6 10 45 + / 9

A rvore acima representa a seguinte expresso : ( 3 + 6 ) * ( 10 + 45 / 9 ) Implemantao da estrutura no linear do tipo ARVORE BINARIA em C++

/* Definicao da classe Nodo - representa o nodo da arvore binaria */ template <class T> class Nodo { public: T * info; Nodo<T> *esq; Nodo<T> *dir; Nodo(); Nodo(const T & e); Nodo(const T & e,Nodo<T> *esq1,Nodo<T> *dir1); }; template<class T> Nodo<T>::Nodo() { info=NULL; esq=dir=NULL; } template<class T> Nodo<T>::Nodo(const T & e) { info = new T(e); esq=dir=NULL; } template<class T> Nodo<T>::Nodo(const T & e,Nodo<T> *esq1,Nodo<T> *dir1) { info=new T(e); esq=esq1; dir=dir1; } /* Fim da classe Nodo */ /* **************************************************** */ /* Definicao da classe arvBinaria - representa a arvore binaria */ template <class T> class arvBinaria { private: Nodo<T> *raiz; void destroiArv(Nodo<T> * raiz); void preOrdem(Nodo<T> *raiz) const; void postOrdem(Nodo<T> *raiz) const; void ordemSimetrica(Nodo<T> *raiz) const; Nodo<T> *eliminar(const T & x,Nodo<T> *rz,int &enc);

Nodo<T> *pesquisar(const T & x,Nodo<T> *rz) const; public: arvBinaria(); ~arvBinaria(); bool vazia() const; void preOrdem() const { preOrdem(this->raiz); return; } void postOrdem() const { postOrdem(this->raiz); return; } void ordemSimetrica() const { ordemSimetrica(this->raiz); return; } void fazerArv(const T & elem,arvBinaria<T> & a1,arvBinaria<T> & a2); bool pesquisar(const T & x) const; arvBinaria<T> & eliminar(const T & x); }; template <class T> arvBinaria<T>::arvBinaria() { raiz = NULL; } template <class T> arvBinaria<T>::~arvBinaria() { destroiArv(raiz); } template <class T> void arvBinaria<T>::destroiArv(Nodo<T> * raiz) { if (raiz !=NULL) { destroiArv(raiz->esq); destroiArv(raiz->dir); delete raiz; } } template <class T> bool arvBinaria<T>::vazia() const { return (raiz==NULL); } template <class T> void arvBinaria<T>::preOrdem(Nodo<T> *raiz) const {

if (raiz!=NULL) { cout<< *(raiz->info) << endl; preOrdem(raiz->esq); preOrdem(raiz->dir); } return; } template <class T> void arvBinaria<T>::postOrdem(Nodo<T> *raiz) const { if (raiz!=NULL) { postOrdem(raiz->esq); postOrdem(raiz->dir); cout<< *(raiz->info) << endl; } return; } template <class T> void arvBinaria<T>::ordemSimetrica(Nodo<T> *raiz) const { if (raiz!=NULL) { ordemSimetrica(raiz->esq); cout<< *(raiz->info) << endl; ordemSimetrica(raiz->dir); } return; } template<class T> void arvBinaria<T>::fazerArv(const T & elem,arvBinaria<T> & a1,arvBinaria<T> & a2) { raiz = new Nodo<T>(elem,a1.raiz,a2.raiz); a1.raiz=a2.raiz=NULL; } template<class T> bool arvBinaria<T>:: pesquisar(const T & x) const { Nodo<T> *temp; temp=pesquisar(x,this->raiz); // este um mtodo privado if(temp!=NULL) { cout <<*(temp->info); return true;

} else return false; } template<class T> Nodo<T> * arvBinaria<T>::pesquisar(const T & x,Nodo<T> *rz) const { Nodo<T> * n; if(rz) { if(*(rz->info)==x) // a classe com que vai instanciar T ter que ter definido o
//operador ==

return rz; n=pesquisar(x, rz->esq); if(n==NULL) return pesquisar(x, rz->dir); return n; } else return NULL; } template<class T> arvBinaria<T>& arvBinaria<T>::eliminar(const T & x) { int enc=0; raiz=eliminar(x,raiz,enc); return *this; } template<class T> Nodo<T>* arvBinaria<T>::eliminar(const T & x,Nodo<T> *rz,int &enc) { if(rz==NULL) return rz; if(*(rz->info)==x) { destroiArv(rz); enc=1; return NULL; } rz->esq=eliminar(x,rz->esq,enc); if (enc==0) rz->dir=eliminar(x,rz->dir,enc); return rz; }