Você está na página 1de 92

AULA 1 - ALGORITMOS E DADOS

Autor: Fbio Rezende Lucas

Ol! Vamos dar incio a nossa primeira aula da disciplina Estrutura de Dados I. Nesta aula estudaremos sobre dados e os tipos abstratos de dado para que voc saiba como definir cada um deles, diferenciar os seus subtipos, alm de poder criar seus prprios tipos de dados. Espero que, desta forma, voc aprenda a criar estruturas denominadas TAD (Tipo Abstrato de Dados), que so comumente adotadas na criao de programas complexos. Vamos comear!

ALGORITMOS E ESTRUTURA DE DADOS


Voc sabia que os algoritmos fazem parte do cotidiano das pessoas? So exemplos de algoritmos, as instrues para o uso de medicamentos, indicaes de como montar um aparelho, uma receita de bolo, uma simples ao de trocar uma lmpada etc. Com isso, pode-se dizer que algoritmo uma sequncia de aes que so executadas para a obteno de uma soluo de um determinado tipo de problema. De acordo com a figura 1, voc pode observar que a computao estuda e manipula dados, em contraste com o computador que o manipulador dos dados.

Figura 1 - Computao e Computador: como os algoritmos utilizam os dados (SAIBEL, 2006)

Neste contexto, os algoritmos fazem parte da computao, utilizando os computadores para manipular os dados. A implementao de uma aplicao uma abstrao do mundo real, que utiliza um conjunto selecionado de dados relacionados com o problema a ser resolvido. A partir da um conjunto de operaes sobre esses dados produzir os resultados esperados. Logo, para a resoluo de um problema do mundo real com algoritmos, voc deve seguir os passos, conforme a figura 2.

Figura 2 - Passos para resoluo de problemas atravs da computao (SAIBEL, 2006)

Assim, pode-se dizer que, para resolver um problema do mundo real atravs da computao, so necessrios dois elementos: o algoritmo e a estrutura de dados. O primeiro faz a representao do comportamento. J o segundo representa a informao. Logo, podemos definir algoritmos e estrutura de dados da seguinte maneira:
Algoritmos: um conjunto finito de instrues que seguidas, realizam uma determinada tarefa, determinam uma sada (resultado) a partir de uma (ou nenhuma) entrada. O seu processo de execuo manipula dados para a obteno de um resultado. Estrutura de dados: determina como a informao organizada, como ser manipulada e como ser utilizada.

Esses dois elementos definidos acima esto intimamente ligados. Segundo Ziviani (2005), no se pode estudar estruturas de dados sem considerar os algoritmos associados a elas, assim como a escolha dos algoritmos em geral depende da representao e da estrutura dos dados.

TIPOS DE DADOS
Agora que voc estudou sobre algoritmos e estrutura de dados, vamos aprender sobre os tipos de dados antes de entrarmos no tema principal da nossa aula que Tipos Abstratos de Dados. Conforme Ziviani (2005), tipos de dados caracterizam o conjunto de valores a que uma constante pertence, ou que podem ser assumidos por uma varivel ou expresso, ou que podem ser gerados por uma funo. Tipos simples de dados so grupos de valores indivisveis (como os tipos bsicos integer, boolean, char e real do Pascal). Os tipos estruturados em geral definem uma coleo de valores simples, ou um agregado de valores de tipos diferentes.

Com isso, podemos dizer que um tipo de dado refere-se a um conjunto de valores (um determinado domnio) e a um determinado conjunto de operaes sobre esses valores. Conforme o pargrafo anterior, cada varivel, expresso ou funo pertence a um tipo de dado. Para a linguagem Pascal temos exemplos dos seguintes tipos com suas operaes:
Integer Valores assumidos: ..., -2, -1, 0, 1, 2, 3... Operaes: +, -, *, mod, div... Boolean Valores assumidos: true, false. Operaes: and, or. Real Valores assumidos: ..., -2.3, -1.54, 0.0, 3.83, 4.0... Operaes: +, -, *, mod, div... String Valores assumidos: "estrutura", "dados", "A"... Operaes: + Char Valores assumidos: "e", "d", "A"... Operaes: ord(), +...

Um tipo de dados est associado a uma representao e a quantidade de memria para armazenar sua representao. Esta ltima refere-se rea de memria onde ficar o valor da varivel, a qual tem que ter dimenses compatveis com a sua representao, alm de permitir apenas um conjunto de valores possveis para as variveis de um dado tipo. Em programas, no possvel deduzir o tipo da varivel a partir do seu contexto. Na criao do programa deve-se conhecer o tipo de dados para saber qual a sua representao, sendo necessrio, nesse momento, explicitar o tipo de cada varivel, a qual tem uma representao associada na mquina. Alm do que os tipos de dados representam, eles podem ser divididos em: primitivos ou elementares e compostos ou estruturados. Tipos primitivos: no existe uma estrutura sobre seus valores.
boolean, integer e char em Pascal.

Tipos estruturados: existe uma relao estrutural intrnseca entre seus valores.
um array, no qual seus elementos seguem uma estruturao linear.

Sendo assim, os tipos de dados primitivos podem ser definidos de trs maneiras, como seguem abaixo:

Dentro da linguagem (fundamentais): INTEGER, REAL, BOOLEAN, CHAR... Por enumerao de valores: TYPE sexo = (masculino, feminino) TYPE cor = (vermelho, laranja, amarelo, verde, azul, anil, violeta) Atravs de Subintervalos: TYPE ano = [2010..3000] TYPE digito = ["0", "9"] J os tipos de dados estruturados, na linguagem Pascal, so divididos entre:
Vetores (arrays) uni e n-dimensionais Registros Conjuntos Arquivos

Vamos ver agora um pouco de cada um desses tipos de dados estruturados.

Tipo Estruturado Vetor


O vetor um conjunto finito e ordenado de elementos homogneos. Ele finito porque tem um tamanho conhecido; ordenado por causa de seus elementos estarem organizados de forma que exista uma linearidade na sua organizao, como elemento 1, elemento 2, e assim por diante; e homogneo devido a seus componentes serem do mesmo tipo. Uma caracterstica a se destacar que os vetores podem ter vrias dimenses, como uma matriz de dimenso 2. Em Pascal, um tipo estruturado de dados vetor definido da seguinte maneira: TYPE tipo = ARRAY [Tindice] OF Tbase; Em que, tipo: nome dado ao array Tindice: ndice, indicando o tamanho do array Tbase: o tipo dos elementos do array

Dessa maneira, seguem alguns exemplos: TYPE vetor = ARRAY [1..100] OF CHAR; TYPE matriz = ARRAY [1..10], [1..50] OF INTEGER; Porm, a especificao da forma da estrutura de dados no descreve totalmente sua estrutura, pois falta definir a forma de acesso s informaes. Dessa maneira, para um vetor sua implementao diz que ele tem n posies sucessivas na memria a partir de um endereo de base e qualquer elemento acessvel a partir de seu ndice. Veja como a figura 3 ilustra essa definio.

Figura 3 - Forma ilustrada da implementao da forma de acesso s informaes em um array Fonte: (SAIBEL, 2006)

Tipo Estruturado Registro


Tipo Estruturado Registro consiste num agrupamento de tipos arbitrrios de dados, que podem ou no ser estruturados. Dessa maneira, o registro agrupa diversos campos ou membros, que funcionam como uma varivel do tipo criado. Cada membro dele pode ser do tipo estruturado ou primitivo. Em Pascal, um tipo estruturado de dados registro definido da seguinte maneira: TYPE TipoReg = RECORD s1 : Tipo1; s2 : Tipo2; ... sn : Tipon; END Em que, TipoReg: nome dado ao registro sn: nome dado ao campo Tipon: o tipo do campo Dessa maneira, segue um exemplo de criao de registro:

TYPE TPessoa = RECORD nome : String; ano : integer; cpf : String; END Mais uma vez, deve-se ainda definir a forma de como manipular a estrutura. Para registros, a manipulao d-se da seguinte forma: x : TipoReg (criao de varivel) x. s1 = valor (manipulao de um membro) De acordo com o exemplo exibido do registro Pessoa, a manipulao seria da seguinte maneira: pessoa : TPessoa (criao de varivel) pessoa.nome = 'Joo' (manipulao do membro nome) pessoa.ano = 1980 (manipulao do membro ano) pessoa.cpf = '123.456.789-00' (manipulao do membro cpf)

Tipo Estruturado Conjunto


Este tipo estruturado representa, em Pascal, um conjunto de objetos de um determinado tipo, tendo como base um tipo simples enumervel. Sua declarao segue o seguinte esquema: TYPE TipoConj = SET OF TipoBase onde, TipoConj: nome dado ao conjunto TipoBase: o tipo dos elementos do conjunto Dessa maneira, segue um exemplo de criao de conjunto: TYPE ConjDigitos = SET OF 0..9; Para sua manipulao, podemos criar variveis da seguinte maneira. digito: ConjDigitos;

TIPO ESTRUTURADO ARQUIVO


O tipo estruturado arquivo representa uma sequncia de valores homogneos de qualquer tipo. Geralmente associado com alguma unidade externa (ZIVIANI, 2005). Sua declarao segue o seguinte esquema: TYPE TipoArquivo = FILE OF TipoBase em que, TipoArquivo: nome dado ao arquivo TipoBase: o tipo dos elementos do arquivo Dessa maneira, segue um exemplo de criao de conjunto: TYPE arquivoPessoa = FILE OF TPessoa; Verifique que o exemplo acima utiliza como tipo base, um tipo estruturado previamente criado no exemplo de registros. Para exemplificar a sua manipulao, incluindo a utilizao de outros tipos vistos aqui na aula, analise o programa a seguir, retirado de Ziviani (2005). Esse programa copia o contedo do arquivo Velho passado como o primeiro parmetro para o arquivo Novo, passado no segundo parmetro.

Figura 4 - Exemplo de programa utilizando estruturas de dados Fonte: (ZIVIANI, 2005)

TIPOS ABSTRATOS DE DADOS


Segundo Ziviani (2005), um tipo abstrato de dados pode ser visto como um modelo matemtico, acompanhado das operaes definidas sobre o modelo. A abstrao de informaes atravs do TAD (Tipo Abstrato de Dados) permitiu uma melhor compreenso dos algoritmos e maior facilidade de programao. Atualmente, esta abstrao incorporada nas linguagens de programao orientada a objetos que, atravs da definio de classes, determinam a estrutura (variveis e mtodos) que devem ter os objetos instanciados a partir das mesmas. Os TADs so estruturas especificamente construdas para armazenarem determinados tipos de dados. Estas estruturas especificam operadores que permitirem a manipulao destes dados, oferecendo recursos para que cada tipo possa ser processado junto com outros e at mesmo convertido. Sua ideia principal, ento, desvincular o tipo de dado (valores e operaes) de sua implementao, ou seja, definir o "que" o tipo faz e no "como" ele faz! Assim, temos as seguintes vantagens:
Integridade dos dados Facilidade de manuteno Reuso

Utilizando Tipos Abstratos de Dados, a programao segue duas fases: aplicao e implementao. Na primeira, apenas as operaes definidas de maneira abstrata so utilizadas, no sendo permitido o acesso direto aos dados (o usurio s tem acesso s operaes). J a segunda consiste na codificao das operaes em uma linguagem de programao que d suporte ao TAD definido. Dessa maneira, um TAD consiste em duas partes:
Definio dos valores: em geral, consiste de uma clusula de definio e outra de condio. Definio dos operadores: cabealho (parmetros e resultado), prcondies (opcionais) e ps-condies.

De acordo com esses conceitos, vamos ver a definio de um Tipo de Dados Abstrato para um nmero racional, na figura 5. Veja que, primeiro fazemos a definio dos valores que o compem, que neste caso so dois nmeros inteiros. Ainda na definio do valor, verifique que existe uma condio que diz que o segundo nmero inteiro deve ser diferente de zero. Logo em seguida, observe que vem a definio dos operadores, em que so informados os parmetros, pr-condio, ps-condio, a funcionalidade do operador e o seu resultado. Notou como fcil definir um TAD? Que tal utilizar essa definio informal e cri-lo utilizando a linguagem Pascal? Se gostou do desafio, continue na aula que voc aprender como fazer logo em seguida. Vamos aprender na prtica como faz-lo.

Figura 5 - Definio informal do tipo abstrato de dados para representao e operao com nmeros racionais (SAIBEL, 2006)

Na prtica, o TAD pode ser implementado, em Pascal, parcialmente usando um tipo composto (RECORD) formado por campos que representem os valores (numerador, denominador) e por funes que operam sobre os mesmos. Quando dito parcialmente, porque um programa em Pascal no pode ser reutilizado, a no ser que o seu cdigo seja copiado. Para a implementao correta de TAD, utilizando a linguagem Pascal, voc deve utilizar UNIT. Vejamos o exemplo a seguir, utilizando registro.

Figura 6 - Cdigo parcial de implementao do tipo abstrato de dados para representao e operao com nmeros racionais. Fonte: Fbio Rezende Lucas

De acordo com o cdigo acima, voc observa que nada mais foi criado, a no ser um programa em Pascal que utiliza registros e funes. Nesse programa, implementamos o TAD nmero racional. Agora, tente responder a seguinte pergunta: caso voc queira utilizar em outro programa essa estrutura, o que voc faria? Voc pensou em copiar o cdigo para o outro programa? Parabns, voc acertou! Mas, isso no seria muito repetitivo? Qual seria a melhor opo, ento? A resposta seria a utilizao de UNIT em Pascal. Com ela voc seria capaz de criar um TAD e utiliz-lo no programa que quisesse sem ter que defini-lo em todo programa que queira utilizar. Ento, vamos ver um pouco sobre UNIT. A UNIT uma coleo de constantes, tipos de dados, variveis, procedimentos e funes definidos em Pascal. Ela funciona como um programa em Pascal separado, sendo uma biblioteca de declaraes que permite dividir um programa e compil-lo em partes separadas. Um exemplo de UNIT a CRT, a qual voc j sabe utilizar. Ela uma biblioteca que contm todas as declaraes de rotinas relativas apresentao na tela do computador. Veja agora, na figura 7, a estrutura para definir uma UNIT:

Figura 7 - Estrutura para criao de uma UNIT em Pascal Fonte: Fbio Rezende Lucas

A figura acima exibe a estrutura para definir uma UNIT em Pascal. Note que a UNIT deve receber o mesmo nome do arquivo em que ela for salva. Na definio de interface devemos escrever apenas o cabealho das funes e procedimentos que a UNIT possui. J na definio de implementao, todas as funes e procedimentos listados na interface devem ser implementados. Pronto! Agora, s criar um novo programa e incluir a UNIT criada, utilizando o comando uses. Com isso, voc poder utilizar todas as definies feitas nela e em qualquer programa, sem ter que copiar cdigo toda vez que quiser utilizar uma mesma funcionalidade. Alm disso, existe outra vantagem que a manuteno. Caso queira alterar a implementao da funcionalidade, esta ser feita apenas uma vez dentro da UNIT e refletir em todos os programas que a utilizam. Agora que vimos a estrutura, vamos analisar o trecho de cdigo de uma UNIT em Pascal, apresentado na figura 8. Veja que nele foi indicado que o nome do arquivo deve ter o mesmo nome da UNIT, que foi chamada de IntLib. Na definio de interface, definimos o cabealho de um procedimento e uma funo, os quais trocam o contedo de duas variveis e retornam o maior valor entre duas variveis, respectivamente. Na definio de implementao, voc pode observar que o local onde deve ser feita a implementao propriamente dita do procedimento e da funo.

Figura 8 - Exemplo de uma UNIT em Pascal Fonte: Fbio Rezende Lucas

Observe agora, na figura 9, a utilizao da UNIT em um determinado programa. Veja que indicamos a sua utilizao atravs do comando uses, seguido do seu nome. J no corpo do programa, utilizamos a funo e o procedimento, ambos definidos na biblioteca criada previamente.

Figura 9 - Exemplo de utilizao da UNIT criada na figura 8. Fonte: Fbio Rezende Lucas

Com isso, terminamos a nossa primeira aula. Com esses exemplos, voc ser capaz de criar seus prprios Tipos Abstratos de Dados de acordo com as necessidades especficas. Que tal comear pela questo para reflexo?

SNTESE
Nessa aula vimos a definio de algoritmos e como eles esto relacionados com estrutura de dados. Vimos, tambm, os tipos de dados primitivos e estruturados (vetores, registros, conjuntos e arquivos), a fim de que voc conhecesse algoritmos e dados. Mas, o principal objetivo da aula foi mostrar como trabalhar com todos esses conceitos, criando e utilizando tipos abstratos de dados. Gostou do assunto? Na prxima aula teremos mais novidades. Voc aprender a criar algoritmos recursivos que vo facilitar e diminuir a complexidade dos cdigos. At l!

QUESTO PARA REFLEXO


Voc aprendeu tudo sobre tipos abstratos de dados mesmo? Que tal implementar a definio informal de nmeros racionais, apresentada na figura 5, com UNIT?

LEITURA INDICADA
Sees 1.1, 1.2 e 1.5 de ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

SITE INDICADO
FREE PASCAL TEAM. Free pascal: Units. Disponvel em: <http://www.freepascal.org/units.var>. Acesso em: 25 abr. 2010.

REFERNCIAS
SAIBEL, Celso. Algoritmos e estrutura de dados. Apresentao da Aula 1 da disciplina Estrutura de Dados do Mestrado em Sistemas e Computao da UNIFACS. Salvador, 2006. SAIBEL, Celso. TAD - tipo abstrato de dados. Apresentao da Aula 1 da disciplina Estrutura de Dados do Mestrado em Sistemas e Computao da UNIFACS. Salvador, 2006. ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

Exerccios de Estrutura de Dados - Aula 1


Professor: Artur Henrique Kronbauer 1. Defina informalmente um TAD representando um tipo de dado RACIONAL, contendo as seguintes operaes: Criar: recebe dois inteiros e retorna um Racional; Somar, Multiplicar, Dividir, Subtrair: recebem dois racionais e retornam um terceiro com o resultado da operao; Teste de igualdade, Teste de superior/inferioridade (> ou <): recebem dois racionais e retornam o resultado da comparao. 2. Escreva uma UNIT em Pascal para implementar o TAD RACIONAL definido anteriormente. Considere duas situaes: Considere uma implementao do TAD RACIONAL onde o numerador e o denominador esto armazenados em um registro; Considere outra implementao do mesmo TAD na qual o numerador e o denominador esto armazenados em um vetor de inteiros de 2 posies; A quantidade de nmeros mpares; Quais os nmeros mpares.

AULA 2 - RECURSIVIDADE
Autor: Fbio Rezende Lucas

Ol! Vamos aprender nessa aula mais um assunto bem recorrente no ramo de programao de software. Trata-se de recursividade. Voc sabe o que isso? Os prximos tpicos desta aula apresentaro o seu conceito, exemplos de utilizao, dicas de quando utilizar e at mesmo quando no utilizar. Preparado? Vamos l!

RECURSIVIDADE: CONCEITOS E APLICAES


Nos algoritmos apresentados at o momento, ns utilizamos as estruturas de repetio para resolver alguns dos problemas relacionados s estruturas aplicadas, como vetores e matrizes. Contudo, na programao existe um recurso que no utilizamos at ento denominado recursividade, ou melhor, algoritmos recursivos. Nos programas que fazem uso da recursividade as funes podem chamar a si mesmas, em que muitas vezes tm o mesmo efeito das estruturas de repetio vistas at agora. Nesta aula, vamos explorar um pouco mais deste recurso. Segundo Wirth (1989),
Um objeto dito recursivo se ele consistir parcialmente ou for definido em termos de si prprio... O poder da recurso deve-se, evidentemente, possibilidade de se definir um conjunto infinito de objetos atravs de uma formulao finita... Sendo assim, um nmero infinito de clculos pode ser definido por um programa recursivo finito, ainda que este no contenha repeties explcitas [...]

Uma explicao menos formal sobre o conceito pode ser dada atravs de um exemplo do nosso cotidiano. Voc j se deparou com uma situao em que um espelho mostra a imagem de outro? Ou seja, eles acabam apresentando a imagem de forma infinita. Outro exemplo que podemos citar quando uma cmera filma ao vivo a mesma transmisso que est sendo feita. Repare que a TV acaba apresentando sempre a mesma imagem, uma dentro da outra. Veja um exemplo disso no link abaixo.

http://www.youtube.com/watch?v=8E8SRB80Jqc

Para Ziviani (2005), um procedimento dito ser recursivo quando chama a si mesmo, de forma direta ou indireta. Diz tambm, que recursividade permite descrever algoritmos de forma mais clara e concisa, especialmente problemas recursivos por natureza ou que utilizam estruturas recursivas. Exemplos de algoritmos dessa natureza so nmeros naturais, funo fatorial, definio de rvores, percursos em rvores binrias e de pesquisas (veremos em aulas posteriores) entre outros. Esses algoritmos so principalmente usados quando a estratgia de se resolver um problema pode ser feita de maneira recursiva ou quando os prprios dados j so definidos de maneira recursiva. Existem problemas que naturalmente apresentam estas duas condies, porm no aconselhado usar algoritmos recursivos. Isto possvel porque um problema que pode ser resolvido de maneira recursiva tambm pode ser resolvido de maneira interativa, ou seja, com laos de repeties. Algumas das principais vantagens de usar recurso so a possibilidade de se gerar programas mais compactos, programas fceis de entender e o uso de uma estratgia para se resolver o problema, que dividi-lo em problemas menores (MIYAZAWA, 2000). Para trabalharmos com recurso, voc utilizar bastante os conceitos aprendidos sobre procedimentos e funes. Com isso, podemos dizer que uma rotina (procedimento ou funo) recursiva, se ela chama a si prpria atravs de uma das duas maneiras: direta ou indiretamente. Essas formas com que as rotinas so invocadas por si prprias so consideradas como tipos de recursividade. A primeira diz que, se uma rotina R1 faz uma chamada a si prpria no meio da sua implementao, ela considerada recursiva direta. J a segunda define que, caso R1 no faa uma chamada a ela mesma, mas outra rotina R2, que foi invocada por R1, volte a chamar R1, ento ela recursiva indireta. Conforme Ziviani (2005), para a execuo de um programa recursivo, gerada uma pilha para armazenar os dados usados em cada chamada de um procedimento que ainda no terminou. Dessa maneira, todos os dados no globais vo para a pilha, registrando o estado corrente da computao da rotina. Por fim, quando uma ativao anterior prossegue, os dados da pilha so recuperados at o trmino dela. Um importante requisito para o desenvolvimento de rotinas recursivas garantir o nmero finito dessas chamadas. Caso esse requisito no seja atendido, o programa far infinitas chamadas recursivas at que no haja memria suficiente para armazenamento dos dados na pilha, havendo um "estouro de memria" (expresso bem conhecida no mundo da computao). Miyazawa (2000, p. 98) diz que,
Para garantir que este processo seja finito, tenha em mente que sua rotina recursiva trabalha sobre uma instncia e para cada chamada recursiva que ela ir fazer, garanta que a instncia que ser passada a ele seja sempre mais restrita que a da chamada superior. Alm disso, garanta que esta seqncia de restries nos leve a uma instncia suficientemente simples e que permita fazer o clculo deste caso de maneira direta, sem uso de recurso. isto que garantir que seu processo recursivo tenha fim. Vamos chamar esta instncia suficientemente simples (que a rotina recursiva resolve de maneira direta) de base da recurso.

Vejamos a seguir um exemplo simples de recursividade para entendermos o procedimento.

Neste exemplo, apresentamos um procedimento recursivo e vamos verificar o que acontece, passo a passo, durante a sua execuo, a cada chamada recursiva. Inicialmente, bom destacar quando o procedimento para de fazer chamadas a si prprio (condio de sada). Observe que as chamadas recursivas somente acontecem quando o valor da varivel A maior do que zero. Vejamos agora o que acontece a cada chamada do procedimento.

A cada chamada recursiva o procedimento ficou parado na linha em destaque aguardando o trmino da prxima chamada e assim sucessivamente para os outros. Da ele segue at quando na sexta chamada o procedimento finalmente no faz uma nova chamada (j que o valor da varivel a igual a zero) e termina, consequentemente encerrando as outras que estavam aguardando, indo da chamada 5 at a 1.

Vejamos, ento, um novo exemplo no cdigo a seguir com o mesmo princpio do cdigo anterior.

Para A = 40, o que vai imprimir neste cdigo? Experimente fazer o teste passo a passo, ilustrando as chamadas e os valores das variveis, como fizemos no exemplo anterior. Qualquer dvida, que tal discutir no frum da disciplina? At agora fizemos as chamadas recursivas com procedimentos, mas como faremos com funes que retornam valor? Para responder a esta questo vamos verificar o exemplo de problema do clculo do fatorial de um nmero. Para isso, vamos relembrar a definio de fatorial.

Dessa maneira, podemos observar que se o valor for zero o retorno 1, no alterando o resultado da multiplicao. E caso seja maior do que zero multiplicamos o valor pelo fatorial do valor menos 1. Portanto, a prpria chamada recursiva pode ter estas propriedades. Vejamos:

Agora vamos analisar melhor a funo fatorial recursiva. Note que o parmetro da funo fatorial um nmero inteiro positivo n. A cada chamada recursiva, o parmetro que passado diminudo de uma unidade (o valor que passado na prxima chamada recursiva (n - 1). Assim, a instncia do problema a ser resolvido (o clculo de fatorial) vai diminuindo (ficando mais restrito) a cada chamada recursiva. E este processo deve ser finito porque existe uma condio que faz com que ele pare quando a instncia ficar suficientemente pequena: caso n = 0. Vamos discutir esse caso tambm no nosso ambiente de aprendizagem? At agora aprendemos o que recurso, como us-la, vimos exemplos etc. Vimos tambm, que recursividade deixa os programas menores, mais fceis para entend-los e mais coesos. Porm, h momentos em que mesmo que o clculo seja definido de forma recursiva, devemos evitar o uso de recurso. Da, voc deve estar se perguntando: quando no devemos utilizar recurso e por qu? Essa uma boa pergunta! Vamos aprender? Temos duas respostas para a pergunta. No devemos utilizar recurso quando temos uma chamada recursiva no incio ou fim da rotina e quando temos repetio de processamento. No primeiro caso, podemos transformar a rotina em outra interativa (sem recurso) usando um lao de repetio. De fato, nestes casos a rotina recursiva simplesmente est simulando uma rotina interativa que usa uma estrutura de repetio, como um for, while ou repeat. O motivo de utilizar a forma no recursiva porque cada chamada recursiva aloca memria para as variveis locais e parmetros. Assim, a funo fatorial recursiva chega a gastar uma memria que proporcional ao valor n passado como parmetro na funo. Por outro lado, a funo no recursiva gasta uma quantidade pequena e constante de memria local, sendo mais rpida e usa menos memria para sua execuo. O outro caso, repetio de processamento, no indicado utilizar recursividade porque na maioria das vezes cada uma destas chamadas

recursivas independente uma da outra. Assim, quando ocorrem os mesmos clculos entre duas chamadas recursivas independentes, estes sero repetidos para cada chamada. Com isso, pode ocorrer uma grande quantidade de clculos repetidos, o que pode tornar o algoritmo invivel (MIYAZAWA, 2000). Vamos ver agora um exemplo de um programa recursivo em que no indicada a sua utilizao, apesar da funo ser naturalmente recursiva, pois causa um nmero exponencial de clculos, enquanto a verso interativa pode ser feito em tempo proporcional a n (o parmetro da funo). Utilizaremos a funo de Fibonacci que definida matematicamente como:

Veja, agora, o cdigo recursivo para clculo da funo Fibonacci de um determinado nmero qualquer.

Tendo visto o programa, veja o que acontece quando executamos e digitamos o valor 5 para n. A figura 1 ilustra essa situao. Verifique que cada chamada recursiva feita independente das chamadas anteriores. Com isso, provocada uma grande repetio dos clculos para algumas chamadas. Note, por exemplo, que a chamada a F(3) ocorreu quatro vezes e a F(1) ocorreu cinco.

Figura 1 - Chamadas recursivas feitas por Fibonacci(5) (MIYAZAWA, 2000, p. 102).

Com isso, voc acaba de aprender que nem sempre devemos utilizar recursividade, pois existem alguns casos em que ela no a melhor opo. Porm, voc aprendeu ao longo de toda aula os seus conceitos e como criar um programa com funes ou procedimentos recursivos.

SNTESE
Finalizamos agora mais um objetivo da nossa disciplina que recursividade. Vimos aqui os seus conceitos com as definies feitas por Wirth (1989) e Ziviani (2005), bem como exemplos de utilizao com procedimentos e funes. Fizemos tambm a execuo passo a passo de algoritmos e exemplo de at quando no utilizar recurso. Na prxima aula voc ver mais um assunto novo, que ser ponteiros. At a prxima aula.

QUESTO PARA REFLEXO


Voc viu nessa aula como fazer um programa recursivo para calcular a funo Fibonacci. Alm disso, aprendemos que para o caso dela a melhor opo no seria empregar a recursividade e sim utilizar a forma interativa com lao de repetio. Ento, que tal fazer o algoritmo interativo para essa funo e compar-la com o cdigo recursivo?

LEITURAS INDICADAS
Seo 2.2 de ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

REFERNCIAS
MIYAZAWA, Flvio Keidi; KOWALTOWSKI, Tomasz. Notas de Aula de Algoritmos e Programao de Computadores. Instituto de Computao da UNICAMP. So Paulo, 2000. WIRTH, N. Algoritmos e estruturas de dados. Rio de Janeiro: Prentice-hall, 1989. ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

Exerccios de Estrutura de Dados - Aula 2


Professor: Artur Henrique Kronbauer 1. Escreva um programa que leia dois nmeros inteiros e possa elevar o primeiro nmero na potncia do segundo nmero, usando uma funo recursiva para realizar essa operao. Exemplo: 34 = 3 X 3 X 3 X 3 = 81

2. Escreva um programa com uma funo recursiva que imprima na tela a sequncia de Fibonacci (1, 1, 2, 3, 5, 8, ...) at o seu 15 elemento. Dica: O prximo nmero da sequncia de Fibonacci a soma dos dois nmeros anteriores. Os dois primeiros nmeros (1, 1) devem ser passados como parmetros iniciais na primeira chamada da funo recursiva.

3. Escreva um programa para ler nmeros inteiros e colocar em um vetor, aps crie uma rotina recursiva para ordenar o vetor. No final mostre o vetor ordenado.

AULA 3 - PONTEIROS
Autor: Fbio Rezende Lucas

Ol, tudo bem? Vamos aprender mais um assunto novo? Vamos ver nesta aula os conceitos e exemplos de apontadores ou ponteiros. At agora os algoritmos implementados por voc utilizaram estruturas de alocao esttica, ou seja, estruturas com tamanho e endereo de memria fixos. Vamos aprender aqui, como manipular estruturas de alocao dinmica, as quais nos permitem que as posies de memria sejam alocadas em tempo de execuo, otimizando o uso da memria. Vamos l!

ALOCAO ESTTICA X ALOCAO DINMICA


Quando utilizamos as estruturas de alocao esttica, temos que prever o espao de memria a ser utilizado pelos programas durante a sua execuo. Isso acontece quando trabalhamos com vetores ou matrizes, por exemplo. Veja o exemplo de cdigo a seguir:

Note que nesse exemplo declaramos uma varivel do tipo array (vetor) com 5 posies. Como citado anteriormente, temos a um exemplo de alocao esttica, pois quando declaramos a varivel nomes, estamos reservando 5 posies na memria para armazenar dados do tipo string durante a execuo do programa. Com isso, se quisssemos adicionar mais um dado na posio 6 do vetor, por exemplo, o programa iria apresentar um erro em tempo de execuo e abortaria. Como se pode notar, o problema da alocao esttica justamente o fato do programador ter que prever o que dever ser armazenado durante a execuo do programa. Muitos desenvolvedores at fazem um super dimensionamento das posies de memria, reservando mais espao do que o que realmente vai precisar, tendo em vista uma eventual necessidade. Contudo, o super dimensionamento no uma boa prtica de programao, j que implica em desperdcios no uso da memria. Ento, como resolver este problema?

A resposta para isso seria programar utilizando alocao dinmica de memria. Dessa maneira, no precisaramos super dimensionar nossas estruturas, fazendo a alocao dos espaos de memria na execuo do programa. E para fazer isso, do que precisaremos? Est difcil? Acho que no, pois a resposta seria utilizar apontadores. Vamos ver na prxima seo os seus conceitos e como utiliz-los. Mas, antes analise um pouco como feita a alocao esttica na memria. Veja o exemplo a seguir.

Nesse exemplo, o programa fez a reserva de memria para duas variveis para armazenar dados do tipo string e integer, como visto na declarao de variveis. Com isso, analisando a figura 1, o sistema deixa as duas posies de memria alocadas somente para uso dessas variveis quando o programa estiver em execuo. Alm disso, para cada posio reservada (33E153, 41FF12) deu-se um apelido (nome e idade, respectivamente), que o programador pode referenciar durante o programa. Endereo 33E153 41FF12 5AB341 89CD1A
Figura 1 - Tabela de alocao de memria

Apelido nome idade

Status X X

Depois de feita a alocao, quando o programa executar as instrues de atribuio de valores para as variveis, utilizando seus "apelidos" para ter o acesso s posies de memria (33E153, 41FF12), tem-se o armazenamento das informaes, conforme ilustra a figura 2.

Endereo 33E153 41FF12 5AB341 89CD1A

Apelido nome idade

Status joo 65

Figura 2 - Tabela de alocao de memria com atribuio de valor

Como se pode verificar, a alocao de espao de memria de forma esttica, muitas vezes, se d pelo fato de termos que definir os nomes para todas as variveis que pretendemos utilizar, indicando seus tipos. At na utilizao de vetores isso feito, pois cada associao de um ndice ao vetor tratada como um espao de memria alocado. No exemplo 1 isto pode ser observado, por exemplo, nas instrues que utilizam nomes[1], nomes[4] etc. Agora que entendemos como funciona a alocao esttica, voc deve estar se perguntando: como fazer ento para ter acesso aos endereos de memria diretamente sem ter de declarar inmeras variveis num programa? Voc j deve saber que devemos utilizar ponteiros ou apontadores, mas no sabe ainda como, no ? Vamos ver na prxima seo.

PONTEIROS OU APONTADORES
Ponteiro um tipo de dados utilizado apenas para registrar endereos de memria, permitindo que no precisemos declarar uma varivel para cada uma delas. Ou seja, as variveis do tipo ponteiro, guardam endereos que apontam para posies de memria do programa, acessando indiretamente os valores das variveis. importante saber, tambm, que um apontador pode "apontar" para uma rea de memria associada a qualquer tipo de dado, incluindo os registros (records). A sintaxe bsica em Pascal para a criao de um ponteiro : type TipoPonteiro = ^TipoDado; var NomePonteiro: TipoPonteiro; Sendo que sua representao na memria conforme a figura 3. Nesse exemplo, a varivel NomePonteiro, conforme declarada no exemplo da sintaxe, uma varivel do tipo ponteiro e guarda endereos para posies de memria que registram dados do tipo informado.

Figura 3 - Representao de varivel do tipo ponteiro

Vamos ver agora um exemplo de programa completo com utilizao de ponteiros. Depois dele, vamos analisar cada instruo para entendermos melhor o que cada uma delas faz e como estar o espao de memria alocado.

Ento, vamos analisar o programa e suas instrues?

A declarao em Pascal:
type int_pont = ^integer; Declara um tipo de varivel chamado int_pont, que um apontador (denotado por ^) para um nmero inteiro.

A declarao:
var iptr : int_pont; Declara uma varivel chamada iptr do tipo int_pont. Essa varivel no contm um valor numrico, ela ir armazenar endereos de memria de uma varivel criada dinamicamente (pelo uso da declarao de criao que veremos daqui a pouco...). Note que neste instante, ainda no existe espao de memria alocado com iptr, ou seja, no existe nenhum espao de memria associado ao apontador, conforme a figura 4.

Figura 4 - Estado do ponteiro aps ter sido declarado

O comando:
new (iptr); Cria uma nova varivel dinmica referenciada por iptr, ou seja, ela s criada quando o programa estiver executando. Com isso, a varivel do tipo apontador iptr "aponta" para o endereo do espao de memria usado para armazenar um valor inteiro.

Figura 5 - Estado do ponteiro aps a criao com o comando new(iptr)

O comando:
iptr^ := 10; Escreve no espao de memria "apontado" por iptr, um valor numrico inteiro 10. Agora, o ponteiro est associado a um endereo de memria que foi alocado na instruo anterior, a qual acabou de armazenar o valor atribudo. Veja na figura como ficou.

Figura 6 - Estado do ponteiro aps a atribuio de um valor

O comando:
dispose (iptr); Libera o espao de memria apontado por iptr, retornando esse espao para o sistema. O apontador iptr s poder ser usado novamente se for

associado a outra declarao new(). Dessa maneira, seu estado retorna para o mesmo quando ele foi declarado. Veja na figura 7.

Figura 7 - Estado do ponteiro aps a liberao do espao da memria

Vamos ver agora o cdigo do exemplo anterior um pouco modificado para aprendermos mais um novo recurso com ponteiros?

Analise o cdigo acima e note um novo valor que comea a surgir que o nil. Devemos utiliz-lo quando o apontador no faz referncia a nenhuma posio de memria, recebendo este valor como atribuio. Vamos analisar a sua utilizao.

A declarao:
iptr := nil; Informa que o apontador no faz referncia a nenhuma posio de memria. Com isso, dizemos que o apontador vlido, que ele existe, mas no est apontando para nenhuma posio de memria ou varivel dinmica.

A declarao:
if (iptr = nil) then um exemplo de teste muito comum com apontadores. Essa condio testa iptr para verificar se ele um ponteiro nulo, ou seja, se ele no est apontando para uma referncia vlida. Agora, vamos analisar um novo cdigo para verificar como feita a atribuio de valores com ponteiros.

Vamos analisar agora, atravs de figuras, o que ocorre com os ponteiros e com os espaos de memria alocados para eles. Vamos analisar primeiro a criao deles. Note na figura 8 que foram alocados dois espaos de memria diferentes para cada um dos ponteiros, quando eles so criados.

Figura 8 - Estado dos ponteiros e memria quando eles so criados

Agora, na figura 9, veja que cada um dos ponteiros continua referenciando seus espaos de memria diferentes, porm com os respectivos os valores atribudos.

Figura 9 - Estado dos ponteiros e memria quando valores so atribudos

E, se voc atribuir um ponteiro ao outro? possvel? Sim, possvel. Veja no programa que atribumos um ponteiro ao outro. Agora voc deve estar se perguntando: o que acontecer? Muito bem! A figura 10 ilustra exatamente essa situao. Note que um ponteiro foi atribudo ao outro e que, agora, eles passam a referenciar o mesmo espao de memria. No exemplo, os dois ponteiros referenciam um nico espao de memria que est com o valor 25.

Figura 10 - Estado dos ponteiros quando referenciam o mesmo espao de memria

E agora, o que acontecer quando atribuirmos um valor a qualquer um dos ponteiros? Essa fcil! Se eles esto apontando para o mesmo espao de memria, logo um valor atribudo poder ser acessado por qualquer um deles. Veja na figura 11 como isso ocorre.

Figura 11 - Atribuio de um novo valor para ponteiros que referenciam o mesmo espao de memria

Nesse caso, atribumos o valor 3 ao endereo de memria que iptr1 referencia. Note que, tanto ele quanto iptr2 esto com o mesmo valor, j que esto associados ao mesmo endereo de memria. Com isso, chegamos ao fim da nossa terceira aula.

SNTESE
Vimos nesta aula como trabalhar com estruturas de alocao dinmica de memria em Pascal. Para isso, utilizamos o conceito de ponteiro, o qual cria e utiliza dinamicamente valores na memria em tempo de execuo. Atravs dos

exemplos, foi possvel observar passo a passo os estados dos ponteiros e memria quando utilizamos esse novo recurso. Tais conceitos so importantes e sero necessrios para a implementao de Listas dinmicas que comearemos a ver a partir da prxima aula.

QUESTO PARA REFLEXO


Que tal implementarmos agora o algoritmo do exemplo 1 utilizando ponteiros?

LEITURAS INDICADAS
Captulo 18 de MANZANO, Jos Augusto N. G.; YAMATUMI, Wilson Y.. Free Pascal: Programao de Computadores. rica, 2007. 392 p.

REFERNCIAS
SAIBEL, Celso. Apontadores ou ponteiros. Apresentao da Aula 6 da disciplina Estrutura de Dados do Mestrado em Sistemas e Computao da UNIFACS. Salvador, 2006. ZIVIANI, Nivio. Projeto de Algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

Exerccios de Estrutura de Dados - Aula 3


Professor: Artur Henrique Kronbauer 1. O que um ponteiro? 2. Qual o caractere usado para definirmos o ponteiro para um tipo de dado? 3. Qual o comando usado para instanciarmos um ponteiro? 4. Qual o comando usado para desalocarmos a regio reservada para um ponteiro. 5. Quando queremos verificar se um ponteiro no aponta para nenhum endereo de memria, qual palavra chave do Pascal devemos utilizar? 6. Escreva os comandos em Pascal para as seguintes questes: a) Crie um tipo de dado ponteiro para valores reais. b) Instancie uma varivel V para o tipo indicado acima.

AULA 4 - LISTAS LINEARES E LISTAS SIMPLESMENTE ENCADEADAS


Autor: Fbio Rezende Lucas

Oi! Vamos aprender mais um novo assunto? Essa aula abordar a manipulao de listas em formas diferentes: lineares e simplesmente encadeadas. Ficou curioso para saber o que e quais as diferenas? Ento, vamos comear a nossa aula! Bom estudo!

LISTAS LINEARES
As listas so conjuntos de dados ordenados e de nmero varivel de elementos que podem ser implementadas basicamente em dois tipos de estruturas de dados: alocao sequencial e alocao encadeada. Na sequencial, cada elemento da lista ocupa posio sucessiva ao elemento anterior. J na encadeada, a ordem dos elementos dada pelos apontadores (LORENZI, 2007). A lista sequencial ou linear um conjunto de n nodos, com n 0; x1, x2, ..., xn, com as seguintes propriedades:
Se n > 0, ento x1 o primeiro elemento da lista e xn o ltimo; Para 1 < k < n, xk precedido por xk-1 e sucedido por xk+1; Se n=0, ento dizemos que a lista vazia.

Uma lista linear pode ser considerada tambm como um tipo de TAD que consiste em um conjunto de valores associado s operaes de:
Acesso a um elemento qualquer Insero de um novo elemento Remoo de um elemento Concatenao de duas listas Separao de uma lista em outras listas Contagem do nmero de elementos

Segundo Lorenzi (2007), uma lista linear representada por contiguidade, ou seja, ela aproveita a sequencialidade da memria, de modo que uma lista L (com n nodos e todos do mesmo tamanho) ocupe um espao consecutivo em memria equivalente. Portanto, uma lista linear definida como um vetor. Porm, tratando a lista como um TAD, de costume registrar informaes adicionais, relacionadas, por exemplo, quantidade de elementos, capacidade, e aos elementos que indicam o incio e fim da lista. O exemplo a seguir ilustra essa situao.
1 2 3 polvo 4 siri 5 camaro 6 baleia 7 golfinho 8 peixe 9 lula 10

lista:

Vejamos, agora, as informaes adicionais que so armazenadas para essa

Incio: 3 Fim: 9 Quantidade de elementos: 7 Quantidade mxima: 10

Baseado nesse exemplo, voc pode notar que a lista de valores (iniciando em polvo e terminando em lula) no precisa necessariamente coincidir com as posies do vetor (que inicia em 1 e vai at 10). Com isso, o vetor passa a ser apenas uma estrutura de armazenamento e a lista consiste no conjunto de valores, com as informaes adicionais. Vamos aprender agora como criar essa estrutura e manipul-la?

Manipulao
A lista linear apresentada no exemplo anterior pode, portanto, ser implementada atravs do uso variveis compostas da linguagem Pascal, conforme o exemplo a seguir:

type T_ListaLinear = record qtdAtual: integer; qtdMax: integer; inicio: integer; fim: integer; dados: array[1..10] of string; end; var lista: T_ListaLinear;

Observe que, no exemplo dado foi criado um tipo de dados chamado T_ListaLinear com o vetor que armazenar os dados da lista e algumas informaes adicionais como o incio e o final da lista e a quantidade atual e mxima de elementos. Alm disso, o exemplo mostra a criao de uma varivel denominada lista, que do tipo de dados criado por ns T_ListaLinear. Dessa maneira, acessando os dados referentes nossa lista, com o que foi apresentado antes teramos as informaes da seguinte maneira:

lista.inicio: 3 lista.fim: 9 lista.qtdAtual: 7 lista.qtdMax: 10

Que tal vermos um exemplo completo de um programa que utiliza lista linear? Est ansioso para isso? Ento, vamos l! Veja o exemplo do programa a seguir, que utiliza o conceito de lista linear com a estrutura apresentada nesta aula e algumas funes e procedimentos para manipulao.

O exemplo do programa utilizando lista linear possui um TAD conforme visto anteriormente nessa aula e algumas sub-rotinas para manipulao. Vamos ver passo a passo o que cada uma delas faz:

iniciarLista
Esse procedimento inicializa os dados adicionais que nos do informaes sobre a lista. Note que, diferente do exemplo visto anteriormente, colocamos o incio da lista em 1. Assim, podemos aproveitar toda a sua capacidade.

listaVazia
Esta uma funo auxiliar que verifica o estado da lista, mais precisamente a quantidade de elementos atual nela, para informar se est vazia ou no, retornando um valor booleano.

listaCheia
Ao contrrio da funo anterior, esta verifica se a lista est cheia ou no. Para isso, ela verifica se a quantidade atual de elementos igual quantidade mxima, retornando tambm um valor booleano.

inserir
Este procedimento insere um elemento na lista. Ele recebe como parmetro o valor a ser inserido, verifica se a lista no est cheia para poder inserir o elemento e, caso insira, atualiza os valores da quantidade atual a marcao de fim da lista. Com isso, mostramos algumas operaes bsicas que podemos fazer com listas lineares. Todas essas funes e criao do tipo, ns poderamos colocar um uma unit em Pascal e utiliz-la em qualquer programa que quisssemos. E, ainda, podemos adicionar mais algumas sub-rotinas que so importantes e que no vimos aqui. Como questo para reflexo, seria legal que voc implementasse-as. O que acha? Se no souber quais so essas rotinas, aqui vo alguns exemplos: remoo de um determinado elemento, exibio dos elementos da lista, ordenao, busca etc. Finalizando esta tarefa, vamos aprender mais um novo tipo de lista? Ento, vamos ver agora listas simplesmente encadeadas!

LISTAS SIMPLESMENTE ENCADEADAS


Atravs da alocao esttica, definimos uma lista como sendo um conjunto de valores consecutivos que eram implementados atravs de vetores, conforme a seo anterior.

Se pararmos para analisar um pouco mais a estrutura da lista linear, vimos que os valores so encontrados porque existe um ndice que nos permite acess-los diretamente. Internamente, o vetor armazena os seus valores em posies consecutivas da memria. Sendo assim, os ndices dos vetores fornecem uma sequncia de valores (1, 2, 3, 4, 5,...) que nos orientam na navegao pela sua estrutura. Ou seja, pelo vetor apresentado na seo anterior, ns sabemos cada valor que se segue aps o outro, pois estes esto indexados pelos valores 1, 2, 3... Agora vamos ver como implementar uma lista sem termos acesso direto aos valores atravs dos seus ndices. Da, voc deve estar se perguntando: como isso seria possvel? Essa uma boa pergunta. Ento, vamos esclarecer todas as nossas interrogaes! Primeiro, devemos saber que utilizaremos alocao dinmica da memria para conseguir tal propsito. Conforme Lorenzi (2007), as listas simplesmente encadeadas utilizam nodos com apenas um campo de ligao. Eles so formados por um registro que possui, pelo menos, dois campos, que so: a informao e o endereo de memria onde est armazenado o prximo elemento da lista. E agora, j est visualizando como funciona a lista simplesmente encadeada? Vamos deixar mais claro ainda? Observe, ento, a figura abaixo, na qual voc pode ver onde a informao armazenada e como feito o elo entre os elementos.

Figura 1 - Representao grfica de lista simplesmente encadeada

Fazendo uma comparao com as listas lineares, podemos concluir que ambas apresentam uma forma de armazenar dados sequencialmente. Porm, a forma de acesso e como so armazenadas essas estruturas que as diferem. Mas, se pensarmos em termos de operaes sobre essas listas teremos alguma diferena? Em relao rotina propriamente dita no, mas em relao sua implementao sim. Ento, vamos ver agora como criar um TAD para uma lista simplesmente encadeada e como manipul-las.

Manipulao
Para implementarmos a lista simplesmente encadeada atravs da linguagem Pascal vamos relembrar a definio de TAD para listas lineares em vista na seo anterior. No TAD de listas lineares, utilizamos uma estrutura para

armazenar a lista e duas variveis que indicavam o primeiro e o ltimo da lista. Agora, a estrutura da lista ser definida pela prpria definio do n e no com vetores, como antes. Alm disso, teremos duas variveis do tipo apontador para indicar o primeiro e ltimo elemento. Vejamos o cdigo em pascal a seguir.

type T_Ponteiro = ^T_No; T_No = record info: string; prox: T_Ponteiro; end; var inicio, fim: T_Ponteiro;

Nesse exemplo de cdigo, estamos definindo um tipo de dados em que a varivel declarada do mesmo armazenar endereos de memria. Esse endereo apontar para um n (T_No) da lista que na verdade uma estrutura de tipo composto que possui um dado do tipo string (info) e uma indicao do prximo elemento (varivel prox que do tipo T_Ponteiro). O tipo criado T_No define justamente a estrutura de tipo composto que cada n da lista dever ter. Por fim, as variveis declaradas vo receber endereos de memria referentes s posies do primeiro e do ltimo n da lista. Dessa maneira, acessando os dados referentes nossa lista, com o que foi apresentado na figura 1, teramos as informaes de acordo com a figura 2.

Figura 2 - Representao grfica de lista simplesmente encadeada de acordo com o tipo definido

Observando a figura 2, note que as variveis inicio e fim apontam respectivamente para o primeiro e ltimo n da lista. Veja tambm, que no ltimo n, o campo que aponta para um prximo elemento da lista deve ser nil, j que no existe mais nenhum aps este. Fazendo um paralelo com a estrutura de lista linear, podemos criar mais um tipo de dados onde agruparemos a informao de inicio e fim e podemos inserir as informaes de quantidade e quantidade mxima (se quisermos restringir o tamanho, pois a quantidade mxima ser a quantidade de memria disponvel). Dessa maneira nossa estrutura ficaria conforme o cdigo a seguir.

type T_Ponteiro = ^T_No; T_No = record info: string; prox: T_Ponteiro; end; T_Lista = record inicio, fim: T_Ponteiro; qtdAtual, qtdMax: integer; end; var lista: T_lista;

Vamos ver agora um exemplo completo de um programa que utiliza lista simplesmente encadeada? No exemplo a seguir, temos um programa que utiliza o conceito apresentado e algumas rotinas para manipulao. Vamos ver passo a passo o que cada uma delas faz:

iniciarLista
Esse procedimento inicializa os dados da lista. Fazemos com que o incio aponte para nil e que o fim seja igual ao incio, alm de colocarmos a quantidade atual como zero. Esse procedimento recebe como parmetro um inteiro para caso ser necessrio limitar o tamanho da lista.

listaVazia
Esta uma funo auxiliar que verifica o estado da lista, mais precisamente a quantidade de elementos atual nela e se o inicio est como nil, para informar se est vazia ou no, retornando um valor booleano.

listaCheia
Ao contrrio da funo anterior, esta verifica se a lista est cheia ou no. Para isso, ela verifica se a quantidade atual de elementos igual quantidade mxima, no caso de termos um valor mximo para a quantidade de elementos da lista, retornando tambm um valor booleano.

inserir
Este procedimento insere um elemento, que foi passado como parmetro, na lista. Note que para fazer a insero necessria a declarao de uma varivel local auxiliar novoNo. A partir da, verificado se a lista no est cheia para poder inserir o elemento. Sendo possvel, criado um novo ponteiro, utilizando a varivel local e em seguida fazemos com que seu campo de informao receba o valor passado como parmetro e o campo de prximo receba nil, j que a insero feita no final. Mas, ainda necessrio verificar se a insero realizada do primeiro elemento, caso a lista esteja vazia, ou de outros elementos, caso j exista algum elemento na lista. Para o primeiro caso (insero do primeiro elemento), bastamos fazer com que o incio e o fim da lista sejam iguais ao novo apontador criado. J no segundo caso (insero a partir do segundo elemento), precisamos ainda ajustar os ponteiros para fazer com que o novo n criado seja apontado como ltima posio da lista. Dessa maneira, vimos algumas operaes bsicas que podemos fazer com listas simplesmente encadeadas. Verifique que as rotinas foram as mesmas de listas lineares, alterando apenas a sua implementao. Assim, todas essas rotinas poderiam ser implementadas com unit em Pascal, como indicado em listas estticas tambm. Da mesma maneira, ainda, podemos adicionar mais algumas sub-rotinas que so importantes e que no vimos aqui. Ento vamos adicionar mais uma questo para exercitar? Que tal criar para listas encadeadas as mesmas rotinas solicitadas em listas lineares? S para relembrar, indicamos a implementao das seguintes rotinas: remoo de um determinado elemento, exibio dos elementos da lista, ordenao, busca etc. Finalizando esta tarefa, voc estar apto a enfrentar qualquer tipo de problema utilizando listas simplesmente encadeadas. No deixe de exercitar.

SNTESE
Vimos, nesta aula, os conceitos bsicos sobre listas lineares, sua estrutura e algumas rotinas bsicas para sua manipulao. Alm disso, vimos como implementar essas listas com ponteiros, as quais so conhecidas como listas simplesmente encadeadas. Tivemos a oportunidade de ver exemplos em Pascal das suas estruturas bsicas e dos primeiros algoritmos utilizados para incluso. Na prxima aula daremos continuidade com o assunto de listas, mas veremos novos tipos delas que so: listas circulares e listas duplamente encadeadas. At l!

QUESTO PARA REFLEXO


Ao longo da nossa aula discutimos sobre algumas tarefas que poderiam ser feitas. No seria uma boa ideia resolv-las como questes para reflexo?

LEITURAS INDICADAS
Captulo 4 de LORENZI, Fabiana; MATTOS, Patrcia N.; CARVALHO, Tanisi P. Estruturas de dados. So Paulo: Thomson Learning, 2007. 175 p. Seo 3.1 de ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

REFERNCIAS
LORENZI, Fabiana; MATTOS, Patrcia N.; CARVALHO, Tanisi P. Estruturas de dados. So Paulo: Thomson Learning, 2007. 175 p. SAIBEL, Celso. Listas lineares. Apresentao da Aula 5 da disciplina Estrutura de Dados do Mestrado em Sistemas e Computao da UNIFACS. Salvador, 2006. ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

Exerccios de Estrutura de Dados - Aula 4


Professor: Artur Henrique Kronbauer Observao: Para resolver os exerccios abaixo, crie funes e procedimentos genricos que possam manipular as listas de acordo com os parmetros recebidos. Por exemplo, s deve existir uma funo de insero de elementos, se for passado como parmetro a lista X, deve ser realizada a insero em X, se for passado a lista Y, deve ser realizada a insero em Y. 1. Escreva um programa para cadastrar nmeros inteiros em uma lista simplesmente encadeada. Alm disso, esse programa dever ter uma funo para mostrar a lista e outra para identificar e mostrar os nmeros pares existentes na lista. Dica: Crie um menu com as seguintes funcionalidades: 1- Inserir nmero 2- Mostrar a lista 3- Mostrar os nmeros pares 4- Fim 2. Seja X = (x1, x2, ..., xn) e Y = (y1, y2, ..., ym) duas listas simplesmente encadeadas. Escreva um programa que leia as duas listas e as intercale, formando uma lista encadeada Z = (x1, y1, x2, y2,..., xn,,ym). Dica: Crie um menu com as seguintes funcionalidades: 1- Inserir em X 2- Inserir em Y 3- Criar X 4- Mostrar X 5- Mostrar Y 6- Mostrar Z 7- Fim 3. Escreva um programa que leia duas listas simplesmente encadeadas A e B, as quais devem guardar informaes (Cdigo e Nome) dos pacientes do mdico X e do mdico Y (respectivamente), de uma determinada clnica (ambas as listas devem ser criadas de forma que os elementos fiquem ordenados por cdigo e que no existam cdigos iguais na mesma lista). Os donos da clnica gostariam de ter uma lista nica com as informaes dos pacientes desses dois mdicos, assim, voc deve criar uma lista C contendo todos os pacientes dos mdicos X e Y, tambm ordenada por cdigo e sem repeties.

AULA 5 - LISTAS CIRCULARES E LISTAS DUPLAMENTE ENCADEADAS


Autor: Fbio Rezende Lucas

Ol! Est gostando dos assuntos novos que estamos vendo nas nossas aulas? Espero que sim, pois, agora, vamos aprender um pouco mais sobre listas encadeadas. Veremos dois novos tipos de lista: circulares e duplamente encadeadas. Ento, vamos comear!

LISTAS CIRCULARES
Quando estamos implementando as listas simplesmente encadeadas, geralmente precisamos dar um tratamento especial aos ns das extremidades. Vejamos o exemplo da figura a seguir:

Figura 1 - Representao grfica de lista simplesmente encadeada

Esse exemplo mostra que o n da primeira posio da lista (22) tem uma indicao feita pela estrutura da lista que indica que este o primeiro n. Contudo, este o nico n que no tem nenhum outro n que o antecede. Ou seja, ele aponta para outro n, mas nunca est sendo apontado por outro. Da mesma maneira, o ltimo n (47) o nico que no aponta para nenhum outro, para estes ns sempre o prximo nulo (nil). J o n intermedirio (38) o nico em que aponta para outro e apontado por outro. As particulares de cada um desses tipos de ns das listas, simplesmente encadeadas, fazem com que seja necessrio implementar algoritmos diferenciados para as operaes de incluso e remoo. Vamos ver agora, outro tipo de lista que modifica um pouco essa estrutura: lista circular. A fim de que seja possvel dar um tratamento igual a todos os ns das listas durante as suas operaes de manipulao, implementamos uma variao das listas simplesmente encadeadas pela qual o ltimo n da lista aponta para o primeiro, dando um carter circular. Vejamos o exemplo anterior com as listas circulares.

Figura 2 - Representao grfica de lista circular

Nesse exemplo, o ltimo n da lista (47) aponta para o primeiro (22) e desta forma todos os ns agora possuem as mesmas caractersticas. Ou seja, aponta para algum n e apontado por outro. Com esta nova forma de implementao, as funes de manipulao utilizadas para a incluso e excluso de ns podem ser genricas, sem necessitar dar um tratamento diferenciado, quando a incluso for feita no incio, no meio ou no fim. Porm, inserindo esta ligao teremos um novo problema que se d quando a lista estiver vazia ou com um nico elemento. Da, precisamos ter um novo n na lista que chamamos de n cabea. Este ser um n que marcar o incio e o final da lista e que no ter qualquer valor armazenado. Em outras palavras, quando a lista estiver vazia, ela ter apenas o n cabea que aponta para ele mesmo. Vejamos o exemplo da figura a seguir que apresenta a lista no seu estgio inicial, sem qualquer valor armazenado, mas com o n cabea criado.

Figura 3 - N cabea em uma lista circular vazia

Nesse exemplo, o n cabea (de endereo BF774B) um n vazio e que aponta para ele mesmo. medida que os valores vo sendo includos, os ns vo sendo atualizados. Vejamos a figura a seguir que mostra a disposio da lista com o n cabea aps a incluso do primeiro elemento.

Figura 4 - Representao de lista circular com um elemento

Desta forma o novo n includo agora aponta para o n cabea, e este, por sua vez, aponta para o novo n. Vejamos agora a lista aps a incluso dos outros valores.

Figura 5 - Representao de lista circular com vrios elementos

Manipulao
Agora que vimos o funcionamento das listas simplesmente encadeadas circulares, bem como as suas vantagens em relao s listas normais vamos agora estudar as funes de manipulao. De acordo com o exemplo a seguir, a estrutura da lista a mesma vista na aula passada para lista simplesmente encadeada. Note tambm que as funes que verificam se a lista est vazia e cheia so iguais da aula passada. Porm, a funo que inicializa a lista j um pouco diferente. Vejamos o trecho de cdigo a seguir utilizado para a inicializao da lista (funo iniciarLista). Nesse cdigo, percebemos que a inicializao consiste basicamente na criao do n cabea. Agora, veja que aps a criao do n cabea, a lista ficar igual a estrutura apresentada na figura 3. Pois, a funo que inicia a lista, cria um novo n, faz com que o prximo aponte para ele prprio e em seguida faz com que o incio da lista aponte para ele tambm.

Agora, para inserir um novo elemento na lista, assumiremos que quem chama a funo saber exatamente a posio onde deseja inserir o novo n, passando como parmetro o n anterior posio desejada. Por exemplo, caso a inteno seja inserir um exemplo na primeira posio da lista, passado como parmetro para a funo a posio do n cabea. J para inserir na ltima posio, passa-se como parmetro o n que antecede o n cabea, e assim segue para as outras posies. Ento, vejamos a funo a seguir, que insere um novo elemento na lista.

Que tal voc praticar um pouquinho de manipulao em listas circulares? Para "aquecer os motores", faa um desenho passo a passo iniciando uma lista e depois inserindo diferentes valores, seguindo as instrues das funes apresentadas nos cdigos anteriores. Veja o que acontece e discuta com os colegas no frum da disciplina. Vamos ver agora, como remover um elemento da lista? Se voc fez a remoo como exerccio na aula passada, ver que no modifica muito. Para remover um elemento da lista, temos que antes procur-lo e sempre ter o elemento anterior para manter o encadeamento. Deste modo, iremos varrer a lista procurando o valor e assim que encontr-lo guardamos o n anterior para apontarmos para o n que precede o valor que queremos excluir. A busca inicia pelo n cabea e termina quando chega ao mesmo. Veja o trecho de cdigo abaixo com a funo de remoo.

Nesse cdigo, as instrues no corpo do while fazem a busca pelo valor a ser removido e medida que passa pelos ns, a referncia para o n anterior registrada na varivel noAnt. Quando sai da repetio, o teste efetuado em seguida verifica se o valor foi encontrado. No caso de ser encontrado, a atualizao feita liberando ainda o endereo de memria alocado para o n removido. Vamos ver agora como fazer a busca de um determinado valor. Veja o trecho de cdigo abaixo.

Perceba que para realizar a busca, fazemos algo parecido com o da busca apresentada no cdigo utilizado na funo de remover. Esta funo recebe como parmetros a lista, o valor procurado e retorna o endereo do n procurado. Quando o valor no encontrado, a funo retorna o valor nil.

LISTAS DUPLAMENTE ENCADEADAS


At agora utilizamos uma estrutura de lista que nos permite navegar pelos ns apenas em um nico sentido, em que a partir de um n no possvel chegar ao n anterior. Por isso, veremos agora as listas duplamente encadeadas, as quais possuem uma estrutura que nos permite navegar em ambos os sentidos. Primeiro vamos analisar uma lista simplesmente encadeada. Atravs delas, como a apresentada no exemplo a seguir, conseguimos navegar pelos ns em um nico sentido, ou seja, se tivermos com o endereo do n que possui o valor "banana", no temos como chegar ao n que possui o valor "uva". Isso ocorre porque a estrutura da lista simplesmente encadeada possui um nico ponteiro, o qual aponta para o prximo, conforme a figura a seguir.

Figura 6 - Representao grfica de uma lista simplesmente encadeada

Para fazermos uma lista que possibilite uma navegao em duplo sentido, adicionaremos um novo campo ao n da lista de forma que alm da indicao do prximo, indicaremos tambm o n anterior. Dessa forma, a lista apresentada anteriormente ficaria conforme o exemplo apresentado na figura a seguir.

Figura 7 - Representao grfica de uma lista duplamente encadeada

Dessa maneira, cada n ter trs campos: endereo para o n anterior (esquerda), informao e endereo para o prximo n (direita). Vamos ver, agora, como definir e manipular essa estrutura em Pascal.

Manipulao
Em primeiro lugar, vamos ver como definir a estrutura de uma lista duplamente encadeada. O cdigo abaixo apresenta a definio desse tipo. Note que a nica mudana em relao ao que vimos nas aulas anteriores foi a adio do campo que indica o n anterior (ant). A ttulo de demonstrao, vamos configurar a informao como um campo numrico inteiro.

type T_Ponteiro = ^T_No; T_No = record info: integer; ant, prox: T_Ponteiro; end; var inicio, fim: T_Ponteiro;
Assim como nas listas simplesmente encadeadas, podemos tambm incluir um n cabea para marcar o incio e o fim da lista nas listas duplamente encadeadas. Vejamos a seguir as funes de manipulao, comeando pela definio e inicializao da lista, verificao de lista vazia e de lista cheia.

Em relao ao cdigo apresentado, observe que a diferena para lista simplesmente encadeada somente a criao do ponteiro que aponta para o n anterior da lista. Inserimos aqui o conceito que vimos nesta aula que o n cabea. Como a inicializao trata-se desse n, apenas indicamos que o anterior ele prprio. Assim, a lista fica da seguinte maneira.

Figura 9 - Representao do n cabea em lista duplamente encadeada aps inicializao

Vamos ver agora a funo de insero em uma lista duplamente encadeada. Utilizaremos o mesmo cdigo novamente, mas com algumas alteraes para manipular o ponteiro para o n anterior. Veja o trecho de cdigo a seguir.

Conseguiu visualizar o que aconteceu? Que tal fazer um desenho do passo a passo da insero de n elementos na lista? Este um excelente exerccio, no s para entender o cdigo, mas tambm para entender o funcionamento da lista duplamente encadeada. Vamos ver agora a manipulao da lista para a remoo. Nas listas simplesmente encadeadas precisamos sempre guardar o endereo do n anterior para que no momento da remoo tenhamos condies de manter o encadeamento. Agora um pouco diferente, uma vez que a lista duplamente encadeada e que temos uma indicao do n anterior. Vejamos ento a funo de remoo a seguir.

Dessa forma, o procedimento para remover se tornou mais simples do que era antes para lista simplesmente encadeada. Basta atualizarmos o n anterior ao qual queremos remover, fazendo com que o mesmo aponte para o n seguinte ao da remoo. Em seguida, atualizamos o n posterior remoo para que seu apontador do n anterior aponte para um n antes ao da remoo. Atravs deste novo encadeamento, a posio de memria referente ao n que possui o valor que queremos remover pode ser liberada pelo programa, uma vez que j no faz mais parte do encadeamento da lista. Assim, chegamos ao fim de mais uma aula!

SNTESE
Nesta aula, estudamos sobre listas simplesmente encadeadas circulares e listas duplamente encadeadas. Vimos como criar, inicializar, inserir e remover cada uma dessas estruturas. Alm disso, aprendemos sobre a utilizao de um n auxiliar que chamado de n cabea. Com isso, possvel criarmos listas nas quais podemos navegar em ambos os sentidos (duplamente encadeada) e listas que podemos ir do ltimo n para o primeiro (circular). Na prxima aula, vamos ver mais dois tipos especiais de listas que recebem o nome de pilha e fila. Fazendo uma associao com o que conhecemos sobre esses dois nomes, ser que voc consegue imaginar como funcionam essas estruturas em programao? At a prxima aula!

QUESTO PARA REFLEXO


Ao longo desta aula deixamos alguns questionamentos e algumas dicas para exercitar o conhecimento sobre os tipos de listas vistos nessa aula. Vamos nos empenhar para faz-los?

LEITURAS INDICADAS
Captulo 4 de LORENZI, Fabiana; MATTOS, Patrcia N.; CARVALHO, Tanisi P. Estruturas de dados. So Paulo: Thomson Learning, 2007. 175 p. Seo 3.1 de ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

REFERNCIAS
LORENZI, Fabiana; MATTOS, Patrcia N.; CARVALHO, Tanisi P. Estruturas de dados. So Paulo: Thomson Learning, 2007. 175 p. SAIBEL, Celso. Listas duplamente encadeadas. Apresentao da Aula 10 da disciplina Estrutura de Dados do Mestrado em Sistemas e Computao da UNIFACS. Salvador, 2006. ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

Exerccios de Estrutura de Dados - Aula 5


Professor: Artur Henrique Kronbauer Observao: Utilize os slides da aula 5 para resolver os exerccios 1 e 2. Utilize os slides da aula 4 para resolver o exerccio 3. 1. Escreva um programa para determinar se uma string de caracteres de entrada da forma xCy, onde x uma string consistindo das letras "A" e "B", e y o inverso de x (isto , se x = "ABABBA", y deve equivaler a "ABBABA"). Em cada ponto, apenas o prximo caractere da string pode ser lido. Obs: Use duas listas duplamente encadeadas para armazenar os caracteres de cada string.

2. Escreva um programa capaz de ler uma lista duplamente encadeada. Aps defina um procedimento capaz de encontrar um determinado elemento na lista e excluir o elemento anterior a ele. Determine uma mensagem de erro caso o elemento encontrado esteja na primeira posio da lista e caso o elemento no seja encontrado.

3. Considerando o programa apresentado nos slides da aula 4 para exemplificar a manipulao de listas simplesmente encadeadas, modifique o cdigo para que possa manipular uma lista circular. Ou seja, o ltimo elemento da lista deve apontar para o primeiro elemento da lista.

AULA 6 - PILHAS E FILAS


Autor: Fbio Rezende Lucas

Ol! Vamos comear mais uma aula? Que tal vermos um pouco mais sobre alguns tipos especiais de listas? Pois , nessa aula voc aprender com criar e manipular estruturas do tipo pilha e fila. Esses nomes so comuns a voc? Os conceitos utilizados so os mesmos que conhecemos no mundo real. Agora vamos para o mundo da programao?

ESTRUTURAS LINEARES COM DISCIPLINA DE ACESSO


Segundo Lorenzi (2007), existem algumas estruturas que possuem critrios para incluso e remoo de elementos, que so caracterizadas como:
LIFO (Last In First Out): traduzido, isso significa ltimo que entra o primeiro que sai. Dessa maneira, tem-se que dentre os elementos que esto presentes em um conjunto, o primeiro a ser retirado o ltimo que foi inserido. Com isso, caracterizamos uma estrutura como uma pilha. FIFO (First In First Out): traduzido, isso significa primeiro que entra o primeiro que sai. Dessa maneira, tem-se que dentre os elementos que esto presentes em um conjunto, o primeiro a ser retirado o primeiro que foi inserido. Com isso, caracterizamos uma estrutura como uma fila.

Vamos ver agora os conceitos especficos para essas estruturas e como implement-las em Pascal de algumas maneiras.

PILHAS
Conforme Ziviani (2005) e a seo anterior, existem tipos de listas nas quais as inseres, remoes e acessos so realizados em um dos extremos, ou seja, com uma disciplina de acesso. Uma pilha um tipo de lista com uma disciplina de acesso (LIFO) em que todas as inseres, retiradas e acessos so feitos em apenas um extremo: o topo. Seguindo os conceitos do mundo real, os itens de uma pilha so colocados um sobre o outro, sendo que o mais recente (o ltimo que entrou) fica no topo e o primeiro que entrou fica no fundo. Dessa maneira, a pilha se torna um conceito ideal para processamento de estruturas aninhadas de profundidade imprevisvel, como sintaxe de expresses aritmticas (ZIVIANI, 2005). Veja um exemplo de pilha na figura 1.

Figura 1 - Exemplo de pilha (Adaptado de LORENZI, 2007).

De acordo com a figura 1, temos uma pilha de livros onde o primeiro elemento inserido foi o livro "Java". Da em diante, empilhamos o restante dos livros at chegarmos ao topo da pilha, com o ltimo livro (C) empilhado. E para retirarmos um livro da pilha, o que devemos fazer? Respondeu certo se pensou em desempilhar! Logo, empilhar significa inserir um novo elemento no topo da pilha e desempilhar seria a remoo de um elemento do topo da pilha. Voc est notando os termos que estamos utilizando aqui? Pilha, Topo, Empilhar, Desempilhar... Essas so palavras chaves para trabalharmos com essas estruturas. Com essa nomenclatura que definimos o tipo de dados da pilha e as operaes. Como uma pilha um tipo de lista, ento podemos represent-la da maneira ilustrada na figura 2. Note que o primeiro elemento continua sendo o livro Java e o ltimo o livro C. Se pensarmos em empilhar, teramos que colocar outro livro na posio logo aps o livro C. J para desempilhar, seramos obrigados a retirar o livro C da pilha. Notou que sempre devemos trabalhar com o topo da pilha?
TOPO 5 C

1 Java

2 Pascal

3 SQL

4 Delphi

Figura 2 - Exemplo de pilha no formato de lista

Pilhas lineares
Vimos em aulas anteriores as listas lineares e as listas encadeadas. Da mesma maneira, podemos implementar pilha com listas lineares e com listas encadeadas, utilizando apontadores. Vamos ver agora como seria a implementao com lista linear. Para sua definio utilizamos uma estrutura bem semelhante lista linear.

type T_Pilha = record altura: integer; alturaMax: integer; base: integer; topo: integer; dados: array[1..10] of string; end; var pilha: T_Pilha;

Se voc comparar essa definio com a apresentada na aula 4, voc ver que s temos modificaes nos nomes dos identificadores. Perceba que toda a estrutura (definio do tipo e da varivel) igual. Vamos ver agora o cdigo completo para manipulao dessa pilha. No exemplo a seguir, utilizamos a estrutura definida acima para manipulao de uma pilha. Definimos algumas sub-rotinas como:
iniciarPilha: inicializa os dados adicionais da pilha, como a altura atual, a altura mxima, a base e o topo. pilhaVazia: verifica se a pilha est vazia, analisando se o topo da pilha igual a zero. pilhaCheia: verifica se a pilha est cheia, analisando se o topo igual a altura mxima da pilha. empilhar: insere um novo elemento na pilha, sendo que a insero sempre feita no topo.

De acordo com o que j vimos at aqui, que tal voc criar uma sub-rotina para remoo de um elemento da pilha? Lembre que a remoo s deve ser feita pelo topo. Mas, caso queiramos remover um elemento que se encontra no meio da pilha, como fazer? A resposta para isso seria a utilizao de uma pilha auxiliar. Com isso, voc deve desempilhar os elementos do topo e empilhar na estrutura auxiliar. Quando o elemento a ser removido estiver no topo, voc deve remov-lo e em seguida desempilhar os elementos da pilha auxiliar, empilhando na pilha original. Topa o desafio? Vamos l, desenvolva essa funo e discuta com os colegas no frum da disciplina.

Visto e analisado o cdigo acima de pilhas lineares, vamos agora estudar pilhas encadeadas?

Pilhas encadeadas
Conforme j mencionado, pilhas so listas lineares, e de maneira similar aos casos estudados anteriormente, podem ser implementadas atravs de ponteiros. E, de acordo com os estudos feitos sobre listas encadeadas,

novamente usamos do artifcio da adio de um n chamado n cabea. Ele mantido no topo da pilha para evitar alguns testes desnecessrios nas operaes com a pilha quando ela est vazia. Para facilitar ainda mais, o campo tamanho definido no registro T_Pilha facilita a obteno do tamanho da pilha, sem que seja necessrio que a mesma seja percorrida. Vamos iniciar analisando a figura 3.

Figura 3 - Representao grfica de uma pilha encadeada.

Note que em cima da pilha temos um n auxiliar que justamente o n cabea, que chamamos de topo. O ponteiro nesse n aponta para o ltimo elemento da pilha, que por sua vez aponta para o anterior e assim sucessivamente at chegar a base da pilha. Vamos agora, ver a definio de tipo para pilha encadeada, no exemplo abaixo:

type T_Ponteiro = ^T_No; T_No = record info: string; prox: T_Ponteiro; end; T_Pilha = record base, topo: T_Ponteiro; tamanho: integer; end; var pilha: T_Pilha;
Note que cada n deve conter um item da pilha e um "campo extra" para um ponteiro para outro n da pilha. Veja tambm que o registro T_Pilha contm um ponteiro para o topo da pilha (n cabea) e um ponteiro para o fundo da pilha (ZIVIANI, 2005). Assim, j podemos analisar um cdigo completo para pilhas encadeadas. Vamos ver o cdigo a seguir.

Apresentado o cdigo anterior, vamos agora descrever cada uma das subrotinas. iniciarPilha Inicia a pilha, criando o n cabea para associ-lo pilha como o seu topo. Alm disso, faz com que a base aponte para o topo, j que a pilha inicia vazia e configura o seu tamanho inicial como zero. pilhaVazia Verifica se o topo igual base da pilha, caso positivo retorna verdadeiro, o que significa que a pilha est vazia. Caso contrrio, a pilha no est vazia, fazendo com que a funo retorne falso. esvaziarPilha Funo auxiliar que esvazia totalmente a pilha. Ela cria um novo topo, o associa com a base e zera o tamanho da pilha. empilhar Funo que adiciona um novo elemento no topo da pilha (ambos passados como parmetro) e retorna um valor booleano, indicando se o empilhamento ocorreu ou no. Alm disso, a funo incrementa o valor do tamanho da pilha, caso tenha inserido realmente o novo valor. desempilhar Funo que remove o valor que se encontra no topo da pilha (passada como parmetro). Alm disso, a funo recebe um outro parmetro string para que seja possvel, no corpo do programa, identificar qual elemento foi removido. Caso a remoo tenha ocorrido com sucesso, a funo decrementa o tamanho da pilha e retorna um valor booleano verdadeiro. Agora que voc j est um especialista em pilhas vamos ver outro tipo de lista j citada no incio dessa aula, que fila. Vamos l!

FILAS
Conforme mencionado nas sees anteriores, existem tipos de listas nas quais as inseres, remoes e acessos so realizados em um dos extremos, ou seja, com uma disciplina de acesso. Uma fila um tipo de lista com uma disciplina de acesso (FIFO) em que todas as inseres s podem ser efetuadas em um extremo da lista, e todas as retiradas (e geralmente os acessos) so realizados no outro extremo da lista. Seguindo os conceitos do mundo real, um modelo clssico para exemplificar seria uma fila de pessoas esperando o atendimento em um banco, onde as pessoas do incio da fila so atendidas antes e as que chegam depois, entram no fim da fila. Como pode ser observado, h uma regra que obedece a ordem de chegada. J no mundo computacional, esse modelo usado tipicamente quando se deseja processar itens de acordo com sua ordem de

chegada, como: filas do sistema operacional e simuladores (ZIVIANI, 2005). Veja um exemplo de fila na figura 3.

Figura 4 - Exemplo de fila (Adaptado de LORENZI, 2007).

De acordo com a figura 4, temos uma fila de pessoas com a indicao da primeira pessoa. Da em diante, a fila foi crescendo at atingir cinco pessoas na qual a quinta a ltima que entrou na fila. Com isso, temos o processo natural da incluso em uma lista linear. E para retirarmos ou acessarmos um elemento da fila, o que devemos fazer? Diferentemente da pilha, aqui o acesso e retirada se do na outra extremidade (incio), j que o primeiro que entra o primeiro que sai. Assim como uma pilha, a fila um tipo de lista, ento podemos represent-la da maneira ilustrada na figura 5. Note que o primeiro elemento continua sendo Ado e o ltimo Maria. Se pensarmos em enfileirar, outra pessoa entraria na fila logo aps Maria. J para desenfileirar, quem sairia da fila seria Ado. Notou que em filas trabalhamos com as duas extremidades?
INCIO 1 Ado FIM 5 Maria

2 Eva

3 Jos

4 Joo

Figura 5 - Exemplo de fila no formato de lista

Filas lineares
Da mesma maneira que fizemos com pilha, podemos fazer com fila, alterando apenas as sub-rotinas de insero, remoo e listagem. A estrutura do tipo abstrato de dados permanece a mesma. Vamos analisar a definio de lista a seguir em Pascal.

type T_Fila = record qtdAtual: integer; qtdMax: integer; inicio: integer; fim: integer; dados: array[1..10] of string; end; var fila: T_Fila;

Note que a estrutura se mantm a mesma. O que modifica aqui so os nomes dos identificadores, somente para ficar mais claro e mais inerente que estamos tratando de fila. Analisando a estrutura, inserindo os dados da figura 5 teramos o seguinte:

fila.qtdAtual = 5 fila.qtdMax = 9 fila.inicio = 1 fila.fim = 5


Dessa maneira, o incio da fila est na posio 1 (representando Ado), o final na posio 5 (representando Maria), a varivel que indica a quantidade de pessoas existente na fila (fila.qtdAtual) com valor igual a 5 e a capacidade mxima da fila (fila.qtdMax) com valor igual a 9. Agora, se analisarmos a remoo de elementos da fila teremos um processo com uma determinada caracterstica que vamos analisar. Suponha que retiraremos duas pessoas da fila, ficando da seguinte maneira:
INCIO 3 Jos FIM 5 Maria

4 Joo

Figura 6 - Lista aps remoo de dois elementos

Logo, seus dados ficariam:

fila.qtdAtual = 3 fila.qtdMax = 9 fila.inicio = 3 fila.fim = 5

Inserindo mais quatro elementos teramos:


INCIO 3 Jos FIM 9 Paulo

4 Joo

5 Maria

6 Ana

7 Luiz

8 Carlos

Figura 7 - Lista aps insero de quatro elementos

Logo, seus dados ficariam:

fila.qtdAtual = 7 fila.qtdMax = 9 fila.inicio = 3 fila.fim = 9


Agora, se removssemos mais seis elementos da lista teramos
INCIO FIM 9 Paulo

Figura 8 - Lista aps remoo de seis elementos

Logo, seus dados ficariam:

fila.qtdAtual = 1 fila.qtdMax = 9 fila.inicio = 9 fila.fim = 9


Chegando nesse ponto, o que acontece se acrescentarmos mais um elemento? E se fizermos o teste de fila cheia ou vazia, o que aconteceria? Verificamos, ento, que as sucessivas incluses e remoes fizeram com que a fila tivesse um deslocamento para a direita, dando uma falsa idia de a fila estar cheia quando na verdade no est. Como poderamos resolver este problema? Neste caso, poderamos continuar inserindo os elementos nas posies do vetor que esto disponveis, mas mantendo as propriedades de filas. Se inserirmos mais um elemento, teremos a fila da seguinte maneira:
FIM 1 Joana INCIO 9 Paulo

Figura 9 - Lista aps adio de um elemento

Logo, seus dados ficariam:

fila.qtdAtual = 2 fila.qtdMax = 9 fila.inicio = 9 fila.fim = 1

Analisando o que acabamos de ver, podemos chegar s mesmas concluses que Saibel (2006) que so:
Quando um elemento enfileirado, a parte final da fila esticada. Quando um elemento retirado da fila, a parte frontal da fila contrada.

A consequncia disso que a fila "anda" pelo espao de memria alocado para ela, ocupando a parte final e liberando a parte frontal. Aps algumas inseres e remoes, a fila chega ao limite final do espao de memria, dando a falsa impresso de que no existe mais espao disponvel. Portanto, uma soluo para isso, seria utilizar uma alocao circular para o vetor que armazena os elementos da fila, conforme a figura 10.

Figura 10 - Representao de fila utilizando lista circular

Para implantarmos o mecanismo de filas circulares em alocao esttica recorreremos propriedade do resto da diviso entre dois nmeros. Se dividirmos 1 por 9 o resto da diviso 1. Ou seja, o prprio nmero 1. O mesmo acontece com 2, 3, 4... at o nmero 9 que possui como resto o nmero 0. Desta forma, podemos ter um mecanismo de saber sempre a prxima posio da fila atravs da funo mod da linguagem pascal atravs da frmula: Prximo = (Fim mod Mximo) + 1 De acordo com o exemplo apresentado anteriormente, teramos: Prox = (1 mod 9) + 1 Prox = (2 mod 9) + 1 Prox = (3 mod 9) + 1 ............ Prox = (9 mod 9) + 1 =1+1=2 =2+1=3 =3+1=4 =0+1=1

Note que quando chegou na ltima posio (9), a seguinte automaticamente retornou para a posio 1 do vetor, j que 9 mod 9 ter como resultado zero. Com isso, conseguimos o objetivo que queramos ter com a fila circular. Porm, ainda temos um problema: no existe distino da configurao de FILA VAZIA do caso de FILA CHEIA; em ambos, o incio e o fim indicam a mesma posio. Uma soluo para isso deixar uma posio vazia para marcar o incio/fim da fila no crculo, perdendo uma posio da memria, mas ganhando em agilidade (SAIBEL, 2006). Assim teremos: O teste de fila cheia Se INCIO + 1 = FIM ento Fila Cheia O teste de fila vazia continua como antes: Se INCIO = FIM ento Fila Vazia Agora, vamos deixar os exemplos de lado e partir para o cdigo! O que acha? J estava ansioso para isso, no ? Ento, vamos l!

Que tal agora voc seguir passo a passo o programa e desenhar toda a insero e remoo? um excelente exerccio! Note que a quantidade mxima da fila trs. Ento, voc conseguir fazer com que o indicador de incio e fim circule a lista facilmente. E melhor ainda, o que acha de implementar o procedimento que imprime a fila inteira? Vamos l! Tente, pois aps esse exerccio voc estudar a implementao de filas com ponteiros!

Filas encadeadas
Conforme j mencionado, filas so listas lineares, e de maneira similar aos casos estudados anteriormente, podem ser implementadas atravs de ponteiros. E, de acordo com os estudos feitos sobre listas encadeadas, novamente usamos do artifcio da adio de um n chamado n cabea. Ele mantido na frente da fila para evitar alguns testes desnecessrios nas operaes com a fila quando ela est vazia. Alm disso, com ele, os algoritmos de insero/remoo so os mesmos, seja qual for a posio de insero/remoo. Vamos ver que o tipo criado T_Fila consiste de dois ponteiros, inicio e fim, que apontam para a mesma posio caso a fila esteja vazia. Para facilitar ainda mais, o campo tamanho definido no registro T_Fila facilita a obteno do tamanho da pilha, sem que seja necessrio que a mesma seja percorrida. Vamos ver, ento, como fica o TAD para fila encadeada.

type T_Ponteiro = ^T_No; T_No = record info: string; prox: T_Ponteiro; end; T_Fila = record inicio, fim: T_Ponteiro; tamanho: integer; end; var fila: T_Fila;

Note que, assim como nas pilhas, aqui cada n deve conter um item da fila e um "campo extra" para a um ponteiro para outro n da fila. Veja tambm que o registro T_Fila contm um ponteiro para o incio da fila (n cabea) e um ponteiro para o final da fila (ZIVIANI, 2005). Agora, j podemos analisar um cdigo completo com manipulao de filas encadeadas. Vamos ver o cdigo a seguir.

O cdigo apresentado fornece um exemplo de como implementar fila encadeada, utilizando tipos abstratos de dados e algumas sub-rotinas essenciais, como: iniciar uma fila, verificar se uma fila est vazia, esvaziar completamente

uma fila, enfileirar e desenfileirar elementos e por ltimo imprimir todos os elementos da fila obedecendo a ordem. Com isso, finalizamos mais uma aula do nosso plano de ensino.

SNTESE
O objetivo desta aula foi apresentar a voc dois novos tipos de listas, os quais possuem uma disciplina de acesso: pilha e fila. Vimos aqui como so definidas as regras para acessar, inserir e remover elementos nessas listas, que so LIFO e FIFO. Alm disso, vimos como implementar pilhas e filas com vetores e tambm com ponteiros. Na prxima e penltima aula iremos iniciar os estudos sobre rvores. Esse um assunto bem importante para desenvolvimento de programas. Espero que tenha gostado bastante dessa aula e que esteja ansioso para prxima. At mais!

QUESTO PARA REFLEXO


Ao longo da nossa aula deixamos algumas atividades para que pudessem exercitar o conhecimento obtido nela. Se ainda no fez, essa a hora. Vamos l! Aproveite!

LEITURAS INDICADAS
Captulo 5 de LORENZI, Fabiana; MATTOS, Patrcia N.; CARVALHO, Tanisi P. Estruturas de dados. So Paulo: Thomson Learning, 2007. 175 p. Seo 3.2 e 3.3 de ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

REFERNCIAS
LORENZI, Fabiana; MATTOS, Patrcia N.; CARVALHO, Tanisi P. Estruturas de dados. So Paulo: Thomson Learning, 2007. 175 p. SAIBEL, Celso. Estruturas do tipo fila. Apresentao de aula da disciplina Estrutura de Dados do Mestrado em Sistemas e Computao da UNIFACS. Salvador, 2006. SAIBEL, Celso. Estruturas do tipo pilha. Apresentao de aula da disciplina Estrutura de Dados do Mestrado em Sistemas e Computao da UNIFACS. Salvador, 2006. ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

Exerccios de Estrutura de Dados - Aula 6


Professor: Artur Henrique Kronbauer Observao: Cada exerccio proposto deve ser resolvido primeiramente utilizando estrutura esttica e posteriormente utilizando estrutura dinmica. 1. Escreva um programa que possa gerar nmeros aleatrios e distribui-los em duas filas. As filas dos pares e a fila dos mpares. A gerao de nmeros aleatrios deve acabar quando for gerado um nmero primo ou quando ambas as filas estiverem cheias. Posteriormente retire de forma intercalada os elementos das filas e mostre na tela.

2. Escreva um programa que tenha funcionalidades para cadastrar elementos em duas filas diferentes e que permita remover os elementos das filas e identificar os elementos iguais que estavam na mesma posio em ambas as filas.

3. Desenvolva um programa que manipule uma pilha e possa fazer consultas a elementos nessa pilha usando o critrio de pilha sem que os elementos consultados sejam perdidos, para isso, use uma pilha auxiliar, guardando os elementos consultados e no final da consulta passe todos os elementos da pilha auxiliar para a pilha original.

4. Escreva um programa com rotinas para colocar elementos em uma pilha e posteriormente desempilhar os elementos e os coloque em uma fila. No final mostre a fila na tela.

AULA 7 - RVORES
Autor: Fbio Rezende Lucas

Ol, pessoal! Estamos iniciando a nossa penltima aula e nosso ltimo assunto, que ser visto nesta e na prxima aula. Nelas, vamos definir os conceitos bsicos de rvores com suas definies e estudaremos um tipo de rvore em particular, a rvore binria. Aprenderemos como inserir ou remover dados em uma rvore e como caminhar entre seus ns. Aprenderemos ainda, como esta estrutura pode ser til na ordenao de dados e quais suas vantagens sobre as estruturas estudadas anteriormente, como as listas. Mas, voc deve estar se perguntando o que uma rvore? Qual a forma desta estrutura e por que este nome? Vamos comear, ento, o nosso estudo!

RVORES
Por definio, uma sequncia, ou lista, pode ser considerada uma rvore na qual cada n possui apenas uma nica subrvore. Sendo assim, uma lista pode ser chamada tambm de rvore degenerada, ilustrada na figura 1.

Figura 1 - Lista representada como uma rvore degenerada

Observe que na figura acima, cada n est ligado somente uma subrvore, apresentando um crescimento unilateral. Por isso dizemos que essa estrutura uma rvore degenerada. Mas, como podemos representar uma rvore? Voc j est pensando como deve ser? Seria como uma rvore propriamente dita, com raiz, ramificaes, folhas etc? Como uma rvore pode possuir sub-rvores? Vamos ento comear a estud-las, partindo do princpio que uma rvore uma estrutura abstrata que teremos que represent-la. Se voc fizer um estudo em diversas bibliografias, ver que so diversas as formas possveis de representar uma estrutura de rvore. Porm, a adotada por unanimidade aquela que mais se assemelha a uma rvore propriamente dita. Vejamos essa representao na figura 2.

Figura2 - Representao clssica de uma rvore

Nessa representao, a rvore uma estrutura hierrquica onde cada crculo da figura representa um n, e deles derivam sub-rvores. Agora ficou lgico como um n pode possuir sub-rvores, no ? Ao n que se encontra no topo da rvore, denominamos de raiz. Note que, comparando com uma rvore no mundo real, essa representao est invertida. Sendo assim, o n raiz o "A" e os ns folhas so os ns "D", "E", "F", "G" e "H". Um exemplo de utilizao de rvores para representar um determinado problema pode ser apresentado na forma da figura 3. Voc consegue visualizar para que est sendo utilizada? Se conseguiu, excelente! Mas, se no conseguiu, no tem problema, estamos ainda no incio da nossa aula e voc ver como simples. A figura 3 faz a representao da seguinte expresso aritmtica: (a + (b *( (c / d) - e))).

Figura3 - Representao de expresso aritmtica com rvore

Depois de vermos a representao, dizemos que a grande motivao para estudarmos rvores que diversas aplicaes necessitam de estruturas mais complexas que as listas estudadas at agora. Sendo que, nas rvores, os ns podem definir uma ordenao implcita. Alm disso, existem algoritmos eficientes para o tratamento de rvores quando comparadas s estruturas mais genricas,

como os grafos. Estes so muito mais flexveis e complexos e no entraro no escopo da nossa disciplina. At agora exemplificamos, de uma forma geral, o que uma rvore, seus componentes e sua representao. Vamos ver agora as suas definies.

Definio
Segundo Saibel (2006), uma rvore T um conjunto finito de elementos denominados ns ou vrtices tais que:
T = 0 a rvore dita vazia ou Existe um n r, chamado raiz de T; os ns restantes constituem um nico conjunto vazio ou so divididos em m 1 conjuntos distintos no vazios que so as sub-rvores de r, cada sub-rvore a qual , por sua vez, uma rvore.

Para visualizarmos melhor as prximas definies, vamos considerar a rvore da figura 4.

Figura 4 - Exemplo de rvore

Dizemos que a notao para uma sub-rvore : Tv, se v um n de T. Assim, Tv indica a sub-rvore de T com raiz em v. Seja a rvore da figura 4, T = {A, B, C, D, E, F, G, H, I}, dizemos que ela possui duas sub-rvores: Tb e Tc, em que: Tb = {B} e Tc = {C, D, E, F, G, H, I} J a sub-rvore Tc possui 3 sub-rvores: Td , Te e Tf, em que:

Td = {D, G, H} Te = {E} Tf = {F, I} Note que as sub-rvores Tb, Te, Tg, Th e Ti possuem apenas o n raiz e nenhuma sub-rvore. Vamos ver agora outras definies acerca de rvores, considerando v o n raiz da sub-rvore Tv de T. Dessa maneira, teremos:

Ns filhos
Os ns w1, w2, ... wj razes das sub-rvores de Tv so chamados filhos de v. De acordo com a figura 4, os ns B e C so filhos de A. Assim como, os ns D, E e F so filho de C.

Pais, tios, irmos e av


O n v chamado pai de w1, w2, ... wj. Assim, os ns w1, w2, ... wj so irmos. E, se z filho de w1, ento w2 tio de z e v av de z. Conforme a rvore da figura 4, teremos que o n C pai dos ns D e E e F. Assim, os ns D, E e F so irmos, o n A av deles e o n B tio deles.

N descendente e ancestral
Se x pertence sub-rvore Tv, ento, x descendente de v e v ancestral, ou antecessor, de x. Dessa forma, para a representao da figura 4, temos que o n G descendente do n D e o mesmo ancestral do n G.

Grau de sada
O grau de sada significa o nmero de filhos de um determinado n. Tratando-se do exemplo da figura 4, temos o seguinte:
G(A): 2 G(B): 0 G(C): 3 G(D): 2 G(E): 0 G(F): 1 G(G): 0 G(H): 0 G(I): 0

N folha
N que no possui descendente, ou seja, um n folha aquele com grau de sada nulo. Analisando a figura 4 e os exemplos vistos para grau de sada, podemos afirmar que os ns B, E, G, H e I so ns folhas.

N interior ou interno
Diferentemente do n folha, as rvores possuem esse tipo de n que aquele que tem um grau de sada diferente de zero. Dessa maneira, para o exemplo da figura 4 e os graus j apresentados, os ns internos dessa rvore so A, C, D e F.

Grau de uma rvore


Refere-se ao valor mximo entre os graus de seus ns. Logo, podemos dizer que a rvore da figura 4 tem grau 3, pois o n C possui o maior grau que justamente esse valor.

Floresta
um conjunto de zero ou mais rvores disjuntas. De acordo com a figura 5, temos um exemplo de uma floresta com duas rvores disjuntas.

Figura 5 - Exemplo de floresta com duas rvores

Caminho na rvore
Sequncia de ns distintos v1, v2, ..., vk, tal que sempre existe a relao " filho de" ou " pai deentre ns consecutivos (isto , entre v1 e v2, entre v2 e v3, ..., v(k-1) e vk). De acordo com a figura 4, podemos traar, por exemplo, os caminhos:
C1: C2: C3: C4: A, A, A, A, C, D, G; B; C, F, I; C, E.

Comprimento do caminho
Um caminho que passa por vk vrtices obtido pela sequncia de k-1 pares. O valor k-1 o comprimento do caminho. No exemplo citado anteriormente para caminho em rvore teramos os seguintes comprimentos:
C(C1): C(C2): C(C3): C(C4): 3; 1; 3; 2.

Nvel ou profundidade de um n
O nvel ou profundidade de um determinado n o nmero de ns do caminho da raiz at o n, sendo que a raiz tem nvel 0. Assim, de acordo com a figura 4, o n F tem nvel 2.

Altura de um n
A altura de um n v determinada pelo nmero de ns no maior caminho de v at um de seus descendentes, sendo que as folhas tm altura igual a 1. Dessa forma, o n C da rvore apresentada na figura 4 tem altura igual a 3.

Altura de uma rvore


A altura de uma rvore T, ou h(T), calculada como sendo o comprimento do caminho mais longo da raiz at uma das folhas. Por definio, a altura de uma rvore que possui somente um n zero. Logo, a altura da rvore apresentada na figura 4 igual a 4.

rvore Ordenada
Uma rvore dita ordenada quando os filhos de cada n esto ordenados de acordo com alguma regra. Alm disso, assume-se que a ordenao feita da esquerda para a direita. A figura 6 ilustra exemplos de rvores ordenada e desordenada.

Figura 6 - Exemplos de rvores ordenada e desordenada

rvore Cheia
Uma rvore de grau z uma rvore cheia se possui o nmero mximo de ns, isto , todos os ns tm nmero mximo de filhos exceto as folhas. Alm disso, todas as folhas devem estar na mesma altura. A figura 7 exibe um

exemplo de rvore cheia de grau 2. Observe que a raiz e os ns internos possuem grau 2 e os ns folhas esto na mesma altura.

Figura 6 - Exemplo de rvore cheia

Agora, terminamos de ver as definies referentes arvore. Voc j imaginou como programar utilizando essas estruturas? J imaginou como seria o TAD e a manipulao? Toda a programao depende de termos os conceitos bem fixados. Ento, essa aula que termina por aqui, mostrou todos os conceitos sobre essa estrutura.

SNTESE
Nessa aula vimos todas as definies de rvores como sua representao, como calcular a altura de um n, da rvore inteira, quando temos uma rvore cheia, ordenada etc. At aqui, o que vimos foi puramente conceituais. Na prxima aula veremos como definir o TAD para rvore, como cri-la, inserir e remover ns, alm de percorrer os ns de vrias maneiras. At mais!

QUESTO PARA REFLEXO


Para a rvore a seguir, que tal utiliz-la e tentar empregar todos os conceitos apresentados nesta aula? Vamos praticar e fixar os conceitos. Em caso de dvida, v ao frum da disciplina e discutir com os colegas, tutor e professor.

LEITURAS INDICADAS
Seo 5.3 de ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

SITES INDICADOS
PIMENTEL, Graa. rvore. Disponvel em: <http://www.icmc.usp.br/~sce182/arvore.html>. Acesso em: 25 mai. 2010.

REFERNCIAS
PIMENTEL, Graa. rvore. Disponvel em: <http://www.icmc.usp.br/~sce182/arvore.html>. Acesso em: 25 mai. 2010. SAIBEL, Celso. rvore. Apresentao de aula da disciplina Estrutura de Dados do Mestrado em Sistemas e Computao da UNIFACS. Salvador, 2006. ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

Exerccios de Estrutura de Dados - Aula 7


Professor: Artur Henrique Kronbauer Observao: Para responder os exerccios abaixo leia o material das Aulas 7 e 8.

1. Dada a seguinte rvore, responda os itens abaixo:

a) b) c) d) e) f) g) h) i) j)

Qual o n raiz? Quais so os ns folhas? Quais so os ns internos da rvore? Qual o grau de cada um dos ns? Qual o nvel de cada um dos ns? Qual a ordem dos elementos para um percurso em pr-ordem? Qual a ordem dos elementos para um percurso em ordem? Qual a ordem dos elementos para um percurso em ps-ordem? Qual o comprimento do caminho entre os ns 6 e 5? A rvore apresentada uma rvore Cheia ou Completa?

AULA 8 - RVORE BINRIA


Autor: Fbio Rezende Lucas

Oi! Vamos estudar a nossa ltima aula? Pois , estamos chegando ao final da disciplina. E para fecharmos com "chave de ouro", vamos aprender a desenvolver programas utilizando estruturas de rvores binrias. Na aula passada vimos os conceitos gerais de rvores. Ento, nada melhor do que praticar agora, no ? Vamos comear!

RVORE BINRIA
Assim como as listas lineares, estruturas de dados do tipo rvore podem ser implementadas atravs de arranjos (vetores) ou atravs de ponteiros. Veremos aqui como implement-las com ponteiros devido a sua grande importncia. Antes de entrarmos na implementao propriamente dita, vamos definir o tipo de rvore que vamos trabalhar. O primeiro e mais importante conceito o que diz que uma rvore binria T um conjunto finito de elementos denominados ns ou vrtices, tal que:
T = 0 a rvore dita vazia. Existe um n r, chamado raiz de T, e os ns restantes podem ser divididos em dois subconjuntos disjuntos, Tre e Trd, que so as sub-rvores esquerda e direita de r, respectivamente e as quais, por sua vez, tambm so rvores binrias.

Com isso, podemos concluir que as rvores binrias possuem um nmero constante de sub-rvores em cada n. Alm disso, os ns possuem uma ordenao implcita, devido a sua organizao. A forma de armazenar os ns surge naturalmente de sua definio, sendo que:
ponteiros para os filhos: esq e dir ponteiro para o n raiz (como nas listas lineares) necessita de 2n+1 ponteiros para representar n ns

De acordo com esses conceitos, podemos dizer tambm que, com as rvores binrias, existe limitao do nmero de ponteiros usados, visto que para n ns precisamos da quantidade expressada acima. Sendo assim, a representao de uma rvore binria pode ter o formato apontado na figura 1.

Figura 1 - Representao de rvore binria com ponteiros.

Note que no topo do desenho temos o n raiz e nesse n existem apontadores para dois outros ns: a sub-rvore da esquerda e a da direita. Dessa forma, como se trata de rvore binria, nenhum n pode ter mais do que duas sub-rvores, indicadas por esses ponteiros. Ainda para a figura 1, se contabilizarmos o nmero de ns que igual a 9 e aplicarmos a frmula apresentada anteriormente para sabermos o nmero de ponteiros, teramos:

P = 2n + 1

P=2x9+1

P = 19

Logo, a rvore utiliza 19 ponteiros, sendo 1 para o n raiz e 18 para os filhos. Vamos ver agora, como representar uma rvore binria em Pascal? Voc j pensou como ser o TAD para ela? Ainda no? Pelos conceitos que j vimos de listas encadeadas, tente imaginar como a estrutura da rvore. J imaginou? Ento confira no trecho de cdigo a seguir.

type T_Ponteiro = ^T_No; T_No = record info: integer; esq, dir: T_Ponteiro; end; T_Arvore = T_Ponteiro;

Agora que voc j conhece a estrutura de uma rvore binria em Pascal, vamos ver as operaes que podemos realizar sobre elas. Daqui em diante veremos trechos de cdigos e explicaes sobre as diversas rotinas de manipulao de rvore binria. Vamos comear pela inicializao!

Inicializar
Esta rotina tem como objetivo iniciar uma rvore, passada como parmetro, colocando-a como nula. Segue abaixo o cdigo deste procedimento.

Criar n raiz
Procedimento que, como o prprio nome diz, utilizado para criar o primeiro n da rvore: o n raiz. Recebe uma rvore e o item a ser inserido para criar o n e configurar seus apontadores para sub-rvores da direita e da esquerda como nulo. O cdigo a seguir mostra a implementao desta rotina.

Vazia
Essa funo recebe uma rvore como parmetro e retorna verdadeiro se ela estiver vazia, caso contrrio retorna falso. Veja o seu cdigo a seguir.

Inserir filho a esquerda


Procedimento que recebe a informao a ser inserida e o n que ser o pai do n criado. Seu objetivo inserir o elemento na rvore a esquerda do n pai se ele no possui um filho esquerda. Vamos ver sua implementao no cdigo a seguir.

Inserir filho a direita


Procedimento que recebe a informao a ser inserida e o n que ser o pai do n criado. Seu objetivo inserir o elemento na rvore a direita do n pai se ele no possui um filho direita. O cdigo a seguir refere-se a este procedimento.

Esvaziar
Recebe como parmetro a rvore e libera todo o espao de memria alocado por ela, tornando-a vazia. Trata-se de um cdigo recursivo que invocado tanto para o n esquerda quanto direita. Vamos analisar o cdigo abaixo.

Vimos at aqui algumas operaes bsicas. Mas, ainda temos outras operaes que so muito importantes quando trabalhamos com rvores. Uma dessas a forma como percorremos os ns da rvore. Vamos ver como fazemos essas operaes?

Percursos em rvores
O percurso em uma rvore se d visitando cada n uma nica vez, gerando uma sequncia linear de ns. Assim, passa a ter sentido falar em sucessor e predecessor de um n, segundo um determinado percurso. Existem trs maneiras recursivas de se percorrer rvores binrias:
Percurso em pr-ordem Percurso em ordem Percurso em ps-ordem

Vamos estudar cada um desses percursos, analisando os passos de cada um e o cdigo deles. Para isso, utilizaremos a rvore representada pela figura 2 a seguir.

Figura 2 - Exemplo rvore binria

Percurso em pr-ordem
O algoritmo para percorrer uma rvore em pr-ordem baseado nos seguintes passos:
Se rvore vazia fim visitar o n raiz percorrer em pr-ordem a sub-rvore esquerda percorrer em pr-ordem a sub-rvore direita

Dessa maneira, analisando a figura 2 qual ser a sequncia de ns que o percurso em pr-ordem far? Ainda no sabe? No tem problema. A sequncia que seria apresentada pelo algoritmo seria a seguinte: ABDCEGFHI Veja agora o cdigo em Pascal para percorrer uma rvore em pr-ordem. Note que o procedimento recebe a rvore como parmetro, analisa se a mesma est vazia e caso no esteja ele processa os ns. Verifique que o algoritmo aqui apresentado recursivo, pois as chamadas ao procedimento so feitas para cada filho esquerda e direita dos ns.

Percurso em ordem
O algoritmo para percorrer uma rvore em ordem baseado nos seguintes passos:
Se rvore vazia fim percorrer em ordem a sub-rvore esquerda visitar o n raiz percorrer em ordem a sub-rvore direita

Dessa maneira, analisando a figura 2 qual ser a sequncia de ns que o percurso em ordem far? Voc j saberia responder? Ento confira sua resposta com a sequncia apresentada a seguir: DBAEGCHFI Vamos ver agora o algoritmo em Pascal para o percurso de uma rvore em ordem. Igualmente ao percurso em pr-ordem, o procedimento recebe a rvore como parmetro, analisa se a mesma est vazia e caso no esteja ele processa

os ns. Veja tambm que o algoritmo recursivo e s alteramos o local que visitamos o n em questo.

Percurso em ps-ordem
O algoritmo para percorrer uma rvore em ps-ordem baseado nos seguintes passos:
Se rvore vazia fim percorrer em ordem a sub-rvore esquerda percorrer em ordem a sub-rvore direita visitar o n raiz

Analisando novamente a figura 2, qual ser a sequncia de ns que o percurso em ps-ordem far? Vamos conferir com a sequncia abaixo: DBGEHIFCA Como nos outros percursos, vamos ver em Pascal como feita a sequncia em ps-ordem. Igualmente aos anteriores, o procedimento recebe a rvore como parmetro, analisa se a mesma est vazia e caso no esteja ele processa os ns. Mais uma vez temos um algoritmo recursivo, porm a visita ao n feita por ltimo.

Agora que vimos os conceitos de rvores e a implementao de algumas operaes bsicas em Pascal, podemos finalizar nossa ltima aula. Espero que tenha gostado de praticar a programao com rvores. Caso se interesse mais nessas estruturas, existem outros tipos de rvores, com implementaes mais complexas como rvores: B, B*, Rubro-Negras, Trie e Patrcias. Todas essas estruturas podem ser encontradas em Ziviani (2005).

SNTESE
Nesta aula apresentamos como implementar em Pascal algoritmos para manipulao de rvores binrias. Vimos como definir a estrutura delas, como cri-las, inserir elementos esquerda e direita e como percorrer seus elementos de trs formas diferentes. Com isso, terminamos aqui os assuntos, finalizando a nossa disciplina! Espero voc no prximo semestre com novidades!

QUESTO PARA REFLEXO


Voc j est craque na programao com rvores binrias? Que tal implementar algoritmos para informar qual o nvel de um determinado n e outro para realizar a remoo de um n? Vamos praticar!

LEITURAS INDICADAS
Captulos 5 e 6 de ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

SITES INDICADOS
PIMENTEL, Graa. rvore. Disponvel em: <http://www.icmc.usp.br/~sce182/arvore.html>. Acesso em: 25 mai. 2010.

REFERNCIAS
PIMENTEL, Graa. rvore. Disponvel em: <http://www.icmc.usp.br/~sce182/arvore.html>. Acesso em: 25 mai. 2010. SAIBEL, Celso. rvore. Apresentao de aula da disciplina Estrutura de Dados do Mestrado em Sistemas e Computao da UNIFACS. Salvador, 2006. ZIVIANI, Nivio. Projeto de algoritmos: com implementaes em Pascal e C. 2. ed. So Paulo: Thomson, 2005. 552 p.

Exerccios de Estrutura de Dados - Aula 8


Professor: Artur Henrique Kronbauer Obs: Para resolver os exerccios abaixo, considere que os elementos devem ser inseridos na rvore de acordo com o valor de suas chaves, onde os elementos menores que o seu antecessor devem ficar a esquerda e os maiores do que o seu antecessor devem ficar a direita. Por exemplo, se tivermos as chaves 5, 10, 3, 15, 12, os passos de insero sero os apresentados abaixo: Passo 1 5 Passo 2 5

10

Passo 3 -

Passo 4 -

10

10

15

Passo 5 -

10

12

15

1. Desenhe uma rvore Binria contemplando as regras de insero apresentadas anteriormente de acordo com as seguintes chaves: 20, 25, 13, 17, 12, 9, 40, 42, 26, 47, 48, 49, 18, 10, 11, 6, 7, 21, 24, 27, 4, 3, 2, 32, 46, 8.

2. Escreva um programa capaz de criar uma rvore binria e imprimir todos os ns "ancestrais" de um certo n dessa rvore. Dica: Desenvolva um menu com as seguinte funcionalidades: 1 Inserir um elemento 2 Pesquisar um elemento 3 Escrever os dados em Pr-ordem 4 Escrever os dados em Ordem 5 Escrever os dados em Ps-ordem 6 Mostrar os ancestrais 7 Fim Exemplo: Considerando a rvore ao lado, os ancestrais do nmero 5 seriam 4 e 6.

3. Escreva um programa capaz de criar uma rvore binria, percorrer essa rvore e imprimir o grau e o nvel de cada um dos ns que compem a rvore. Dica: Desenvolva um menu com as seguinte funcionalidades: 1 Inserir um elemento 2 Pesquisar um elemento 3 Escrever os dados em Pr-ordem 4 Escrever os dados em Ordem 5 Escrever os dados em Ps-ordem 6 Mostrar Grau e nvel 7 Fim Exemplo: Considerando a rvore abaixo, o resultado do programa deve ser: N = 2 Grau = 0 Nvel = 2 N = 4 Grau = 2 Nvel = 1 N = 5 Grau = 0 Nvel = 2 N = 6 Grau = 2 Nvel = 0 N = 8 Grau = 1 Nvel = 1 N = 10 Grau = 0 Nvel = 2

4. Escreva um programa capaz de criar uma rvore binria de pesquisa e com apenas um percurso obter a impresso dos ns em ordem decrescente. Dica: Desenvolva um menu com as seguinte funcionalidades: 1 Inserir um elemento 2 Pesquisar um elemento 3 Escrever os dados em Pr-ordem 4 Escrever os dados em Ordem 5 Escrever os dados em Ps-ordem 6 Mostrar em ordem decrescente 7 Fim Exemplo: Considerando a rvore abaixo, o resultado do programa deve ser: 10 8 6 5 4 2