Sie sind auf Seite 1von 110

Mariela Ins Corts Enyo Jos Tavares Gonsalves

Estrutura de Dados

2 Edio 2012

Copyright 2010. Todos os direitos reservados desta edio SECRETARIA DE EDUCAO A DISTNCIA (SEAD/UECE). Nenhuma parte deste material poder ser reproduzida, transmitida e gravada, por qualquer meio eletrnico, por fotocpia e outros, sem a prvia autorizao, por escrito, dos autores. EXPEDIENTE Design instrucional Antonio Germano Magalhes Junior Igor Lima Rodrigues Pedro Luiz Furquim Jeangros Projeto grfico Rafael Straus Timb Vasconcelos Marcos Paulo Rodrigues Nobre Coordenador Editorial Rafael Straus Timb Vasconcelos Diagramao Marcus Lafaiete da Silva Melo Francisco Jos da Silva Saraiva Ilustrao Marcos Paulo Rodrigues Nobre Capa Emilson Pamplona Rodrigues de Castro

PRESIDENTE DA REPBLICA Luiz Incio Lula da Silva MINISTRO DA EDUCAO Fernando Haddad SECRETRIO DE EDUCAO A DISTNCIA Carlos Eduardo Bielschowsky DIRETOR DO DEPARTAMENTO DE POLTICAS EM EDUCAO A DISTNCIA DPEAD Hlio Chaves Filho SISTEMA UNIVERSIDADE ABERTA DO BRASIL Celso Costa GOVERNADOR DO ESTADO DO CEAR Cid Ferreira Gomes REITOR DA UNIVERSIDADE ESTADUAL DO CEAR Francisco de Assis Moura Araripe VICE-REITOR Antnio de Oliveira Gomes Neto PR-REITORA DE GRADUAO Josefa Lineuda da Costa Murta COORDENADOR DA SECRETARIA DE EDUCAO A DISTNCIA Antonio Germano Magalhes Junior COORDENADOR GERAL UAB/UECE Francisco Fbio Castelo Branco COORDENADORA ADJUNTA UAB/UECE Josete de Oliveira Castelo Branco Sales COORDENADOR DA LICENCIATURA EM INFORMTICA Joaquim Celestino Junior COORDENADOR DE TUTORIA E DOCNCIA DA LICENCIATURA EM INFORMTICA Jorge Lus de Castro e Silva

Apresentao........................................................................................................................ 7

Sumrio

Unidade 1 Introduo Complexidade de Algoritmos............................................................................ 9 Captulo 1 - Introduo....................................................................................................... 11


O que anlise de algoritmos?.............................................................................................. 12

Captulo 2 - Medidas de Complexidade.............................................................................. 14


Comparao entre algoritmos...............................................................................................16

Unidade 2 Representao dos Dados...................................................................................................... 25 Captulo 1 - Modelagem Conceitual.................................................................................... 27


Tipo de dados ........................................................................................................................27 Tipo abstratos de dados.........................................................................................................30 Critrios para a escolha da estrutura de dados adequada.....................................................32

Unidade 3 Listas..................................................................................................................................... 37 Captulo 1 - Listas................................................................................................................ 39


Introduo..............................................................................................................................39 Definio do TAD Lista............................................................................................................39
Implementao do TAD Lista usando alocao esttica ................................................................ 40 Implementao do TAD Lista usando alocao dinmica .............................................................. 46 Variaes sobre o TAD Lista............................................................................................................ 53

Captulo 2 - Pilhas ............................................................................................................... 55


Implementaes do TAD Pilha usando vetores...................................................................... 56 Implementao do TAD Pilha usando ponteiros.................................................................... 59

Captulo 3 - Filas.................................................................................................................. 63
Implementao do TAD Fila usando vetores.......................................................................... 64 Implementao do TAD Fila usando ponteiros...................................................................... 67

Unidade 4 rvores ................................................................................................................................. 73 Captulo 1 - rvores............................................................................................................ 75


rvore binria .......................................................................................................................76

Captulo 2 - rvore binria de busca................................................................................... 79


Definio do TAD rvore Binria de Busca ............................................................................ 79 Implementao do TAD rvore Binria de Busca .................................................................. 80

Ordens de percurso em rvores binrias....................................................................................... 85 Relao entre o nmero de ns de uma rvore binria e sua altura......................................................................................................................... 87

Captulo 3 - rvores AVL...................................................................................................... 89 Unidade 5 Busca avanada .................................................................................................................... 97 Captulo 1 - Tabela de disperso......................................................................................... 99
A funo de disperso............................................................................................................100 Estratgias para resoluo de colises................................................................................... 102
Encadeamento .............................................................................................................................. 102 Tcnicas de sondagem.................................................................................................................... 103

Captulo 2 - Busca digital..................................................................................................... 105


rvore digital.........................................................................................................................106

Captulo 3 - Estruturas autoajustveis................................................................................ 108


Listas autoajustveis..............................................................................................................108

Dados dos Autores................................................................................................................ 110

O constante aumento da complexidade dos sistemas e suas demandas computacionais relacionadas a tempo e espao, impem o desafo de projetar solues algortmicas cada vez mais eficientes. Neste contexto, as estruturas de dados e seus algoritmos tm um papel fundamental uma vez que constituem os blocos construtores utilizados na resoluo dos mais diversos problemas em todas as areas da computao. O objetivo do presente livro apresentar de forma clara e amigvel diferentes estruturas de dados e seus algoritmos de manipulao, analisando a estratgia mais eficiente para a sua implementao, em termos de complexidade. Esta anlise envolve a utilizao de tcnicas de projeto associadas a tcnicas de programao, as quais so adequadas s caracteristicas da aplicao especfica. O livro est organizado em cinco unidades. As primeiras fornecem as bases necessrias para a anlise e o projeto de uma boa soluo algortmica incluindo conceitos bsicos sobre complexidade, tipos e estruturas de dados. A Unidade 3 apresenta o conceito central de Listas, a partir do qual duas importantes e amplamente utilizadas estruturas so derivadas: Pilhas e Filas. A Unidade 4 apresenta a estrutura de rvore, sua conceituao, implementao e algoritmos de manipulao bsicos. Mais especificamente, nesta unidade so explo radas as rvores Binrias de Busca analizando suas caractersticas e as implicaes em relao eficincia. Neste contexto, a fundamentao e funcionamento das rvores balanceadas (AVL) so apresentados. Finalmente, na Unidade 5 so descritas as tcnicas avanadas de pesquisa aplicadas sobre estruturas de dados especficas, tais como tabelas de disperso, busca digital e estruturas autoajustveis. O contedo apresentado destina-se principalmente para professores e alunos de graduao em Cincias da Computao ou reas afins, fornecendo um embassamento terico e uma clara noo das estratgias a serem seguidas na implementao dos algoritmos para a manipulao eficiente das estruturas de dados mais amplamente utilizadas. Os autores

Unidade

Introduo Complexidade de Algoritmos


Objetivos:
Nesta unidade introduzido o conceito de complexidade de algoritmos. Este conceito central na Cincia da Computao, uma vez que possibilita avaliar e comparar solues algortmicas, fornecendo os insumos necessrios para determinar qual o algoritmo mais adequado para resolver determinada classe de problemas.

Captulo 1
Introduo

Um algoritmo determina um conjunto de regras no ambguas as quais especificam, para cada entrada, uma seqncia finita de operaes, gerando como resultado uma sada. O algoritmo representa uma soluo para um problema se, para cada entrada, gera uma resposta correta, sempre que dispor de tempo e memria suficientes. Um algoritmo pode ser implementado atravs de diferentes programas. Ou seja, diferentes implementaes podem ser propostas a partir de um nico algoritmo. Esta situao nos coloca na dificuldade de escolher qual a melhor soluo para o problema especfico. Assim sendo, apenas resolver o problema parece no ser suficiente uma vez que diferentes solues podem ser idealizadas a partir de algoritmos, para a resoluo de um nico problema. Neste contexto, se torna necessrio um mecanismo que permita determinar se uma soluo melhor do que uma outra, de forma a fornecer uma ferramenta de apoio decio em relao qualidade das solues propostas. De forma geral, a qualidade de um programa depende do ponto de vista. Por um lado, o usurio determina a qualidade de um programa atravs de critrios, tais como: Facilidade de uso e entendibilidade da interface do programa levando em conta diferentes nveis de experincia. Compatibilidade do programa com outros programas ou verses de programas, de forma a facilitar a troca de informao com outros sistemas existentes. Desempenho, em relao velocidade de execuo e tempo de resposta. Quantidade de memria utilizada pelo programa durante a sua execuo, aspecto que pode se tornar um fator limitante. Os ltimos dois itens esto diretamente ligados quantidade de dados a serem processados, ou seja, ao tamanho da entrada. Por outro lado, critrios que podem ser determinantes desde o ponto de vista da organizao desenvolvedora incluem: Portabilidade do cdigo entre diferentes plataformas. Documentao e padronizao do cdigo. Facilidade de evoluo e manuteno. Reusabilidade do cdigo, permitindo que pores de um programa sejam reaproveitadas para desenvolver outros produtos, aumentando a produtividade.

Programa codifica um algoritmo para ser executado no computador resolvendo um problema. fundamental que o programa produza a soluo com dispndio de tempo e memria: Importncia de Projeto e Analise de Algoritmos.

ESTRUTURA DE DADOS

11

A correta avaliao destes critrios influenciada por diversos fatores, tais como: caractersticas do hardware, sistema operacional, linguagens e compiladores, plataforma, etc. Estes fatores so considerados acidentais uma vez que no esto diretamente relacionados qualidade da soluo. Em contrapartida, os fatores essenciais so inerentes soluo e determinantes para a sua qualidade. O tempo gasto e o espao fsico na memria so considerados fatores essenciais. Consequentemente preciso de um mtodo formal para medir o tempo e a memria requeridos pelo algoritmo, independentemente das caractersticas de plataforma de hardware e software sendo utilizadas.

O que anlise de algoritmos?


A anlise de algoritmos o corao da Cincia da Computao e tem por objetivo estabelecer medidas de desempenho dos algoritmos, com vistas gerao de algoritmos cada vez mais eficientes. Adicionalmente fornece fundamentos para a escolha do melhor algoritmo para a resoluo de um problema especfico, com base na sua complexidade computacional . O tempo de execuo e o espao de memria alocado so os dois fatores principais que determinam a complexidade computacional de uma algoritmo. Complexidade temporal consiste no nmero (aproximado) de instrues executadas. Complexidade espacial consiste na quantidade de memria utilizada. De forma geral, tanto a complexidade temporal quanto a espacial podem ser descritas por funes que tm como parmetro principal o tamanho da entrada sendo processada. Como exemplos temos que: Ordenar 100.000 elementos leva mais tempo que ordenar 10 elementos. A abertura de um editor de textos leva mais tempo e consume mais memria quando aberto com um arquivo grande do que com um arquivo pequeno. Alm do tamanho da entrada, as caractersticas apresentadas na organizao dos dados, tambm podem influenciar na eficincia de um algoritmo em relao a uma outra soluo. Por exemplo, o desempenho de um algoritmo especfico para ordenar um conjunto onde os dados se encontram parcialmente ordenados pode ser muito diferente se utilizado para ordenar um conjunto de dados totalmente desordenados, considerando conjuntos de igual tamanho. Logo importante estabelecer de que forma o tamanho e caractersticas da entrada podem influenciar no comportamento do algoritmo. Em alguns casos, se o algoritmo no recursivo, no contem iteraes e no usa algoritmos com essas caractersticas, o nmero de passos necessrios pode ser independente do tamanho da entrada, e consequentemente a complexidade temporal constante. Um exemplo de algoritmo com estas caractersticas o algoritmo que imprime HELLO WORD, que possui complexidade constante.

A principal caracterstica de um algoritmo recursivo a ocorrncia de chamadas a ele prprio. Para avaliar a complexidade de um algoritmo recursivo preciso analisar quantas vezes a funo vai ser chamada, e quantas operaes acarretam cada chamada.

12

ESTRUTURA DE DADOS

main() { Printf (Hello Word!\n); } Considerando que impossvel fazer uma predio exata do tempo e memria a serem utilizados a estratgia consiste em estabelecer uma aproximao, com base em conceitos e modelos matemticos.

#include <stdio.h>

1. Descreva com suas palavras a relao entre os conceitos de algoritmo e programa. 2. Determine em quais casos e de que forma as especificaes a seguir podem depender do tamanho ou organizao dos dados da entrada. Justifique a sua resposta. a. Procurar o maior elemento em uma sequncia. b. Modificar o contedo de uma varivel. c. Imprimir o contedo de uma sequncia de elementos. d. A partir dos dados de uma pessoa: nome, data de nascimento, sexo, determinar se a pessoa maior de 18 anos.

ESTRUTURA DE DADOS

13

Captulo 2
Medidas de Complexidade

De forma geral, a complexidade de um algoritmo determinada pela quantidade de trabalho requerido sobre um determinado tamanho da entrada. O trabalho depende diretamente do nmero de operaes bsicas efetuadas. Considere o problema de estabelecer se um determinado elemento pertence a um conjunto de 100 elementos. A soluo mais simples para este problema envolve uma pesquisa sequencial onde o elemento procurado comparado a cada um dos elementos pertencentes ao conjunto. O nmero de comparaes realizadas ir depender dos diversos cenrios possveis. A principio podemos analizar duas situaes: o elemento encontrado na primeira comparao realizada ou, o elemento no existe no conjunto. No primeiro caso seria preciso somente uma comparao, enquanto que no ltimo caso todo o conjunto precisaria ser checado, envolvendo, portanto 100 comparaes. Situao 1: Elemento procurado: 10 Conjunto de elementos:
10 1 7 2 50 3 13 4 99 5 5 6 22 7 ... 2 94 66 95 29 96 15 97 88 98 77 99 0 100

Neste caso, na primeira comparao o logaritmo encontra o elemento procurado. A comparao a seguinte: Elemento procurado igual ao primeiro elemento do vetor? R-Sim. 10=10. Situao 2: Elemento procurado: 10 Conjunto de elementos:
10 1 7 2 50 3 13 4 99 5 5 6 22 7 ... 2 94 66 95 29 96 15 97 88 98 77 99 0 100

Neste caso, o elemento comparado com todos os elementos do vetor e no encontrado. As comparaes so as seguintes: 1) Elemento procurado igual ao primeiro elemento do vetor? R-no. 105. 2) Elemento procurado igual ao segundo elemento do vetor? R-no. 107. ... 100) Elemento procurado igual ao centsimo elemento do vetor? R-no. 100. A partir das situaes apresentadas podemos concluir que a complexidade de um algoritmo pode ser estabelecida utilizando uma estratgia pessimista ou mxima, ou otimista ou mnima. Na estratgia pessimista, o algoritmo analisado levando em conta o cenrio mais adverso, o que normalmente ir resultar no maior tempo de execuo. Este critrio nor-

14

ESTRUTURA DE DADOS

malmente o mais utilizado uma vez que estabelece uma cota ou limite superior no tempo requerido. Em oposio a esta abordagem, a complexidade otimista ou mnima obtida quando o problema analisado levando em conta um cenrio ideal demandando, portanto, menos tempo de execuo. Pode ainda ser considerado um caso mdio ou esperado, correspondente mdia dos tempos de execuo de todas as entradas de tamanho n . Estas estratgias podem ser utilizadas tanto para estabelecer a complexidade espacial quanto temporal dos algoritmos. A anlise para o clculo destas medidas pode ser realizada empiricamente, isto , com base na experincia e na observao prtica, exclusivamente, sem se basear em nenhuma teoria. No entanto, a medio obtida pode ser influenciada por fatores acidentais referentes plataforma espe cfica, como por exemplo, a capacidade de processamento do computador sendo utilizado. Consequentemente, a execuo de um algoritmo em um determinado computador pode ter um desempenho diferente medio resultante a partir da execuo do mesmo algoritmo em um outro computador com caractersticas diferentes. Estas possveis divergncias tornam a abordagem baseada na medio emprica pouco confivel.

1. Determine o caso otimista e o caso pessimista a partir das seguintes especificaes: a. Encontrar o maior elemento de um vetor (desordenado) de inteiros. b. Encontrar o maior elemento de um vetor ordenado de forma decrescente de inteiros. c. Remover um dado elemento de um vetor de inteiros. d. Idem anterior considerando um vetor ordenado em forma crescente. 2. Considere o problema de encontrar o maior elemento de um vetor de inteiros. O algoritmo a seguir apresenta uma soluo simples para o problema. int Max (A Vetor){ int i, Temp; Temp = A[0]; for (i := 1; i < n; i++) if (Temp < A[i]) Temp := A[i]; return (Temp); } a. Determine o nmero de comparaes realizadas entre os elementos de A, considerando que A contem n elementos. b. Descreva quais so as situaes que representam o melhor caso, o pior caso e o caso mdio para o algoritmo.

ESTRUTURA DE DADOS

15

Comparao entre algoritmos


Como dito anteriormente, para um dado problema podem existir diversos algoritmos possveis. Cabe ao programador analisar as possibilidades e escolher o algoritmo mais adequado utilizando como critrio bsico a sua complexidade. Uma abordagem amplamente adotada para analizar a complexidade de algoritmos baseada na anlise sobre as operaes fundamentais que compem o algoritmo, a partir das quais derivada uma funo custo modelando o comportamento que o algoritmo ir a adotar de acordo com os dados de entrada fornecidos. Em particular, quando consideradas entradas suficientemente pequenas, o custo reduzido, mesmo no caso de algoritmos ineficientes. J para tamanhos de entrada suficientemente grandes, a escolha por um determinado algoritmo pode ser um problema crtico. Logo, a anlise de algoritmos interessante para valores grandes da entrada, ou seja, no caso de algoritmos que manipulam grandes quantidades de dados. O estudo da complexidade consiste em determinar a ordem de magnitude do nmero de operaes fundamentais realizadas pelo algoritmo, descritas a partir da definio da funo custo. A partir desse estudo possvel realizar a comparao do comportamento assinttico atravs da anlise dos grficos correspondentes. A comparao entre funes com base no critrio de comportamento assinttico consiste no estudo do crescimento de funes para valores grandes de n , no nosso caso, referente ao tamanho da entrada. A partir dessa anlise, as funes so classificadas em ordens, onde cada ordem agrupa funes de crescimento semelhante. O algoritmo assintoticamente mais eficiente o melhor para todas as entradas. Neste contexto, uma funo considerada uma cota assinttica superior ou domina assintoticamente outra, quando cresce mais rapidamente do que outra: graficamente, o grfico da primeira funo fica por cima da segunda a partir de certo ponto m. No caso geral, nem sempre possvel determinar se f (n) < g (n). Sejam f e g as duas funes de custo que queremos comparar: 1. Se f sempre inferior a g, ou seja, o grfico de f fica sempre por baixo do grfico de g, ento a escolha para o algoritmo correspondente a f bvia.

Comportamento observado de f(n) quando n tende a infinito.

Grfico 1 - f sempre inferior a g. Neste caso, o algoritimo f melhor.

2. Se f s vezes inferior a g, e vice-versa, e os grficos de f e g se interceptam em um nmero infinito de pontos. Neste caso, consideramos que h empate, e a funo custo no ajuda a escolher um algoritmo.

16

ESTRUTURA DE DADOS

Grfico 2 - s vezes f superior e s vezes g superior e os grficos se interceptam em um nmero infinito de pontos. Empate.

3. Se f s vezes g inferior a g, e vice-versa, e os grficos de f e g se cortam em um nmero finito de pontos. Portanto, a partir de certo valor de n , f sempre superior a g, ou sempre inferior. Neste caso, consideramos melhor aquele algoritmo que inferior ao outro para grandes valores de n .

Grfico 3 - Se os grficos se interceptam uma quantidade finita de vezes, o melhor aquele que menor que o outro para valores grandes de n.

As funes mais comumente encontradas em anlise de programas, considerando n como tamanho da entrada, so: f(n) = k Constante f(n) = k . n Linear f(n) = n . log n Logartmica f(n) = k . n2 Quadrtica f(n) = k . n3 Cbica f(n) = nk Polinomial f(n) = k . en Exponencial A figura a seguir representa a ordem de crescimento das funes mais comumente utilizadas na representao da complexidade dos algoritmos. Comparativamente podemos concluir que, na medida em que o tamanho da entrada n aumenta, a funo linear n cresce mais rapidamente do que a funo log(n), que por sua vez cresce mais lentamente do que a funo quadrtica n2, e assim por diante.

ESTRUTURA DE DADOS

17

Sempre possvel determinar a taxa de crescimento relativo de duas funes f(n) e g(n) calculando Lim f(n) / g(n) x A partir deste clculo existem os seguintes valores possveis: 0, ento g(n) limite superior para = f(n) c, ento f(n) e g(n) tem complexidades equivalentes infinito, ento f(n) limite superior para g(n) No caso de funes oscilantes, como o caso de sen(n) ou cos(n), nenhuma afirmao pode ser feita.

1. Considere os algoritmos A e B com complexidades: CA(n) = 1000 n2 CB(n) = 0, 1 n3 Determine a partir de qual valor de n , CB domina assintoticamente CA? 2. Para um determinado problema P, temos algoritmos A, B, C, e D com as seguintes complexidades. CA(n) = 100 n log n CB(n) = 1000 n CC(n) = 4 n2 CD(n) = 10 5 en Classificar os algoritmos do melhor at o pior, em termos de complexidade, sempre considerando valores grandes da varivel n (tamanho da entrada). Justifique.

18

ESTRUTURA DE DADOS

A notao utilizada para denotar a dominao assinttica foi introduzida por Knuth em 1968. De acordo com esta notao, a expresso g(n) = O(f(n)) expressa que f(n) domina assintticamente g(n). A expresso pode ser lida da seguinte forma: g(n) da ordem no mximo de f(n). As definies a seguir formalizam a notao de Knuth. A notao mais comumente usada para medir algoritmos O, uma vez que determina um limite superior da complexidade: Definio. A funo custo C(n) O(F(n)) se existem constantes positivas c e m tais que: C(n) c . F(n), quando n m A definio acima afirma que existe algum ponto m a partir do qual c . F(n) sempre pelo menos to grande quanto C(n). Assim, se os fatores constantes so ignorados, F(n) pelo menos to grande quanto C(n). Como exemplo, seja g(n) = (n + 1)2 . Logo, g(n) O(n2), quando m = 1 e c = 4, uma vez que (n + 1)2 4n2 para n 1. Em outras palavras, quanto dizemos que C(n) = O(F(n)) estamos garantindo que a funo C(n) no cresce mais rpido do que F(n). Assim, F(n) um limite superior para C(n). De forma geral, os termos de menor peso e os fatores podem sempre ser eliminados uma vez que para valores grandes da variaveis, estes componentes se tornam despresiveis. Assim O(4n3 + 10n2) e O(n3) so sinnimos, mas o segundo termo mais preciso. Se um algoritmo O(1) significa que o nmero de operaes fundamentais executadas limitado por uma constante. Intuitivamente, se g(n) = 2 n2 , ento g(n) = O(n4), g(n) = O(n3) e g(n) = 2 O(n ). Todas as respostas so tecnicamente corretas, mas a menor a me lhor resposta.

Donald Ervin Knuth, nacido em Milwaukee, em 10 de Janeiro de 1938, um cientista computacional de renome e professor emrito da Universidade de Stanford. o autor do livro The Art of Computer Programming, uma das principais referncias da Cincia da Computao. considerado o criador do campo de Anlise de Algoritmos e fez diversas e importantes contribuies a vrios ramos da teoria da computao

Outras definies formais


Limite inferior: A notao usada para especificar o limite inferior da complexidade de um algoritmo. Complexidade exata: A notao usada para especificar exatamente a complexidade de um algoritmo. Limite superior estrito: o Enfim a notao o usada para especificar que a complexidade de um algoritmo e inferior estritamente a certa funo.

ESTRUTURA DE DADOS

19

1. Suponha g(n) = n e f(n) = n2, demostre qual das seguintes afirmaes verdadeira: a. f(n) = O(g(n)) b. g(n) = O(f(n)) 2. Determine a ordem mxima para as seguintes funes e justifique a sua resposta detalhando os valores de c e n adequados. a. g(n) = 3n3 + 2n2 + n b. h(n) = n2 + n + 1

Operaes com a notao O


Algumas operaes que podem ser realizadas com a notao O so apresentadas a seguir: f(n) = O(f(n)) c . O(f(n)) = O(f(n)), onde c uma constante O(f(n)) + O(f(n)) = O(f(n)) O(O(f(n))) = O(f(n)) O(f(n)) + O(g(n)) = O(max (f(n), g(n))) O(f(n)) . O(g(n)) =O(f(n) . g(n)) f(n ). O(g(n)) = O(f(n) . g(n)) Estas operaes foram demostradas matematicamente na literatura e tem aplicao direta para o clculo do tempo de execuo de (trechos de) programas. Por exemplo, a regra da soma, O(f(n)) + O(g(n)) pode ser utilizada para calcular o tempo de execuo de uma sequncia de trechos ou sentenas de programas. Aplicando essa regra, somente ser considerado o trecho que tiver atribudo o custo mximo dentre os trechos ou sentenas considerados no sumatrio. Aplicando a abordagem de dividir para conquistar, a complexidade de um algoritmo pode ser determinada a partir da complexidade das suas partes. De forma geral, a anlise da complexidade feita em forma particular para cada algoritmo, mas existem conceitos gerais que s dependem das estruturas algortmicas ou comandos de controle utilizados no algoritmo: 1) Sequncia ou conjuno um tipo de comando que, no fluxo lgico do programa, executado e o controle passa para o prximo comando na sequncia. A anlise da complexidade neste caso envolve a aplicao da regra da soma para a notao O com base na complexidade dos comandos. 2) Seleo ou disjuno um tipo de comando que, no fluxo de execuo permite que desvios possam ser feitos a partir do resultado da avaliao de uma condio, executando um bloco de comandos e outros no.

20

ESTRUTURA DE DADOS

A anlise sempre feita considerando o pior caso. Consequentemente, na avaliao da complexidade considerado o desvio que envolve a execuo do bloco de comandos mais custoso, a partir da avaliao da condio. Adicionalmente, a avaliao da condio consome tempo constante 3) Repetio um tipo de comando que, no fluxo de execuo do programa, permite que um bloco de comandos seja repetido enquanto uma condio satisfeita. Alm da checagem da condio (O(1)), o custo de um comando de repetio envolve o custo do bloco envolvido, multiplicado pelo nmero de vezes que ser executado, no pior caso. Vale ressaltar que pode existir aninhamento de comandos de repetio. Neste caso a anlise feita de dentro para fora. O lao pode ser definido (for) ou indefinido (while). 4) Um comando de atribuio possibilita que um valor possa ser atribudo a uma varivel. Um comando de atribuio consome tempo constante.

Por exemplo, dado um vetor v de nmeros inteiros de tamanho n, retornar o maior elemento deste vetor. 1: int Maximo (int v[], int n){ 2: int i: n; 3: int max; 4: 5: if (n = 0) printf ( Vetor vazio ); 6: else { 7: max = v[0]; 8: for (i = 1; i < n; i++) 9: if (v[i] > max)max = v[i]; 10: } 11: return max; 12:} O nmero n de elementos do vetor representa o tamanho da entrada. O programa contm um comando de iterao (8) que contm um comando de desio que, por sua vez, contm apenas um comando de atribuio (9). O comando de atribuio requer tempo constante O(1) para ser executado, assim como a avaliao do comando de desio. Considerando o pior caso, o comando de atribuio sempre ser executado. O tempo para incrementar o ndice do lao e avaliar sua condio de terminao tambm O(1), e o tempo combinado para executar uma vez o lao composto pelas linhas (8) e (9) O(max(1, 1)) = O(1), conforme a regra de soma para a notao O, e considerando que o nmero de iteraes do lao n - 1, ento o tempo gasto no lao (8) O((n - 1) x 1) = O(n - 1), conforme a regra do produto para a notao O.
ESTRUTURA DE DADOS

21

O algoritmo estruturado com base em um comando de desio, cuja condio checada em tempo constante, da mesma forma que a edio da mensagem de erro (O(1)). Por outro lado, utilizando a regra da soma novamente, temos que a execuo das linhas (7), (8) e (9) consome O(max(1, n - 1)) = O(n - 1). No pior caso temos que a execuo do bloco (5) consome O(n - 1). Finalmente, o comando (11) executado em tempo O(1). Aplicando novamente a regra da soma entre (5) e (11) temos que O(max(n 1, 1)) = O(n - 1). Portanto a complexidade temporal do algoritmo Maximo linear. Simplificando a anlise, a quantidade de trabalho do algoritmo pode ser determinada pela quantidade de execues da operao fundamental. No entanto, pode existir mais de uma operao fundamental com pesos diferentes. Neste caso, a regra de soma para a notao O pode ser aplicada.

Considere o algoritmo buscaBinaria descrito a seguir: int buscaBinaria (int array[], int chave, int n){ int inf = 0; int meio; int sup = n - 1; while (inf <= sup) { meio = (inf + sup) / 2; return meio; if (chave == array[meio]) else if (chave < array[meio]) else inf = meio + 1; } } return -1; sup = meio - 1; //Limite inferior //Limite superior

// no encontrado

1. Descreva o funcionamento do algoritmo buscaBinaria. Qual situao representa o pior caso? e o melhor? 2. Considerando a execuo do algoritmo buscaBinaria em um vetor com 15 elementos, quantas repeties (nmero de passos) so necessrios para o algoritmo detectar que uma determinada chave de busca no se encontra no vetor. 3. Determine a complexidade temporal do algoritmo buscaBinaria analisando passo-a-passo a complexidade de cada comando.

22

ESTRUTURA DE DADOS

Nesta unidade foi apresentado um estudo introdutrio sobre os fundamentos da teoria sobre complexidade de algoritmos. Esta teoria de fundamental importncia uma vez que possibilita determinar a melhor soluo para um determinado tipo de problema, assim como tambm elaborar projetos de algoritmos cada vez mais eficientes.

CORMEN T. H., LEISERSON C. E., RIVEST R. L., STEIN C. (2001). Introduction to Algorithms. McGraw-Hill e The Mit Press. KNUTH D. E. (1968). The Art of Computer Programming, Vol. 1: Fundamental Algorithms. Addison-Wesley. KNUTH D. E. (1971). Mathematical Analysis of Algorithms. Procedings IFIP Congress 71, vol. 1, North Holland, 135-143. WIRTH N. (1986). Algorithms and Data Strutures. Prentice-Hall. ZIVIANI N. (2005). Projeto de Algoritmos com implementaes em Pascal e C, 2da. Edio. Thomson.

ESTRUTURA DE DADOS

23

Unidade

Representao dos Dados

Objetivos:
Nesta unidade descrito o processo de abstrao seguindo para a modelagem e desenvolvimento de uma soluo computacional a partir de um problema do mundo real. Neste contexto, os conceitos de tipos de dados, estruturas e tipos abstratos so introduzidos, ressaltando sua importncia para a adequada modelagem, manipulao e representao na memria do computador.

Captulo 1
Modelagem Conceitual

Para que um problema do mundo real possa ser resolvido computacionalmente necessrio utilizar mtodos e tcnicas que possibilitem a modelagem adequada do problema, de forma que possa ser interpretado e processado pelo computador para gerar uma soluo. Os modelos so utilizados para representar o mundo real de forma simplificada, com o objetivo de facilitar o gerenciamento da complexidade. Um modelo reflete os aspectos considerados importantes para o desenvolvimento da aplicao, deixando em um segundo plano, os aspectos que no so relevantes. A modelagem de situaes do mundo real alcanada atravs de um processo de abstrao, a partir do qual, somente as propriedades relevantes para a aplicao so consideradas no modelo.

O processo de abstrao envolve a observao das entidades presentes no domnio do problema para a correspondente representao no domnio computacional. No nvel mais baixo de abstrao, a representao dos dados a nvel de mquina acontece de acordo a padres de bits e bytes de memria. No entanto, as linguagens de programao modernas possibilitam que o programador possa trabalhar com objetos relativamente complexos em um nvel mais alto de abstrao, tornando transparente ao desenvolvedor a manipulao dos dados ao nvel da sua representao interna no computador. Esta facilidade alcanada atravs da utilizao de uma variedade de tipos de dados.

Bit significa dgito binrio, do ingles BInary digiT. Um bit a menor unidade de informao que pode ser armazenada ou transmitida. Um bit pode assumir somente 2 valores: 0 ou 1, verdadeiro ou falso. O conjunto de 8 bits denominado de Byte.

Tipo de dados
O tipo de dados associado a uma varivel, numa linguagem de programao, define o conjunto de valores que a varivel pode assumir. Isto , a declarao da varivel como sendo de um tipo especfico determina: 1. A quantidade de bits que devem ser reservados na memria. 2. Como o dado representado por esse padro de bits deve ser interpretado (p.e., uma cadeia de bits pode ser interpretada como sendo um inteiro ou real).
O sistema operacional (SO) um programa ou conjunto de programas responsvel por gerenciar todos os recursos do sistema, tais como: comandos do usurio, arquivos, memria, etc.

ESTRUTURA DE DADOS

27

Os tipos tm geralmente associaes com valores na memria ou variveis. Consequentemente, tipos de dados podem ser vistos como mtodos para interpretar o contedo da memria do computador, o que pode variar conforme o sistema operacional e a linguagem de implementao. Na sua maioria, as linguagens de programao exigem que um comando declarativo que define uma varivel especifique tambm o tipo de dados associado varivel. Estas linguagens so chamadas de fortemente tipadas. Em contrapartida, as linguagens fracamente tipadas permitem que a definio do tipo correspondente a uma varivel possa ser determinada dinamicamente, em tempo de execuo. Os tipos de dados podem ser classificados em dois grupos: primitivos ou bsicos e compostos ou estruturados. Os tipos de dados primitivos so fornecidos pela linguagem de programao como um bloco de construo bsico. Dependendo da implementao da linguagem, os tipos primitivos podem ou no possuir correpondncia direta com objetos na memria. Exemplos de tipos primitivos comuns so: inteiro, real, caractere, booleano, dentre outros. Alm de estabelecer um esquema predeterminado de armazenamento, a definio de um tipo de dados primitivo estabelece tambm um conjunto de operaes predefinidas sobre aquele tipo. Consequentemente, a definio de uma varivel como instncia de um desses tipos determina o conjunto de operaes que podem ser realizadas utilizando essas variveis. Por exemplo, ao considerar variveis do tipo primitivo inteiro (int), as operaes permitidas se traduzem nos operadores aritmticos vlidos para os valores desse tipo, no caso: soma (+), subtrao (-), multiplicao (*), diviso inteira (DIV) e resto da diviso inteira (MOD). Estas operaes so implementadas de forma nativa por qualquer linguagem de programao, e seu desenvolvimento fica transparente ao usurio. Dada a complexidade das entidades do domnio do problema a serem modeladas e representadas no universo computacional, o fosso semntico (gap semntico) envolvendo a descrio de alto nvel de uma entidade (domnio do problema), e a descrio de baixo nvel (domnio da soluo) pode ser inconcilivel. Neste contexto, a possibilidade de definir tipos de dados que possibilitem a representao destas entidades de forma mais prxima da realidade facilita o processo de abstrao, assim como contribui para a reduo do fosso semntico entre ambos os domnios. O programador pode definir tipos de dados prprios que mais correspondam s necessidades de suas aplicaes. Linguagens de programao atuais permitem aos programadores definir tipos de dados adicionais, utilizando os tipos primitivos e as estruturas como blocos construtivos. Por exemplo, para definir a varivel Empregado com esta estrutura heterognea em C seria: struct Empregado{ char Nome[9]; int Idade; float Qualificao; }; No entanto, se a estrutura for muito frequente, o programa pode ficar volumoso e difcil de ser lido. O mtodo mais adequado consiste em descre-

A memria o dispositivo que permite a um computador armazenar dados de forma temporria ou permanente.

O fosso semntico representa a diferena entre uma descrio de alto nvel e outra de baixo nvel relativa a uma mesma entidade.

28

ESTRUTURA DE DADOS

ver a estrutura de dados correspondente uma nica vez, associando-a a um nome descritivo, e utilizar esse nome todas as vezes que for necessrio. typedef struct { char Nome[9]; int Idade; float Qualificao; } TipoEmpregado; Esta declarao define um novo tipo denominado TipoEmpregado que pode ser usado para declarar variveis da mesma forma como um tipo primitivo. TipoEmpregado Empregado; A partir desta definio possvel gerar as correspondentes variveis instncia, as quais iro assumir valores nos atributos, dependendo do tipo. Por exemplo, valores vlidos para uma varivel do tipo Empregado podem ser: Nome: Joo Soares Idade: 25 anos Qualificao: 8.58 Um tipo definido pelo usurio essencialmente um modelo usado para construir instncias de um dado tipo, que descreve todas as caractersticas que todas as instncias deste tipo devem assumir mas no constitui, ele prprio, uma ocorrncia real deste tipo. A forma conceitual dos dados materializada pela estrutura de dados utilizada na implementao do tipo. Uma estrutura de dados uma forma particular de se implementar um tipo, e construda dos tipos primitivos e/ou compostos de uma linguagem de programao, e por este motivo so chamados de tipos compostos ou estruturados. Um tipo composto envolve um conjunto de campos e membros organizados de forma coerente, onde o tamanho total da estrutura corresponde soma dos tamanhos dos campos constituintes. Exemplos de tipos estruturados so: registros, vetores, matrizes, arquivos, rvores, dentre outros. A escolha por uma estrutura de dados determinante na qualidade e esforo requerido para o desenvolvimento da soluo. As estruturas de dados e algoritmos so escolhidos com base em critrios diversos, tais como desempenho, restries de plataforma de hardware e software, capacidade do equipamento, volume de dados, etc. As estruturas de dados dividem-se em homogneas e heterogneos. As estruturas homogneas so conjuntos de dados formados por componentes do mesmo tipo de dado (p.e., vetores, matrizes, pilhas, listas, etc.). Em contrapartida, as estruturas heterogneas so conjuntos de dados formados por componentes pertencentes a tipos de dados diferentes (p.e., registros). A escolha de uma estrutura de dados apropriada pode tornar um problema complicado em uma soluo bastante trivial. Diferentemente do que acontece na definio de tipos de dados bsicos, onde um conjunto de operaes de manipulao fornecido pela linguagem de progamao (soma, subtrao,...), no caso dos tipos estruturados definidos pelo usurio apenas novos esquemas de armazenamento so definidos. Isto significa que, a principio, no so fornecidos meios para definir as opeESTRUTURA DE DADOS

29

raes a serem executadas sobre instncias de tais estruturas. Consequentemente, algoritmos de manipulao precisam ser desenvolvidos de forma a possibilitar a correta utilizao e acesso s novas estruturas definidas.

1. Defina os conceitos de tipo de dado bsico e tipo de dado definido pelo usurio. 2. Cite como exemplos tipos de dados bsicos que voc conhece e detalhe suas caractersticas e as operaes permitidas sobre esses tipos. 3. Defina um tipo de dado estruturado que descreva de forma adequada e completa as seguintes informaes: a. Livro b. Crculo c. Filme
O paradigma orientado a objetos envolve um conjunto de tcnicas, mtodos e ferramentas para anlise, projeto e implementao de sistemas de software baseado na composio e interao de componentes de software denominados de objetos.

d. Pessoa e. Aluno f. Item de estoque g. Conta bancaria

Tipo abstratos de dados


Um tipo de dado definido pelo usurio, incrementado com a definio e implementao das operaes necessrias para a sua manipulao, constitui um Tipo Abstrato de Dados (TAD), conceito central no contexto do Paradigma Orientado a Objetos. A utilizao de TADs permite que linguagens de programao de propsito geral sejam personalizadas para um domnio de aplicao mais especfico. Uma vez definidos, podem ser empregados como primitivas da linguagem, e possibilitam o desenvolvimento de componentes de software reusveis e extensveis. TADs estendem a noo de tipo de dado (estrutura de dados + operaes) com base na utilizao de tcnicas de ocultamento da informao referente estrutura de dados utilizada e implementao das operaes definidas. Este objetivo alcanado atravs de uma clara separao entre interface e implementao. A seguir apresentado como exemplo a definio do tipo abstrato Retngulo. Um retngulo pode ser definido pela sua largura e altura. A especificao do tipo retngulo pode ser definida como: typedef struct { float altura, largura; } TipoRetangulo;

30

ESTRUTURA DE DADOS

A partir destas informaes possvel calcular sua rea e perme tro. Portanto, alm das operaes de consulta sobre as informaes do retngulo, as operaes de clculo de rea e permetro so requeridas. Desta forma, a interface do tipo abstrato retngulo inclui as seguintes operaes de manipulao. //inicia valores do retangulo void inicia _ retangulo (float a, float l); // atribui um valor altura void InitAltura (float a); // retorna o valor da altura float Altura (void); // atribui um valor largura void InitLargura (float l); // retorna o valor da largura float Largura; // calcula o valor do permetro float Perimetro; // calcula o valor da rea float Area (prottipos das operaes); Finalmente, todos os mtodos implementados na linguagem de programao. Exemplos da implementao de alguns dos mtodos so apresentados a seguir. void inicia _ retangulo (float a, float l) altura = a;
Prottipos na linguagem C define o cabealho das funes. O construtor um mtodo distinguido que tem como funo principal a de instanciar o objeto corretamente, para seu uso posterior.

largura = l; }

float Altura () { return altura; } float Perimetro () { return 2 * (altura + largura); } O projeto de um tipo abstrato uma tarefa difcil, pois este deve ser idealizado de forma a possibilitar a sua utilizao por parte de terceiros, favorecendo o reuso e agilizando o processo de desenvolvimento de software. A atividade de projeto envolve a escolha de operaes adequadas, delineando seu comportamento consistente, de forma que estas possam ser combinadas para realizar funes mais complexas, a partir de operaes simples.
A fase de projeto produz uma descrio computacional do que o software deve fazer, e deve ser coerente com as especificaes geradas na anlise, de acordo com os recursos tecnolgicos existentes.

ESTRUTURA DE DADOS

31

No intuito de aumentar o reuso das operaes, estas devem ser definidas de forma coesa, e ter um comportamento coerente, com um propsito especfico e evitando considerar diversos casos especiais em um mesmo cdigo. O conjunto de operaes que integram a interface do TAD deve oferecer todas as operaes necessrias para que os usurios possam manipular a estrutura adequadamente. Um bom teste consiste em checar se todas as propriedades do objeto de um determinado tipo podem ser acessadas. A escolha pela representao mais adequada ao problema envolve uma anlise aprofundada, uma vez que cada representao possvel possui diferentes vantagens e desvantagens.

1. Defina os conceitos de Tipo Abstrato de Dados. Estabelea o relacionamento que vincula ambos conceitos. 2. Defina TADs para os tipos de dados estruturados para as entidades listadas a seguir especificando detalhadamente a interface completa. A interface deve incluir todas as operaes necessrias para a correta manipulao do tipo, dentre elas os mtodos de inicializao, modificao, e consulta. a. Livro b. Crculo c. Filme d. Pessoa e. Aluno f. Item de estoque g. Conta bancria 3. Implemente dois TADs do exerccio anterior utilizando a linguagem de programao da sua escolha ou pseudo-cdigo prximo da linguagem.

A memria o dispositivo que permite a um computador guardar dados de forma temporria ou permanente.

Critrios para a escolha da estrutura de dados adequada


Como dito anteriormente, a interface do TAD independe da implementao e, portanto, diferentes estruturas de dados podem ser utilizadas como esquema de armazenamento na memria para seus atributos. A partir do esquema utilizado, os dados podem ser armazenados e recuperados. A forma em que a alocao de memria acontece, pode ser um fator determinante para a escolha de uma determinada estrutura de dados.

Uso da memria
Informalmente, podemos dizer que existem trs maneiras de reservarmos espao de memria para o armazenamento de informaes: Uso de variveis globais (e estticas). O espao reservado para uma varivel global existe enquanto o programa estiver sendo executado.

32

ESTRUTURA DE DADOS

Uso de variveis locais. Neste caso o espao fica reservado apenas enquanto a funo que declarou a varivel est sendo executada, sendo liberado para outros usos quando a execuo da funo termina. Por este motivo, a funo que chama no pode fazer referncia ao espao local da funo chamada. As variveis globais ou locais podem ser simples ou vetores, sendo que no caso dos vetores, preciso informar o nmero mximo de elementos ou tamanho do vetor. A partir do tamanho informado, o compilador reserva o espao correspondente. Requisies ao sistema em tempo de execuo. Este espao alocado dinamicamente permanece reservado at que explicitamente seja liberado pelo programa. Uma vez que o espao liberado fica disponvel para outros usos. Se o espao alocado no for liberado explicitamente pelo programa, este ser automaticamente liberado quando a sua execuo terminar. A seguir ilustrada esquematicamente a alocao da memria pelo sistema operacional. Quando requisitamos ao sistema operacional para executar um determinado programa, o cdigo em linguagem de mquina do programa deve ser carregado na memria. O sistema operacional reserva tambm o espao necessrio para armazenarmos as variveis globais (e estticas) utilizadas ao longo do programa. O restante da memria utilizado pelas variveis locais e pelas variveis alocadas dinamicamente enquanto o programa est executando. Cada vez que uma determinada funo chamada, o sistema reserva o espao necessrio para as variveis locais da funo. Este espao pertence pilha de execuo e, quando a funo termina, desempilhado e liberado. A parte da memria no ocupada pela pilha de execuo pode ser requisitada dinamicamente. Se ao longo de diversas chamadas a funo, a pilha cresce atingindo o espao disponvel existente, dizemos que ela estourou e o programa abortado com erro. Similarmente, se o espao de memria livre for menor que o espao requisitado dinamicamente, a alocao no feita e o programa pode prever um tratamento de erro adequado (por exemplo, podemos imprimir a mensagem Memria insuficiente e interromper a execuo do programa). Como mencionado anteriormente, a alocao de memria pode acontecer em tempo de compilao (esttica) ou em tempo de execuo (dinmica). No caso da alocao de memria em forma esttica, o espao destinado para o armazenamento dos dados possui um tamanho fixo, que no pode ser modificado ao longo da execuo do programa. Adicionalmente, a alocao de memria acontece em espaos contguos, isto , um do lado do outro. Exemplos de alocao esttica de memria so variveis globais e vetores. No caso do vetor, a partir de certo endereo que armazena o primeiro elemento a1 do vetor, os elementos subsequentes podem ser acessados diretaESTRUTURA DE DADOS

33

mente incrementando em k o endereo inicial do vetor, onde k o tamanho de memria ocupado por cada elemento do vetor.

O ponteiro ou apontador um tipo de dado que armazena o endereo de um outro dado. A partir do ponteiro, o dado que se encontra no respectivo endereo pode ser acessado e manipulado.

Em contrapartida, no caso de alocao dinmica, a memria gerenciada sob demanda, ou seja, os espaos de memria so alocados e desalocados dependendo da necessidade, durante a execuo do programa. Consequentemente, a alocao no acontece necessariamente de forma contgua (ou sequencial), podendo, os dados, ficarem esparsos na memria do computador. A partir desta configurao onde os dados so armazenados de forma no sequencial, o acesso alcanado atravs de variveis do tipo ponteiro, indicando o endereo de memria correspondente. A seguir ilustrada esquematicamente a distribuio dos elementos integrantes de uma cadeia ao longo da memria. Na primeira coluna indicado o endereo correspondente ao contedo. A coluna ponteiro indica o endereo do prximo elemento na cadeia. Note que o segundo elemento no ocupa o endereo consecutivo ao a1.
Endereo L=3FFB 1D34 BD2F 1500 16F7 5D4A Contedo a1 a2 a3 an-2 an-1 an Ponteiro 1D34 BD2F AC13 16F7 5D4A null ltimo elemento da cadeia. O endereo null indica que o elemento no tem sucessor. Observao Primeiro elemento acessado a partir de L

A partir das caractersticas de cada uma das abordagens para a alocao dos dados, vantagens e desvantagens podem ser estabelecidas. Alocao esttica: Vantagem: Possibilita acesso direto ao local da memria, uma vez que os dados se encontram armazenados de forma contgua ou sequencial. Consequentemente, em alguns casos, as operaes de busca podem ter custo constante O(1). Desvantagem: preciso determinar em tempo de codificao, quanto espao necessrio. Esta estimativa pode ser difcil de ser estabelecida, e est sujeita a flutuaes ao longo da execuo. Consequentemente o espao pode resultar insuficiente ou pode ter sido sobreestimado. Por outro lado, a alocao sequencial na memria prejudica as operaes de insero e remoo, uma vez que a sequencialidade dos dados precisa ser preservada. Com isso, no pior caso, o custo destas operaes pode ser de O(n) por conta dos deslocamentos necessrios para abrir ou fechar espaos para insero e remoo, respectivamente.

34

ESTRUTURA DE DADOS

Alocao dinmica: Vantagem: no necessrio fixar o tamanho da estrutura a priori , uma vez que a alocao de memria feita sob demanda em tempo de execuo. Com isso evitado o desperdcio de espao, e o risco de ficar sem espao reduzido. Consequentemente, no existe restrio encima do nmero de inseres e remoes. Adicionalmente, estas operaes no requerem de nenhum esforo adicional uma vez que envolvem somente o ajuste dos ponteiros j que os elementos se encontram esparsos na memria. Desvantagem: o gerenciamento dos dados diretamente da memria pode ser trabalhoso e propenso a erros. Como conseqncia da no linearidade na alocao dos dados, o acesso a um determinado elemento i torna necessrio o percurso pelos i 1 elementos anteriores na sequncia. Esta propriedade, que caracteriza o acesso sequencial aos dados, torna a operao de busca por um elemento de custo O(n).

Nesta unidade foi apresentado o conceito de abstrao e seus nveis, e a sua importncia no processo de modelagem. Tipos de dados bsicos e estruturados foram definidos neste contexto, como meios de representar e interpretar as informaes manipuladas pela aplicao. Adicionalmente, o conceito de tipo abstrato estabelecido como um mecanismo de extenso e customizao de linguagens de programao, no intuito de facilitar o desenvolvimento de sistemas. TADs so caracterizados por suas operaes, as quais so encapsuladas junto sua estrutura, sendo acessveis exclusivamente atravs da interface especificada, garantindo independncia da implementao utilizada. A independncia de representao torna possvel alterar a representao de um tipo sem que seus clientes sejam afetados. Finalmente, noes de gerncia de memria foram introduzidas, focando nas principais caractersticas que influenciam na escolha pela alocao esttica ou dinmica da memria. Uma anlise dos fatores que contribuem na tomada de deciso foi apresentada.

CORMEN T. H., LEISERSON C. E., RIVEST R. L., STEIN C. (2001). Introduction to Algorithms. McGraw-Hill e The Mit Press. TENENBAUM A. M., LANGSAM Y., AUGENSTEIN M. J. (1995). Estruturas de Dados Usando C, Makron Books/Pearson Education. WIRTH N. (1986). Algorithms and Data Structures. Prentice-Hall. ZIVIANI N. (2005). Projeto de Algoritmos com implementaes em Pascal e C, 2da. Edio. Thomson.

ESTRUTURA DE DADOS

35

Unidade

Listas

Objetivos:
Existem certas estruturas clssicas que se comportam como padres uma vez que so utilizadas na prtica em diversos domnios de aplicao. Nesta unidade apresentada a estrutura de dados Lista e o correspondente Tipo Abstrato, detalhando a sua interface e apresentando duas implementaes: vetores e ponteiros. Variantes do tipo abstrato listas, na forma de Pilhas e Filas, de ampla utilizao prtica, so descritas.

Captulo 1
Listas

Introduo
Um conjunto de elementos pode ser intuitivamente representado atravs de uma lista linear. Listas so estruturas extremamente flexveis que possibilitam uma ampla manipulao das informaes uma vez que inseres e remoes podem acontecer em qualquer posio. Uma lista pode ser definida como uma estrutura linear, finita cuja ordem dada a partir da insero dos seus elementos componentes. As listas so estruturas compostas, constitudas por dados de forma a preservar a relao de ordem linear entre eles. Cada elemento na lista pode ser um dado primitivo ou arbitrariamente complexo. Em geral, uma lista segue a forma a1, a2, a 3, ..., an, onde n determina o tamanho da lista. Quando n = 0 a lista chamada nula ou vazia. Para toda lista, exceto a nula, ai + l segue (ou sucede) ai (i < n), e ai - 1 precede ai (i > 1). O primeiro elemento da lista a1, e o ltimo an. A posio correspondente ao elemento ai na lista i. A lista pode ser representada visualizando-se um vetor, por exemplo. As caractersticas bsicas da estrutura de dados lista so as seguintes: Homognea. Todos os elementos da lista so do mesmo tipo. A ordem nos elementos decorrente da sua estrutura linear, no entanto os elementos no esto ordenados pelo seu contedo, mas pela posio ocupada a partir da sua insero. Para cada elemento existe anterior e seguinte, exceto o primeiro, que no possui anterior, e o ltimo, que no possui seguinte. possvel acessar e consultar qualquer elemento na lista. possvel inserir e remover elementos em qualquer posio.

Uma estrutura dita de linear uma vez que seus elementos componentes se encontram organizados de forma que todos, a exceo do primeiro e ltimo, possuem um elemento anterior e um posterior, somente.

Definio do TAD Lista


Como apresentado na unidade anterior, a definio de um Tipo Abstrato de Dados (TAD) envolve a especificao da interface de acesso para a manipulao adequada da estrutura, a partir da qual so definidas em detalhe, as operaes permitidas e os parmetros requeridos. O conjunto de operaes depende fortemente das caractersticas de cada aplicao, no entanto, possvel definir um conjunto de operaes mnimo, necessrio e comum a todas as aplicaes.

ESTRUTURA DE DADOS

39

Interface do TAD Lista


// Cria uma lista vazia Lista Criar () //insere numa dada posio na lista. int Inserir (Lista l, tipo _ base dado, corrente pos) // Retorna o elemento de uma dada posio tipo _ base consultaElemento (Lista l, corrente pos); // Remove o elemento de uma determinada posio int Remover (Lista l, corrente pos); // Retorna 1 a lista est vazia, ou 0 em caso contrario. int Vazia (Lista l); // Retorna 1 se a lista est cheia, ou 0 em caso contrario. int Cheia (Lista l); // Retorna a quantidade de elementos na lista. int Tamanho (Lista l); // Retorna o prximo elemento na lista a partir da posio corrente. corrente proximoElemento (Lista l, corrente pos); /*Busca por um determinado elemento e retorna sua posio corrente, ou -1 caso no seja encontrado.*/ corrente Busca (Lista l, tipo _ base dado); Uma vez definida a interface, esta pode ser implementada utilizando uma representao dos dados adequada. Existindo mais de uma estrutura adequada, a escolha depende principalmente das necessidades e caractersticas dos dados a serem manipulados pela aplicao. A seguir, o Tipo Abstrato Lista implementado utilizando duas estruturas de dados comumente utilizadas e adequadas s necessidades, cada uma com vantagens e desvantagens particulares.

Implementao do TAD Lista usando alocao esttica


Na implementao de lista adotando alocao de memria esttica os elementos componentes so organizados em posies contguas de memria utilizando arranjos ou vetores. Vantagens e desvantagens desta estrutura foram discutidas na unidade 3. Em particular, a utilizao de vetores se torna adequada no caso em que existe uma clara noo do tamanho da entrada a ser processada, e uma

40

ESTRUTURA DE DADOS

perspectiva que indica que as aplicaes que iro utilizar o TAD no estaro executando muitas operaes de insero e remoo que possam vir a alterar significativamente o tamanho preestabelecido. A estruturao da lista utilizando alocao esttica apresentada graficamente a seguir. Note que, a partir do endereo correspondente ao primeiro elemento no vetor ( pos), e conhecendo o tamanho (c ) de cada componente na lista, possvel calcular o endereo na memria de qualquer elemento armazenado no vetor. Isso garante o acesso direto aos elemento em O(1).

A seguir apresentada a definio da estrutura de dados e implementao das operaes definidas na interface utilizando alocao esttica de memria atravs da definio de vetores. Considerando a utilizao de alocao esttica de memria, o tamanho da estrutura de dados precisa ser determinado em tempo de compilao. #define tamanho Como o prottipo da lista definido de modo a ser implementado usando vetor ou outro recurso, torna-se necessrio definir um tipo que possa ser utilizado como elemento que acessado nas operaes (ou corrente). No caso desta implementao inicial, utilizando vetor, os elementos so acessados atravs de suas posies no vetor, sendo que estas posies so representadas como interiores que iniciam em 0 (zero) na primeira posio e seguem at n-1 (tamanho do vetor - 1). Portanto, torna-se necessrio definir o tipo corrente como inteiro. typedef int corrente; Uma lista um tipo de dado que estrutura elementos cujo tipo pode ser arbitrariamente complexo, envolvendo inclusive, a utilizao de outros TADs. A definio a seguir especifica o tipo base dos elementos da lista como inteiros. typedef int tipo _ base; Os elementos da lista so organizados em um vetor, de tamanho predefinido. Adicionalmente, um atributo contendo a quantidade de elementos da lista (quant_Elem) includo na estrutura no intuito de tornar mais fcil e gil o acesso aos elementos e possibilitar o controle do crescimento da estrutura. typedef struct { tipo _ base v[tamanho]; int quant _ Elem; } no _ Lista;
ESTRUTURA DE DADOS
A notao utilizada na implementao prxima linguagem C.

41

A informao relativa quantidade de elementos existente na lista pode ser til em diversas situaes uma vez que, conhecendo a posio na memria (endereo) do primeiro elemento da lista, possvel calcular o endereo do ltimo elemento e, consequentemente, da primeira posio disponvel. Isto possvel por conta da propriedade de armazenamento contguo propiciada pela estrutura de dados. Finalmente a lista definida como um ponteiro estrutura de dados onde os elementos so agregados. typedef no _ Lista *Lista; A criao de uma lista inicialmente vazia envolve a definio do ponteiro correspondente, apontando a um endereo de memria reservado com tamanho adequado para o armazenamento da estrutura, em particular, o primeiro n representando a cabea da lista. O tamanho da lista inicializado em zero uma vez que inicialmente no contm elementos. Lista Criar () { Lista l = (Lista) malloc (sizeof (no _ Lista)); if (l != NULL){ l -> quant _ Elem = 0; return (l); } else printf (No existe memria suficiente); return; } Normalmente, a lista precisa ser percorrida de forma a realizar algum tipo de processamento sobre os dados que a compem. Consequentemente se torna necessrio um mecanismo que possibilite checar no momento em que no seja possvel processar mais nenhum elemento. O mtodo ultimoElemento responsvel por fazer esta checagem. int ultimoElemento (Lista l, corrente pos) { if (pos + 1 == l -> quant _ elem) return (1) else return (0); } A execuo de uma operao de remoo requer a existencia de no mnimo um elemento na lista. A funo Vazia utilizada para informar se h elementos no vetor, retorna o valor 1 no caso da lista se encontrar vazia, e 0 em caso contrrio. int Vazia (Lista l) { if (l -> quant _ Elem == 0) return (1) else return (0); }

Na linguagem C, a posio que corresponde ao primeiro elemento do vetor corresponde ao ndice i = 0. Em outras linguagens, como por exemplo Pascal, o primeiro elemento no vetor se encontra na posio i=1.

42

ESTRUTURA DE DADOS

Outra operao que pode ser de utilidade a checagem pelo caso em que a estrutura que armazena a lista possa estar cheia, uma vez que esta situao pode inviabilizar a insero de um novo elemento. Este mtodo de fundamental importncia, principalmente no caso de utilizao de alocao de memria esttica onde a tentativa de insero de um novo elemento pode acarretar o estouro da memria, fazendo com que o programa termine com erro. int Cheia (Lista l) { if (l -> quant _ Elem == tamanho) return (1) else return (0); } Uma funo que pode ser definida para auxiliar a verificao de prximo elemento e a insero uma funo vailadPos. Esta recebe a lista e a posio atual e verifica se a posio maior ou igual a zero e se a posio maior que a quantidade de elementos -1. int validaPos(Lista l, corrente pos){ if(pos >=0&&pos< ((l-> quant _ Elem) -1)){ return (1); }else{ return (0); } } Adicionalmente, o percurso ao longo dos elementos de uma lista requer de uma operao que possibilite a movimentao ao longo da estrutura, elemento a elemento. A funo proximoElemento retorna o ndice no vetor correspondente posio do prximo elemento, se for o ltimo e no tiver prximo, retorna -1. corrente proximoElemento (Lista l, corrente pos) { pos = pos++; if (validaPos(l, pos) return (pos); return (-1); } A operao de insero possivelmente uma das mais importantes, uma vez que atravs dela que a lista ser construda. Em particular, o tipo lista no possui nenhuma restrio em relao insero, podendo acontecer em qualquer posio. Desta forma, na hora de inserir um elemento na lista, necessrio informar qual a posio correspondente ao novo elemento, seja no inicio, meio ou fim da lista. Considerando que a insero nem sempre possvel por conta da limitao de espao da estrutura de dados utilizada, a funo retorna 1 se a insero foi realizada com sucesso e 0 em caso contrrio

ESTRUTURA DE DADOS

43

Algoritmo 0 int Inserir (Lista l, tipo _ base dado, corrente pos) { int i; if (!validaPos(l pos) || (cheia (l))) return (0); for (i = l->) quant _ elem ; i > = pos; i--){ l -> v[i] = l -> v[i-1]; } l -> v[pos] = dado; l -> quant _ elem = (l -> quant _ elem)+1; } return (1);

Dependendo da posio onde o elemento ser inserido, o trabalho requerido pode ser estimado de forma a estabelecer o custo da funo. Pelo fato de se utilizar alocao esttica e contgua de memria para o armazenamento dos elementos da lista, a insero de um elemento em uma execuo requer que o espao fsico na memria seja providenciado em tempo de compilao. Para isso necessrio deslocar (shift) todos os elementos necessrios, desde a posio requerida at o final da lista. Por exemplo, se a lista possui 5 elementos e o novo elemento precisa ser inserido na posio 3, os ltimos 3 elementos precisaro ser deslocados direita, para que a posio de insero requerida fique disponvel para o novo elemento a ser inserido. A situao ilustrada na figura a seguir.

O pior cenrio neste caso acontece quando requerida a insero na primeira posio da lista, obrigando o deslocamento de todos os elementos da lista em uma posio direita. Nete caso, o custo requerido O(n). Analogamente operao de insero, a operao de remoo exclui um elemento em qualquer posio, portanto esta posio precisa ser informada explicitamente. O algoritmo responsvel por checar se a posio informada representa uma posio vlida dentro da estrutura.

44

ESTRUTURA DE DADOS

Algoritmo 0.1 int Remover (Lista l, corrente pos) { int i; if (vazia(l) || (!validaPos(l)) return (0); int dado = l -> v[pos]; for (i = pos + 1 ; i < l -> quant _ elem; i++) l -> v[i-1] = l -> v[i]; l -> quant _ elem = (l -> quant _ elem)-1; return (1);

Realizando uma anlise anloga ao caso da insero, o custo para a remoo O(n). No caso em que seja necessrio remover um elemento de acordo com algum contedo especfico, o elemento em questo precisa ser previamente localizado atravs da operao de Busca. A partir da posio retornada pela busca, caso o elemento seja efetivamente encontrado na estrutura, a remoo poder ser efetivamente realizada. A busca por um determinado elemento pode ser originada de duas formas. Na primeira variante, a busca pode ser orientada por um determinado contedo, retornando como resultado a sua posio na lista, no caso em que o elemento for efetivamente encontrado, caso contrrio retorna -1. corrente Busca (Lista l, tipo _ base dado) { int i; for (i = 0; i <= tamanho(l); i++) if (l -> v[i] == dado) return (i); return (-1); } O pior caso possvel para esta busca, consiste na situao onde o elemento procurado no se encontra na lista. Nesta situao a lista ser percorrida na totalidade, sem sucesso, passando pelos n elementos que determinam seu tamanho. Consequentemente, o custo desta operao no seu pior caso O(n), ou seja linear. Na segunda variante, a busca pode acontecer a partir de uma determinada posio na lista, retornando o elemento contido nessa posio.

ESTRUTURA DE DADOS

45

tipo _ base Consulta (Lista l, corrente pos) { return (l -> v[pos-1]); } A complexidade da busca neste caso O(1) uma vez que consiste no acesso direto posio correspondente, demandando para isso tempo constante.

1. Considerando a implementao do TAD utilizando alocao esttica de memria resolva as questes a seguir: a) Explique por que o custo da remoo em uma lista implementada utilizando alocao esttica e contgua de memria O(n). b) Implemente a operao que retorna a quantidade de elementos na lista, cujo cabealho : int tamanho (lista l). Determine a complexidade da operao implementada. c) Implemente o mtodo auxiliar que verifique se uma determinada posio vlida, isto , se encontra dentro dos limites do vetor. O cabealho da operao int validaPos (corrente pos).

Implementao do TAD Lista usando alocao dinmica


Na implementao do Tipo Abstrato lista adotando alocao de memria dinmica, a alocao de memria gerenciada sob demanda em tempo de execuo. Esta caracterstica determina que os elementos componentes so organizados em posies no-contguas, ficando espalhados ao longo da memria. Consequentemente, no preciso estimar a priori o tamanho da estrutura uma vez que o espao alocado na medida da necessidade, dependendo das operaes de insero e remoo realizadas. Vantagens e desvantagens desta estrutura foram discutidas na Unidade 3. Em particular, esta estrutura se torna adequada quando o tamanho da estrutura desconhecido e pode variar de forma imprevisvel. No entanto, a gerncia da memria torna a implementao mais trabalhosa e propensa a erros, podendo acarretar em perda de informao. Adicionalmente, o acesso aos dados seqencial, no sentido que para acessar o elemento na posio m, se torna necessrio percorrer os m - 1 elementos anteriores. Com isso, no pior caso, a busca por um elemento na lista demanda custo O(n). A seguir apresentada a definio da estrutura de dados e implementao das operaes definidas na interface para o TAD Lista utilizando alocao dinmica de memria atravs de ponteiros. A notao utilizada na implementao prxima linguagem C. Esta estrutura representa uma seqncia de elementos encadeados por ponteiros, ou seja, cada elemento deve conter, alm do dado propriamente dito, uma referncia para o prximo elemento da lista. Graficamente, a estrutura de dados para a implementao de listas utilizando ponteiros a seguinte:

46

ESTRUTURA DE DADOS

Por exemplo, uma lista com valores de ponteiros a endereos reais tem a seguinte forma:

O espao total de memria gasto pela estrutura proporcional ao nmero de elementos nela armazenados: para cada novo elemento inserido na estrutura alocado um espao de memria para armazen-lo. Consequentemente, no possvel garantir que os elementos armazenados na lista ocuparo um espao de memria contguo, e, portanto no possvel ter acesso direto aos elementos da lista. Isto implica que, para percorrer todos os elementos da lista, devemos explicitamente seguir o encadeamento dos elementos. Para isto, preciso definir a estrutura do n, como uma estrutura auto-referenciada contendo, alm do contedo de informao, um ponteiro ao prximo elemento na sequncia. As definies a seguir implementam a estrutura correspondente.
typedef struct node *no _ ptr;

struct node { tipo _ base elemento; no _ ptr prox; }; Finalmente a lista definida como um ponteiro ao primeiro n da lista, a partir do qual a sequncia de ns encadeada. typedef no _ PTR Lista; Uma lista um tipo de dado que estrutura elementos cujo tipo pode ser arbitrariamente complexo, envolvendo inclusive, a utilizao de outros TADs. A definio a seguir especifica o tipo base dos elementos da lista como inteiros. typedef int tipo _ base; A implementao de listas com ponteiros requer um cuidado especial uma vez que qualquer erro na manipulao dos ponteiros pode acarretar em perda parcial ou total da lista de elementos. Assim sendo, a utilizao de um ponteiro auxiliar para o percurso ao longo da lista pode ser de grande utilidade. Com esse objetivo definimos um tipo Corrente, a ser utilizado como cpia da lista de forma a possibilitar a sua manipulao com segurana. typedef no _ ptr Corrente;
ESTRUTURA DE DADOS

47

A funo que cria uma lista vazia utilizando alocao dinmica de memria apresentada a seguir. A funo tem como valor de retorno a lista vazia inicializada, isto , o valor de retorno NULL, pois no existem elementos na lista. Lista Criar (){ return (NULL); } O mtodo Inicializar posiciona o ndice da posio corrente no inicio da lista. Desta forma o ponteiro pos aponta para o mesmo local onde se encontra o primeiro elemento da lista. Este mtodo til quando a lista precisa ser percorrida desde o inicio. corrente Inicializar (Lista L){ corrente pos = L; return (pos); } O deslocamento de um elemento para o seguinte na lista dado pelo percurso ao longo dos ponteiros, onde, a partir do n atual, a funo a seguir retorna o ponteiro onde se localiza o prximo elemento na lista. corrente proximoElemento (corrente p) { return (p -> prox); } A procura por um contedo na lista realizada atravs da funo Busca. Esta funo percorre a lista desde o inicio, enquanto o elemento no for encontrado. A funo retorna a posio do elemento na lista em caso de sucesso na procura, ou NULL se o elemento no for encontrado.
corrente Busca (Lista L, tipo _ base corrente p = L; x) {

return p; }

p = p -> prox;

while ((p != NULL) && (p -> elemento != x))

O acesso s informaes contidas nos ns da lista realizado atravs da funo Consulta, que retorna o contedo de informao armazenado no n referenciado pelo ponteiro corrente. tipo _ base Consulta (Lista L, corrente p){ if (p != NULL) return (p -> elemento); }

48

ESTRUTURA DE DADOS

A remoo de um elemento da lista envolve a anlise de duas situaes: a remoo do primeiro n da lista ou de um n em outra posio qualquer, sem ser no inicio da lista. A seguir, o processo de remoo em cada caso ilustrado. No caso da remoo do primeiro elemento da lista necessrio que o ponteiro lista seja atualizado, indicando o novo primeiro elemento.

No caso de remoo de um elemento, sem ser o primeiro, o processo consiste em fazer um by pass sobre esse elemento atravs do ajuste correto dos ponteiros, para posteriormente liberar a memria correspondente. Para efetivar a remoo preciso o n anterior ao n a ser removido, que pode ser obtido a partir da funo auxiliar Anterior.

A funo Remover apresentada a seguir, remove o elemento correspondente a uma determinada posio pos, passada por parmetro. Esta posio pode ser resultado de um processo de busca, a partir de um determinado contedo. Em ambos os casos preciso liberar a memria correspondente ao n removido. A seguir apresentado o algoritmo que implementa o processo de remoo. Algoritmo 0.2 A funo inerior retorna o n anterior ao n passado (pos). Ela percorre a toda a lista verificando se o prximo elemento o elemento pos. corrente Anterior(Lista l, corrente pos){ corrente ant = null; if(pos!= l){ corrente atual = l; while(atual != null & atual -> prox != pos){ atual = atual -> prox; } ant = atual } } return (1);

ESTRUTURA DE DADOS

49

Na remoo encontramos duas situaes: 1) quando o elemento a ser removido a primeira posio (N anterior null); e 2) quando o elemento a ser removido no o elemento da primeira posio (N anterior no null).

int Remover(Lista l, corrente pos){ corrente noAnterior = Anterior (L,pos); corrente tmp _ cell = pos;

if(noAnterior == NULL){ l = l -> prox; }else{ noAnterior -> prox = pos -> prox; } free (tmp _ cell); } return (1);

O algoritmo apresentado para a funo remover utiliza uma funo anterior. Esta funo anterior tem o papel de retornar o elemento que antecede a posio atual. Tendo em vista que para o elemento atual ser removido, basta ligar o elemento anterior ao prximo. A seguir a funo anterior apresentada: corrente Anterior(Lista l, corrente pos){; corrente ant = null;

if(pos != NULL){ corrente atual = l; while(atual != null & atual ->prox !=pos){ atual = atual -> prox; } ant = atual; } return (ant);

50

ESTRUTURA DE DADOS

A insero em uma lista pode acontecer em qualquer posio, que pode ser no inicio, no final ou qualquer outra posio no meio da lista. O contedo do parmetro pos representa a posio de insero requerida para o elemento novo a ser inserido, no caso de insero na cabea da lista pos null. Neste caso, o ponteiro L que apontava ao primeiro elemento da lista aponta agora para o novo elemento inserido.

Para qualquer outro valor de pos, o processo de insero acontece como ilustrado a seguir. A lista precisa ser percorrida at a posio de insero requerida. Nesse ponto, o novo elemento ser inserido atualizando os ponteiros correspondentes.

int Inserir (Lista l, tipo _ base dado, corrente pos){ int i; Corrente atual = Inicializar (l); Lista novo = (Lista) malloc(sizeof(struct node)); novo -> elemento = dado; if (pos == NULL){ novo -> prox = l; l = novo; } else { while (atual -> next != NULL) and (atual -> next != pos) atual = atual -> prox; novo -> prox = atual -> prox; atual -> prox = novo; } else return (1); } A funo Vazia utilizada para verificar se a lista possui ou no elementos armazenados. A verificao consiste em checar se o ponteiro ao primeiro elemento null.
ESTRUTURA DE DADOS

51

int Vazia (Lista L) { if (L == NULL) return (1) else return (0); } A funo ultimoElemento utilizada para verificar o final da lista. Esta checagem consiste em determinar se o prximo elemento que segue ao atual NULL .
int ultimoElemento (corrente p) {

if (p -> prox == NULL) return (1) return (0);

Com exceo de Busca e Anterior todas as operaes consomem tempo O(1). Isto por que somente um nmero fixo de instrues executado sem levar em conta o tamanho da lista. Para Busca e Anterior o custo O (n), pois a lista inteira pode precisar ser percorrida se o elemento no se encontra ou for o ltimo da lista.

Utilizando o TAD Lista definido nesta unidade, implemente como aplicao um programa que, dadas duas listas A e B, crie uma terceira lista L intercalando os elementos das duas listas A e B. Lista Intercala (Lista A , Lista B) { Lista L = cria (); corrente pos _ L = Inicializar (L); corrente pos _ A = Inicializar (A); corrente pos _ B = Inicializar (B); /*Assumimos que A e A tem o mesmo tamanho while (not ultimoElemento(pos _ A)) && (not ultimoElemento (pos _ B)){ Inserir (L, Consulta (pos _ A), null); pos _ A = proximoElemento (pos _ A); Inserir (L, Consulta (pos _ B), null); pos _ B = proximoElemento (pos _ B); return(L);

} }

52

ESTRUTURA DE DADOS

Considerando a implementao do TAD utilizando alocao dinmica de memria resolva as questes a seguir: 1. Implemente a operao que retorna a quantidade de elementos na lista, cujo cabealho : int Tamanho (Lista l). Determine a complexidade da operao implementada. 2. Implemente uma rotina para a remoo de uma lista desalocando a memria utilizada. O cabealho da rotina void Remove_list (Lista L). 3. Implemente a rotina auxiliar chamada anterior usada na remoo, de acordo com o seguinte cabealho corrente anterior (Lista L, corrente pos). Esta rotina retorna a posio do elemento anterior a uma outra posio pos. Se o elemento no for encontrado retorna NULL. 4. Utilizando as operaes definidas na interface do TAD Lista implemente um mtodo que dadas duas listas L1 e L2, calcule L1 L2 (unio) e L1 L2 (interseo). O resultado das operaes deve ser retornado em uma terceira lista L3. 5. Utilizando as operaes definidas na interface do TAD Lista implemente um mtodo que dada uma lista retorne uma segunda lista onde os elementos pertencentes primeira estejam ordenados em forma crescente. Determine a complexidade do seu algoritmo. 6. Escreva um programa que, utilizando o TAD Lista, faa o seguinte: a) Crie quatro listas (L1, L2, L3 e L4); b) Insira sequencialmente, na lista L1, 10 nmeros inteiros obtidos de forma randmica (entre 0 e 99); c) Idem para a lista L2; d) Concatene as listas L1 e L2, armazenando o resultado na lista L3; e) Armazene na lista L4 os elementos da lista L3 (na ordem inversa); f) Exiba o contedo das listas L1, L2, L3 e L4.

Variaes sobre o TAD Lista


Lista ordenada
Uma lista ordenada uma lista onde seus elementos componentes so organizados de acordo a um critrio de ordenao com base em um campo chave. A ordem estabelecida determina que a insero de um determinado elemento na lista ir a acontecer no lugar correto. A lista pode ser ordenada de forma crescente ou decrescente.

ESTRUTURA DE DADOS

53

A partir da existncia de um critrio de ordenao na lista, a funo responsvel pela busca por um determinado contedo na lista pode ser adaptado de forma a tornar a busca mais eficiente.

Lista circular
A conveno consiste em manter a ltima clula apontando para a primeira. Desta forma, o teste por fim de lista nunca satisfeito. Com isso, precisa ser estabelecido um critrio de parada de forma a evitar que o percurso na lista no encontre nunca o fim. Uma forma padro estabelecido com base no nmero de elementos existentes na lista.

Lista duplamente encadeada


Em alguns casos pode ser conveniente o percurso da lista de trs para frente atravs da adio de um atributo extra na estrutura de dados, contendo um ponteiro para a clula anterior. Esta mudana na estrutura fsica acarreta um custo extra no espao requerido e tambm aumenta o trabalho requerido nas inseres e remoes, uma vez que existem mais ponteiros a serem ajustados. Por outro lado simplifica a remoo, pois no mais precisamos procurar a clula anterior (O(n)), uma vez que esta pode ser acessada diretamente atravs do ponteiro correspondente.

54

ESTRUTURA DE DADOS

Captulo 2
Pilhas

Em geral, as operaes de insero e remoo realizadas sobre listas so custosas. No caso da implementao utilizando alocao de mem ria esttica, estas operaes acarretam a movimentao dos elementos. No caso da alocao dinmica o deslocamento at a posio correta de insero ou remoo envolve o percurso ao longo do encadeamento pelos elementos. Em ambos os casos, o custo destas operaes O(n). Estas situaes desfavorveis podem ser contornadas se os elementos a serem inseridos e removidos se encontram em posies determinadas especialmente, como a primeira ou ltima posio. Uma Pilha uma lista com a restrio de que inseres e remoes so executadas exclusivamente em uma posio, referenciada como fim ou topo. Pilhas so conhecidas como estruturas LIFO do ingls Last In First Out ou ltimo que entra primeiro que sai. Em uma Pilha o nico elemento acessvel o elemento que se encontra no topo. Consequentemente, a operao de busca ao longo da estrutura, por exemplo, no uma operao aplicvel para esta estrutura de dados. Graficamente, uma pilha pode ser representada da seguinte forma:

O funcionamento de uma pilha pode ser facilmente interpretado a partir de uma analogia simples com uma pilha de livros pesados. Livros so empilhados, um encima de outro, sendo que o ltimo livro empilhado o que fica no topo da pilha, e, portanto o nico visvel e que pode ser consultado sem precisar movimentar outros exemplares. Por se tratar de livros pesados, o acesso a um livro determinado na pilha, requer que os livros

ESTRUTURA DE DADOS

55

encima deste sejam retirados, um a um, a partir do topo. Desta forma, o ltimo livro empilhado ser o primeiro a ser retirado da pilha. A partir desta descrio, o funcionamento da pilha pode ser modelado de acordo com a seguinte interface. Interface do TAD Pilha // Cria uma pilha vazia Pilha Criar (); //insere um novo elemento no topo da pilha. int Push (Pilha p, tipo _ base dado); // consulta pelo elemento que se encontra no topo tipo _ base Top (Pilha p); //Remove e retorna o elemento do topo tipo _ base Pop (Pilha p); /* Retorna 1 se no tem mais elementos na pilha, ou 0 em caso contrario.*/ int Vazia (Pilha p) // Retorna 1 se a pilha estiver cheia, e 0 em caso contrario. int Cheia (Pilha p); // Retorna a quantidade de elementos na pilha. int Tamanho (Pilha p); Pilhas so listas, portanto as abordagens de implementao utilizadas para listas so vlidas para o caso da implementao de pilhas. Considerando que a implementao de pilhas representa uma variao de listas, boa parte da especificao e implementao de listas pode ser aproveitada.

O fato de mquinas modernas possurem operaes sobre pilhas como parte do conjunto de instrues, faz desta estrutura uma abstrao fundamental na Cincia da Computao, depois do vetor.

Implementaes do TAD Pilha usando vetores


Levando em conta as restries inerentes prpria estrutura de dados e as restries na manipulao da pilha, a estrutura projetada para a implementao de listas modificada, adicionando mais um campo de informao referente localizao do elemento que se encontra no topo da pilha. Esta informao indispensvel na implementao das operaes de insero e remoo, de forma a possibilitar o acesso direto ao local. Com essa pequena alterao na estrutura de dados as operaes passam a demandar tempo constante.

56

ESTRUTURA DE DADOS

typedef int tipo _ base #define tamanho; struct estrutura _ Pilha { int topo; tipo _ base elementos [tamanho]; }; typedef struct estrutura _ Pilha *Pilha; Em C uma pilha definida como um ponteiro estrutura, que passado por valor para as funes que iro modificar o contedo da pilha. Dada a semelhana com a estrutura de dados utilizada para o caso de listas, o mtodo Criar se mantem essencialmente o mesmo, adicionando somente a sentena de inicializao do campo topo para a primeira posio. Algoritmo 1 Pilha Criar(){ Pilha p = (Pilha) Malloc (sizeof(estrutura _ Pilha)); if(p != NULL){

p -> topo = -1; return (p); } else printf ("No existe memria suficiente"); return; }

Na escolha pela extremidade do vetor a ser definida como o topo onde a insero e remoo de elementos estar acontecendo, importante analisar os custos decorrentes desta escolha. Como discutido anteriormente, a propriedade de alocao contgua de memria traz como desvantagem a necessidade de movimentaes dos elementos ao longo da estrutura de dados. Nesse caso, se o topo for escolhido como a primeira posio do vetor, o custo da insero e remoo seria de O(n). Em contrapartida, a definio de topo como sendo o ltimo elemento inserido mais conveniente uma vez que este pode ser acessado em tempo constante a partir do tamanho da estrutura. Algoritmo 2 A operao de insero de um elemento feita no tipo da pilha caso a pilha no esteja cheia. A seguir seguem os algoritmos de verificao de pilha cheia e de insero. int Cheia(Pilha p){ if(p -> topo == tamanho -1 return (1); else return (0) ; }

ESTRUTURA DE DADOS

57

A operao de remoo do elemento que se encontra no topo da pilha descrita no algoritmo a seguir.
tipo _ base Pop (Pilha p) { tipo _ base v; v = p -> elementos [p -> topo]; (p -> topo)--; return v;

A remoo de um elemento somente possvel sempre que a pilha contiver pelo menos um elemento. Nesse caso o elemento copiado em uma varivel auxiliar para seu retorno posterior, decrementando em 1, consequentemente, a posio do ltimo elemento. A lgica seguida para a implementao do algoritmo de consulta do topo, Top, a mesma, com a diferena de que no preciso alterar a posio do topo uma vez que nenhum elemento removido da pilha. O algoritmo que verifica se a pilha se encontra vazia ou no baseado na informao contida no campo topo. Considerando que o topo indica indiretamente a quantidade de elementos efetivamente contidos na pilha, a checagem pela posio onde este elemento se encontra utilizado para estabelecer se a pilha est vazia. Nesse caso a funo retorna 1. int Vazia (Pilha p) { if (p -> topo == 0) return (1) else return (0); } Uma estratgia similar pode ser utilizada para estabelecer se a pilha se encontra cheia, s que neste caso a posio do elemento no topo precisa ser confrontada contra o tamanho total reservado para a estrutura de dados.

58

ESTRUTURA DE DADOS

Considerando a implementao do TAD utilizando alocao esttica de memoria resolva as questes a seguir: 1. Implemente o algoritmo que consulta e retorna o contedo correspondente ao elemento que se encontra no topo, atendendo ao seguinte cabealho: tipo _ base Top (Pilha p). 2. Explique por que mais conveniente a definio do topo da pilha no final e no no inicio da estrutura.

Implementao do TAD Pilha usando ponteiros


No caso da implementao de pilhas utilizando alocao dinmica de memria, a desvantagem do acesso sequencial necessrio para alcanar qualquer elemento da pilha pode ser contornado eficientemente, uma vez que no caso da pilha, as operaes acontecem necessariamente a partir de um extremo. A escolha pelo extremo da estrutura a ser considerado como topo ir a determinar o custo envolvido na execuo das operaes: enquanto que o acesso ao ltimo elemento da pilha envolve custo O(n), o acesso ao primeiro elemento constante. Consequentemente, no caso da implementao da pilha utilizando ponteiros, a definio do topo como sendo o inicio (cabea da lista) da pilha mais vantajoso em termos de desempenho e complexidade. A estrutura de dados utilizada na implementao da pilha idntica aquela definida no caso de listas, consequentemente, a maior parte das operaes so coincidentes, tais como Criar e Vazia. O n pode ser visualizado de acordo com a ilustrao a seguir:

typedef struct node *no _ ptr; struct no dl{ tipo _ base elemento; no _ ptr prox; }; typedef no _ ptr Pilha; A partir da deciso de projeto para o TAD Pilha de considerar o topo para as operaes de insero ( push) e remoo ( pop) na cabea da lista de elementos, cuidados especiais na implementao de tais operaes so requeridos de forma a evitar perda de informao.

ESTRUTURA DE DADOS

59

A seguir, o algoritmo de criao da pilha. Este bom simples, apenas devolve nulo como valor inicial da pilha. Pilha Criar(){ return (NULL); } A operao Push , responsvel pela insero de um novo elemento no topo da pilha, consiste na alocao de memria para o novo elemento. Se a alocao de memria realizada com sucesso, o novo componente instanciado com a informao correspondente e inserido como primeiro elemento na lista, atualizando consequentemente a cabea da lista com o endereo do novo elemento. No caso em que a insero acontea com sucesso o algoritmo retorna 1, e 0 em caso contrario. int Push (Pilha p, tipo _ base x) { no _ ptr novo = (no _ ptr) malloc (sizeof (struct no)); if (no _ tmp == NULL){ printf (Memoria insuficiente!!); return (0); } else { novo -> elemento = x; novo -> prox = p; p = novo; return (1); } }

60

ESTRUTURA DE DADOS

A operao de desempilhar, pop, realiza a remoo de m elemento no inicio da pilha. tipo _ base Pop (Pilha p) { no _ ptr temp; if (p == NULL){ printf (Pilha vazia.); return (0); }else{ temp = p; int valor = temp -> elemento; p = p -> prox; free(temp); return (valor); } }

Considerando a implementao do TAD utilizando alocao dinmica de memoria resolva as questes a seguir: 1. Implemente o algoritmo que consulta e retorna o contedo correspondente ao elemento que se encontra no topo, atendendo ao seguinte cabealho: tipo _ base Top (Pilha p).

2. Implemente uma operao que libere a memria alocada pela pilha. Determine a complexidade do seu algoritmo. 3. Explique por que mais conveniente a definio do topo da pilha no inicio e no no fim da estrutura, no caso de utilizao de ponteiros. 4. Utilizando as operaes definidas na interface do TAD Lista e do TAD Pilha, elabore um algoritmo que dada uma lista ordenada, inverta a ordem dos elementos na lista, utilizando para isso uma pilha. Determine a complexidade do seu algoritmo.
ESTRUTURA DE DADOS

61

5. Utilizando as operaes definidas na interface do TAD Pilha escreva um algoritmo para ordenar pilhas, sendo que no final do processamento os elementos da pilha devem estar dispostos em ordem crescente de seus valores. Determine qual a estrutura auxiliar mais adequada para suportar o processo. Determine a complexidade do seu algoritmo. 6. Utilizando as operaes definidas na interface do TAD Pilha escreva um algoritmo que fornea o maior, o menor e a mdia aritmtica dos elementos de uma pilha dada como entrada.

62

ESTRUTURA DE DADOS

Captulo 3
Filas

Assim como pilhas, filas so listas que possuem algumas restries especficas para a execuo das operaes de insero e remoo. Na fila, as inseres so realizadas em um extremo, enquanto a remoo ocorre no outro. A fila segue o modelo FIFO, do ingls First In First Out, ou seja, que o primeiro que entra na fila o primeiro em sair. A estrutura de dados fila, como seu prprio nome j sugere, semelhante ao funcionamento de uma fila de banco. Onde: 1) Se no h ningum na fila e chega uma pessoa, est ser o inicio e o fim da fila; 2) A partir de ento, quaquer pessoa que chegar ir para o final da fila (aps a pessoa que est no fim); 3) Cada elemento a ser removido ser do inicio da fila (O primeiro que chega na fila o primeiro que sai).

Interface do TAD Fila // Cria uma fila vazia Fila Criar (); //insere um novo elemento no topo da fila. void Inserir (Fila p, tipo _ base dado); // Consulta pelo elemento que se encontra no topo tipo _ base Top (Fila f); //Remove e retorna o elemento do topo int Remover (Fila f); // Retorna 1 se no tem mais elementos na fila, ou 0 em caso contrario.*/ int Vazia (Fila f); // Retorna 1 se a fila estiver cheia, e 0 em caso contrario. int Cheia (Fila f); // Retorna a quantidade de elementos na fila. int Tamanho (Fila f);
ESTRUTURA DE DADOS

63

Implementao do TAD Fila usando vetores


Considerando que a operao de remoo acontece em uma extremidade e a insero na outra, interessante manter apontadores indicando ambos extremos da estrutura, de forma que o acesso seja direto (O(n)). Consequentemente, a estrutura de dados fila inclui, alm do vetor que ir a comportar, as informaes correspondentes, os ndices correspondentes ao inicio e fim da fila, e o tamanho da fila relativo ao nmero de elementos contidos. A seguinte figura mostra uma fila em algum estado intermedirio.

De acordo com esta estratgia e depois da remoo de b e a, e da insero de f e 1, a situao da fila seria a seguinte:

A insero de um elemento na fila incrementa o tamanho e o ndice que indica o fim da fila, enquanto que na remoo de um elemento o tamanho da fila decrementado e o ndice que indica o inicio incrementado. Esta estratgia evita a movimentao de elementos sempre que uma insero ou remoo for realizada. Com isso o custo de ambas operaes fica constante. Levando em conta as restries inerentes manipulao da fila, a estrutura projetada para a sua implementao utilizando alocao de memria esttica ou vetor precisa ser modificada em relao pilha. Neste caso preciso indicar mais um campo de informao referente localizao do elemento que se encontra no inicio da fila. Esta informao indispensvel na implementao das operaes de insero e remoo, de forma a possibilitar o acesso direto ao local. Com essa pequena alterao na estrutura de dados as operaes passam a ser executadas em tempo constante. typedef int tipo _ base; //definindo o tipo base da fia #define tamanho; struct estrutura _ Fila { int ini; int fim; int quant _ elementos; tipo _ base elementos [tamanho]; }; typedef struct estrutura _ Fila *Fila;

64

ESTRUTURA DE DADOS

No entanto existe um problema potencial uma vez que a fila pode ficar aparentemente cheia, no entanto vrios elementos podem ter sido removidos, podendo existir na verdade poucos elementos na fila (observe a figura anterior na qual o fim est na ultima posio do vetor, no entando h duas posies vazias no inicio do vetor). A soluo para contornar este problema implementar o chamado incremento circular no vetor, onde sempre que os ndices de inicio ou de fim chegam no final do vetor, estes so redefinidos na primeira posio do vetor. Esta estratgia requer um cuidado especial na hora do percurso sobre a estrutura, uma vez que o fim do vetor precisa ser determinado logicamente (p.e., pela quantidade de elementos na fila), e no mais fisicamente pelo fim da estrutura. A figura a seguir exemplifica o funcionamento da fila utilizao o vetor circular, onde o contedo c foi removido e adicionado o contedo m.

Quando a fila est cheia, sua quantidade de elementos igual ao tamanho do vetor.

A criao de uma fila vazia, similarmente criao de uma lista, envolve a alocao de memria para a estrutura de dados respectiva, e a posterior inicializao dos campos envolvidos, no caso os ndices de inicio e fim, e a quantidade de elementos que precisam ser inicializados em 0. Algoritmo 3 Fila Criar(){ Fila if (f = (Fila) malloc (sizeof (estrutura _ Fila)); f -> ini = -1; f -> fim = -1; f -> quant _ elementos = 0; return(f) ; }else{ printf(No existe memria suficiente.) ; return; } } Considerando a insero de elementos acontecendo no fim e a remo o no inicio, o cdigo das respectivas operaes apresentado a seguir. No caso da insero, e levando em conta que o tamanho da estrutura de dados esttica foi estabelecida em tempo de compilao, importante verificar que exista espao disponvel para armazenar um novo elemento. Aps esta verificao, o novo elemento inserido na primeira posio livre indicada por fim . Aps isso, tanto fim quando a quantidade de elementos precisam ser atualizados.

ESTRUTURA DE DADOS

65

void inserir (Fila f, tipo _ base v) { if (f -> quant _ elementos == tamanho) { printf (Fila cheia!); return; } f -> fim = incrementar (f -> fim); if(f-> quant _ elementos == 0){ } } f -> elementos [f-> fim] = v; f -> quant _ elementos++;

A implementao do vetor circular requer que seja realizado um incremento especial onde, a partir de uma posio corrente, o mtodo retorna a posio seguinte ou, no caso de atingir o final do vetor, a posio corrente especificada como sendo no inicio da estrutura, no caso 0. int incrementar (int pos){ if (pos == tamanho - 1) return (0); else return (pos++); } Os elementos da fila so removidos do seu inicio. Deste modo, as operaes de remoo movimentam o elemento ini, onde o inicio passa uma posio para frente no vetor e a quantidade de elementos reduzida em 1. Duas situaes merecem o cuidado especial, quando a fila est vazia (quantidade de elementos igual zero) e quando a fila tem somente o elemento que ser removido (neste caso quando a quantidade de elementos para a ser zero inicio e fim devem receber o valor -1 para identificar que a fila est vazia). int remover(Fila f){ if (f -> quant _ elementos == 0); printf("Fila vazia.") ; return; } int temp = f -> elementos[f -> ini]; f -> ini = incrementar(f -> ini); (f -> quant _ elementos)--;

if(f -> quant _ elementos == 0){; f -> ini = -1; f -> fim = -1; } } return(temp) ;

66

ESTRUTURA DE DADOS

Considerando a implementao do TAD utilizando alocao esttica de memria resolva as questes a seguir: 1. Implemente os algoritmos Tamanho, Cheia, Topo e Vazia de acordo com os respectivos cabealhos definidos na interface do TAD. 2. Explique por que mais conveniente a realizao da operao de insero no fim e de remoo no inicio. Como seria se fosse ao contrario? 3. Escreva um algoritmo para ordenar filas, sendo que no final do processamento os elementos da fila devem estar dispostos em ordem crescente de seus valores. Determine qual a estrutura auxiliar mais adequada para suportar o processo. Determine a complexidade do seu algoritmo.

Implementao do TAD Fila usando ponteiros


A implementao de filas utilizando ponteiros segue a mesma estratgia analisada na seo anterior. Como teremos que inserir e retirar elementos das extremidades opostas da lista, representando o incio e o fim da fila, preciso utilizar dois ponteiros, ini e fim, que apontam respectivamente para o primeiro e para o ltimo n da fila. A partir desta necessidade se faz indispensvel a implementao da fila utilizando um n diferenciado, chamado de header ou cabealho, para conter estes ponteiros. Essa situao ilustrada na figura abaixo:

A definio da estrutura de dados que implementa a abordagem descrita a seguinte: typedef struct no *no _ ptr; typedef struct no { tipo _ base elemento; no _ ptr prox; };

ESTRUTURA DE DADOS

67

A estrutura de dados envolve a definio de uma lista de elementos, no mesmo formato em que foi definida para o caso de listas e pilhas. Adicionalmente, a estrutura correspondente ao n cabealho precisa ser especificada uma vez que inclui campos diferenciados. struct cabealho { no _ ptr ini; no _ ptr fim; }; Finalmente, a fila definida como sendo um ponteiro ao n cabealho. typedef struct cabealho *Fila; A partir da interface especificada para o TAD fila, as operaes de criao e verificao pela fila vazia seguem as mesmas estratgias anteriormente descritas. Algoritmo 5 Fila Criar(){ Fila f = (Fila) malloc(siziof(cabelho)); if(f != NULL){; f -> ini = NULL; f -> fim = NULL; return; }else{ printf("No existe memria suficiente.") ; return; } } Algoritmo 6 int Vazia(Fila f){ if(f -> ini == NULL){ return (1) ; }else{ return (0) ; } } A deciso de projeto em relao s operaes de insero e remoo envolve estabelecer em qual extremidade da fila cada uma ser executada. Em particular, a lgica na implementao da operao de remoo de um elemento em uma lista implementada com ponteiros, requer a procura pelo elemento anterior na lista, de forma a atualizar o ponteiro para o prximo elemento (Ver remoo em listas). O custo desta procura pelo anterior O(n). Esta situao pode ser evitada se a remoo acontece sempre no inicio

68

ESTRUTURA DE DADOS

da lista, uma vez que no existe anterior que precise ser atualizado. Esta constatao determina que a escolha mais conveniente em termos de complexidade que cada novo elemento seja inserido no fim da lista enquanto que a remoo de um elemento seja realizada no incio.

No caso da operao de insero, onde o elemento inserido no fim da lista, na situao especfica de insero do primeiro e nico elemento, ambos os ponteiros ini e fim precisam ser atualizados apontando para o nico n inserido na fila. Em qualquer outro caso, somente o ponteiro que indica o final da fila ser atualizado. Algoritmo 7 int inserir (Fila f, tipo _ base dado){ no _ ptr novo = (no _ ptr) malloc (sizeof (no)); novo -> elemento = dado; novo -> prox = NULL; if (f -> fim != NULL){ f -> fim -> prox = novo; }else{ f -> ini = novo; } f -> fim = novo; return(1) ; } Analogamente, a funo para remover um elemento da fila deve atualizar ambos os ponteiros no caso em que for removido o ltimo e nico elemento existente, tornando a fila vazia (ini e fim nulos).

ESTRUTURA DE DADOS

69

Algoritmo 8 tipo _ base remover (Fila f){ no _ ptr temp; if (f == NULL){ printf("Fila Vazia."); return(0) ; }else{ if(f ->ini == NULL){ printf("Fila Vazia."); }else{ temp = f ->ini; int valor = temp -> elemento; f ->ini = f ->ini ->prox; if(f ->ini == NULL){ f ->ini == NULL; } free(temp) ; return(valor) ; } } }

1. Implemente os algoritmos Top e Tamanho de acordo com os respectivos cabealhos definidos na interface do TAD Fila utilizando ponteiros. 2. Explique por que mais conveniente a realizao da operao de insero no fim e de remoo no inicio. Como seria se fosse ao contrrio? 3. Utilizando as operaes definidas na interface do TAD implemente como aplicao uma operao que libere a memria alocada pela fila. Determine a complexidade do seu algoritmo. 4. Utilizando as operaes definidas na interface do TAD Fila, escreva um algoritmo que fornea o maior, o menor e a mdia aritmtica dos elementos de uma Fila. 5. Utilizando as operaes definidas na interface dos TAD Fila e Pilha escrever um algoritmo que leia um nmero indeterminado de valores inteiros. Considere que o valor 0 (zero) finaliza a entrada de dados. Para cada valor lido, determinar se ele um nmero par ou mpar. Se o nmero for par, ento inclu-lo na FILA PAR; caso contrrio inclu-lo na FILA M-

70

ESTRUTURA DE DADOS

PAR. Aps o trmino da entrada de dados, retirar um elemento de cada fila alternadamente (iniciando-se pela FILA MPAR) at que ambas as filas estejam vazias. Se o elemento retirado de uma das filas for um valor positivo, ento inclu-lo em uma PILHA; caso contrrio, remover um elemento da PILHA. Finalmente, escrever o contedo da pilha.

Nesta unidade foi apresentado o tipo abstrato de dados Lista, a partir da definio da sua interface. O tipo abstrato foi implementado de acordo com duas abordagens tradicionais: vetores e ponteiros, analisando as vantagens e desvantagens de cada uma das abordagens de acordo com as caractersticas das aplicaes e operaes mais frequentes. Os TADs Pilha e Fila foram descritos e implementados como variantes do TAD Lista. Estes TADs so amplamente difundidos e de comprovada utilidade na resoluo e modelagem de problemas do mundo real.

CORMEN T. H., LEISERSON C. E., RIVEST R. L., STEIN C. (2001). Introduction to Algorithms. McGraw-Hill e The Mit Press. KNUTH D. E. (1968). The Art of Computer Programming, Vol. 1: Fundamental Algorithms. Addison-Wesley. KNUTH D. E. (1971). Mathematical Analysis of Algorithms. Prociedings IFIP Congress 71, vol. 1, North Holland, 135-143. SZWARCFITER J. l., MARKENZON L. (2010). Estruturas de Dados e Seus Algoritmos. 3. Edio. LTC. WIRTH N. (1986). Algorithms and Data Strutures. Prentice-Hall. ZIVIANI N. (2005). Projeto de Algoritmos com implementaes em Pascal e C, 2da. Edio. Thomson.

ESTRUTURA DE DADOS

71

Unidade

rvores

Objetivos:
Diversas aplicaes requerem de uma organizao e manipulao de dados mais complexa daquela propiciada atravs de estruturas lineares, analisadas na unidade anterior. Uma rvore uma estrutura de dados no linear muito eficiente para armazenar informao de forma a representar relacionamentos de aninhamento ou hierarquia entre os elementos envolvidos. Nesta unidade so apresentados os conceitos iniciais relativos a rvores e a sua representao clssica e implementao atravs da definio do tipo abstrato correspondente. rvores binrias de busca e balanceadas (AVL) so introduzidas.

Captulo 1
rvores

Vetores e listas so estruturas de dados chamadas de unidimensionais ou lineares, e portanto, no so adequadas para representarmos dados que devem ser dispostos de maneira hierrquica. Por exemplo, a estrutura hierrquica de diretrios (pastas), aninhamento, etc. Estruturas de dados no lineares, como rvores, so ideais para representar este tipo de relacionamento. A ilustrao a seguir representa esquerda o aninhamento de conjuntos e direita a representao hierrquica deste aninhamento utilizando uma rvore.

Uma rvore composta por um conjunto de ns. Existe um n r, denominado raiz, que contm zero ou mais sub-rvores, cujas razes so ligadas diretamente a r. Esses ns razes das sub-rvores so ditos filhos do n pai, r.

O nmero de filhos permitido por n e as informaes armazenadas em cada n diferenciam os diversos tipos de rvores existentes: rvores binrias, onde cada n tem, no mximo, dois filhos. rvores genricas, onde o nmero de filhos indefinido. A forma mais natural para definirmos uma estrutura de rvore usando recursividade. Uma rvore T um conjunto finito de n ns ou vrtices, tais que:

ESTRUTURA DE DADOS

75

Se T um conjunto vazio, ou seja n = 0, a rvore nula, ou vazia, ou Existe um n especial, r, chamado raiz da rvore; Os demais ns constituem um conjunto vazio ou so particionados em conjuntos disjuntos no vazios, as sub-rvores de r ; Cada sub-rvore, por sua vez, tambm uma rvore. Sejam T uma rvore e v um n, tal que v T, Tv a sub-rvore de T que tem v como raiz. Definem-se as seguintes propriedades: O grau de sada do no v o nmero de sub-rvores que ele possui. O grau da rvore T o maior grau dentre os de todos os seus ns. Os filhos de v so as razes das sub-rvores de v. Um n que no tem descendentes chamado de folha ou terminal. Uma propriedade fundamental de todas as rvores que s existe um caminho da raiz para qualquer n. Com isto, podemos definir a altura de uma rvore como sendo o comprimento do caminho mais longo da raiz at uma das folhas. Assim, a altura de uma rvore com um nico n raiz zero. Um caminho em T uma sequncia de ns v1, v2, ..., vm, tal que para cada par (vi, vi+1), vi pai de vi+1. O comprimento do caminho m-1. O nvel do n v o nmero de ns no caminho da raiz at v. O nvel do n raiz 0, por definio. A altura de um n v o nmero de ns no maior caminho de v at um dos seus descendentes. Folhas tm altura 1. A altura da raiz determina a altura da rvore.

rvore binria
Em uma rvore binria, cada n tem zero, um ou dois filhos. De maneira recursiva, podemos definir uma rvore binria como sendo: Uma rvore vazia; ou Um n raiz v tendo duas sub-rvores, identificadas como a subrvore da direita (sad ) e a sub-rvore da esquerda (sae) de v.

Pesquise sobre aplicaes da estrutura de dados rvore.

Pela definio, uma sub-rvore de uma rvore binria sempre especificada como sendo a sae ou a sad de uma rvore maior, e qualquer das duas sub-rvores pode ser vazia. Uma rvore binria T um conjunto finito de n ns ou vrtices, tais que: Se T um conjunto vazio, ou seja, n=0, a rvore nula ou vazia, ou Existe um n especial, r, chamado raiz da rvore; Os demais ns constituem um conjunto vazio ou so particionados em dois conjuntos disjuntos: sub-rvore esquerda e direita de r, cujas razes so chamadas de filho esquerdo e direito de r ; Cada sub-rvore, por sua vez, tambm uma rvore binria;

76

ESTRUTURA DE DADOS

Uma rvore estritamente binria aquela em que cada n possui zero ou dois filhos, como representado na figura a seguir.

Uma rvore binria completa aquela cujos ns com sub-rvore vazias localizam-se no ltimo ou no penltimo nvel. Um exemplo de rvore binria completa ilustrado na figura abaixo.

Uma rvore binria cheia aquela cujos ns com sub-rvores vazias localizam-se todos no ltimo nvel. Logo, ela tambm estritamente binria.

Um exemplo de utilizao de rvores binrias est na avaliao de expresses. Nessa rvore, os ns folhas representam operandos e os ns internos operadores binrios. Uma rvore que representa, por exemplo, a expresso (5 + 9) * (3 - 7) + 7 ilustrada na seguinte figura:

ESTRUTURA DE DADOS

77

Dependendo do percurso da rvore a mesma expresso pode ser representada em forma expresses infixas, prefixas e psfixas. No cao de percorrer uma rvore de forma infixa, inicialemente a sub-rvore esquerda percorrida, em seguida o n raiz percorrido, por ultimo a sub-rvore direita percorrida. No caso da rvore acima ser percorrida de forma infixa, o resultado seria: 5 + 9 * 3 - 7 + 7. Neste caso, o percurso resulta em uma expresso matemtica vlida. No caso de percorrer uma rvore de forma prefixa, inicialmente o n raiz percorrido, em seguida a sub-rvore esquerda percorrida, por ultimo a sub-rvore direita percorrida. No caso da rvore acima ser percorrida de forma prefixa, o resultado seria: + * + 5 9 - 3 7 7. Observe que neste caso, o percurso no resulta em uma expresso matemtica vlida. No caso de percorrer uma rvore de forma psfixa, inicialmente a sub-rvore esquerda percorrida, em seguida a sub-rvore direita percorrida, por ultimo o n raiz percorrido. No caso da rvore acima ser percorrida de forma psfixa, o resultado seria: 59 + 37 -* 7+. Observe que neste caso, o percurso tambm no resulta em uma expresso matemtica vlida. No prximo captulo sero abordados estas formas de percursos em rvores.

1. Pesquise sobre aplicaes da estrutura de dados rvore binria.

78

ESTRUTURA DE DADOS

Captulo 2
rvore binria de busca

Uma rvore de busca uma rvore binria com a propriedade de que para todo no x na rvore, os valores de todas as chaves na sub-rvore esquerda so menores ou iguais do que o valor chave em x , e que os valores de todas as chaves na sub-rvore direita so maiores ou iguais do que o valor chave em x . Esta definio se aplica recursivamente a cada n da rvore. Assumimos que cada n na rvore possui um valor chave, e em principio no considerada a ocorrncia de chaves repetidas. No caso das rvores representadas a seguir, a propriedade de ordenao pode ser verificada em todos os ns na rvore esquerda. Na rvore direita, a propriedade no se verifica uma vez que na sub-rvore esquerda do n raiz aparece um n com chave maior (5) quela encontrada na raiz (4).

Como a profundidade mdia das rvores binrias de busca O(log n), as operaes sobre elas executadas tambm. Desde que todos os elementos na rvore seguem um critrio de ordem os operadores <, > e = podem ser aplicados de forma a estabelecer comparaes entre eles.

Definio do TAD rvore Binria de Busca


O conjunto de operaes necessrio para a manipulao correta e satisfatria de uma rvore binria de busca definido a seguir.

ESTRUTURA DE DADOS

79

Interface do TAD ABB // Retorna uma rvore vazia. ABB Inicializar (void); // Cria e retorna uma rvore inicializada. ABB Rriar (element _ type c, no _ ptr e, no _ ptr d); //Insere um dado na rvore. no _ ptr Inserir (no _ ptr pai, no _ ptr filhoEsq); /*Busca por um determinado elemento e retorna o n correspondente, ou null caso no seja encontrado. no _ ptr Buscar (element _ type x, ABB t); // Retorna o contedo de um n. element _ type Conteudo (no _ ptr a); // Retorna o filho esquerdo de um n. ABB retornaSAE (no _ ptr a); // Retorna o filho direito de um n. ABB retornaSAD (no _ ptr a); //Remove um elemento. void Remove (element _ type x, pai, ABB pai, ABB n); // Retorna 1 se o n for nulo, ou 0 em caso contrrio. int Vazia (no _ ptr a);

Implementao do TAD rvore Binria de Busca


O armazenamento de rvores pode utilizar alocao dinmica ou esttica, cujas vantagens e desvantagens foram analizadas em unidades anteriores. No entanto, por se tratar de uma estrutura mais complexa o potencial desperdcio de espao pode ser reduzido pela utilizao de ponteiros. A definio da estrutura de dados surge naturalmente a partir da definio recursiva da rvore. Cada n na rvore possui, alm do campo de informao, dois ponteiros, que apontam para cada uma das suas sub-rvores. typedef struct no _ rvore *no _ ptr; typedef int element _ type; struct no _ rvore { element _ type info; no _ ptr esq; no _ ptr dir; };

80

ESTRUTURA DE DADOS

Da mesma forma que uma lista encadeada representada por um ponteiro para o primeiro n, a estrutura da rvore como um todo representada por um ponteiro para o n raiz, a partir do qual todos os ns da rvore podem ser alcanados. typedef no _ ptr ABB; Como uma rvore representada pelo endereo do n raiz, uma rvore vazia tem que ser representada pelo valor NULL . ABB Inicializar (void){ return NULL; } Para criar rvores no vazias, podemos ter uma operao que cria um n raiz contendo a informao e os ponteiros s suas duas sub-rvores, esquerda e direita. Essa funo tem como valor de retorno o endereo do n raiz criado e inicializado, como segue: ABB Criar (element _ type c, ABB sae, ABB sad){ p = (ABB) malloc (sizeof (no _ rvore)); p -> info = c; p -> esq = sae; p -> dir = sad; return p; } As duas funes Inicializar e Criar representam os dois casos da definio recursiva de rvore binria: uma rvore binria vazia (a = Inicializar ();) ou composta por uma raiz e duas sub-rvores (a = Criar (c, sae, sad);). As operaes que possibilitam a consulta dos contedos dos campos que compem o n so apresentadas a seguir. O mtodo Conteudo retorna a informao contida no n, enquanto que retornaSAE retorna a sub-rvore esquerda do n. Analogamente o mtodo retornaSAD retorna a sub-rvore direita. element _ type Conteudo (ABB a){ return (a -> info); } } ABB retornaSAE (ABB a){ return (a -> esq);

A busca por um contedo em uma rvore binria de busca leva em conta o critrio de ordenao estabelecido entre os ns que a compem. Desta forma, enquanto a chave procurada no for encontrada, se for menor do
ESTRUTURA DE DADOS

81

que a chave que se encontra no n da rvore, a procura continua na sub-rvore da esquerda, e no caso contrrio na sub-rvore direita, recursivamente. no _ ptr Buscar (element _ type x, ABB T) { if (T == NULL) return NULL; if (x < T -> info) return (Buscar (x, T -> esq)); else if (x > T -> info) return (Buscar (x, T -> dir)); else return T; } O processo de insero na rvore segue a mesma lgica do algoritmo Buscar. Se o elemento for encontrado nada feito, uma vez que no estamos considerando a ocorrncia de chaves repetidas. Em outro caso, o elemento inserido. Note que seja qual for a chave a ser inserida, a insero sempre acontece em um n folha. O exemplo a seguir ilustra a insero da chave com valor (12).

Duplicaes podem ser manipuladas mantendo um campo extra no registro do n indicando a freqncia da ocorrncia. Esta soluo mais eficiente uma vez que replicar ns na rvore tornaria a rvore mais profunda aumentando o custo mdio requerido nas operaes sobre as rvores, alm de alocar mais espao de memria. no _ ptr Inserir (element _ type x, ABB T) { if (T == NULL) { T = (ABB) malloc (sizeof (no _ rvore)); T -> element = x; T -> esq = NULL; T -> dir = NULL; } else if (x < T -> info) T -> esq = Inserir (x, T -> esq); else if (x > T -> info) T -> dir = Inserir (x, T -> dir); return T; }

82

ESTRUTURA DE DADOS

Na remoo vrias possibilidades devem ser consideradas. Se o n que vai ser removido folha a remoo imediata. Se o n tem somente um filho ele pode ser removido ajustando os ponteiros entre seu pai e seu filho de modo de realizar um by pass encima do n. Por exemplo, considere a rvore a seguir, onde o n correspondente ao dado (5) precisa ser removido. O processo a ser seguido descrito na rvore que aparece direita.

Se o n a ser removido tem dois filhos a estratgia geral consiste em reemplazar a chave do n com a menor chave da sub-rvore direita (ou maior da sub-rvore esquerda), e recursivamente remover esse n. Como o filho mais esquerdo da sub-rvore direita no pode ter filho esquerdo, a segunda remoo mais fcil. O exemplo a seguir ilustra a remoo do n cujo contedo (2), que possui dois filhos. Nesse caso o n substitudo pelo filho mais a esquerda da sub-rvore direita (ou o menor dos maiores). Posteriormente, o n utilizado na substituio precisa ser removido (3) da sub-rvore correspondente.

O mtodo Remover recebe por parmetro o ponteiro ao n que ser removido. Este ponteiro pode ter sido obtido a partir da execuo da operao de busca por um contedo especfico. O algoritmo tambm precisa do ponteiro correspondente ao n pai do n que ser removido, j que o respectivo ponteiro precisa ser ajustado. O cdigo realiza dois passes na rvore para encontrar e remover o menor n da sub-rvore direita. Esta ineficincia pode ser removida escrevendo uma funo delete_min.

ESTRUTURA DE DADOS

83

void Remover (element _ type x, ABB pai, ABB no){ no _ ptr tmp _ no, filho; if (no -> esq != null && v -> dir != null) { tmp _ cell = buscaMin (no -> dir); no -> info = tmp _ cell -> info; no -> dir = Remover (no -> info, no -> dir);

else { tmp _ no = no; if(no -> esq == NULL filho = no -> dir; if(no -> dir == NULL ) filho = no -> esq; if (pai -> dir ==T) pai -> dir = filho; else pai -> esq = filho; free (tmp _ no); }

O mtodo auxiliar que procura o n que contem o contedo mnimo possui duas verses, uma recursiva e outra iterativa. no _ ptr buscaMin (ABB T){ if (T == NULL ) return NULL; else if (T -> esq == NULL ) return (T); else return (buscaMin (T -> esq)); } no _ ptr buscaMin (ABB T){ if (T != NULL) while (T -> esq != NULL) T = T -> esq; return T; } Os dois algoritmos possuem uma lgica simples, no entanto a verso no recursiva pode ser mais eficiente em termo de custo espacial e temporal do que a verso recursiva.

84

ESTRUTURA DE DADOS

Escreva uma funo que verifique se uma rvore cheia. Uma rvore dita cheia se todos os ns que no so folhas tm os dois filhos, isto , no pode existir n com apenas um filho. A funo deve retornar 1 no caso da rvore ser cheia ou 0 no caso de no ser. No caso da rvore ser vazia, a funo deve retornar 1. int cheia (tree _ ptr a) { if (vazia (a)) return (1); else if ((vazia (retornaSAE (a)) && !vazia (retornaSAD (a)) || ((!vazia (retornaSAE (a)) && vazia (retornaSAD(a)) return (0); else return cheia (retornaSAE (a)) && cheia (retornaSAD(a)); }

Ordens de percurso em rvores binrias


O percurso de todas as sub-rvores executando alguma ao de tratamento em cada n, pode ser feito seguindo uma das seguintes ordens: pr-ordem: trata raiz, percorre sae, percorre sad; ordem simtrica: percorre sae, trata raiz, percorre sad; ps-ordem: percorre sae, percorre sad, trata raiz. Por exemplo, no caso de imprimir o contedo dos ns de uma rvore binria, os algoritmos que implementam esta ao de acordo com cada percurso so apresentados a continuao. void ImprimirPosordem (no _ ptr a){ if ( !Vazia(a) ){ ImprimirPosordem (retornaSAE(a)); ImprimirPosordem (retornaSAD(a)); printf (Conteudo(a)); } return; }

ESTRUTURA DE DADOS

85

void ImprimirSimetrica (no _ ptr a){ if ( !Vazia(a) ){ ImprimirSimetrica (retornaSAE(a)); printf (Conteudo(a)); ImprimirSimetrica (retornaSAD(a)); } return; } void ImprimirPreordem (no _ ptr a){ if ( !Vazia(a) ){ printf (Conteudo(a)); ImprimirPreordem (retornaSAE(a)); ImprimirPreordem (retornaSAD(a)); } return; } Por exemplo, dada a rvore de expresso a seguir, como resultado dos percursos apresentados, as expresses resultantes so as seguintes:

Inordem: 5 + 9 * 3 - 7 + 7 Preordem: + * +5 9 3 7 7 Posordem: 5 9 + 3 7 - * 7 +

1. Crie a rvore binria de acordo com a seguinte sequncia de nmeros, na ordem: a) 1, 2, 3, 4, 5, 6, 7. Analise a rvore binria obtida em termo de desempenho na execuo das operaes sobre ela. b) 20, 5, 12, 36, 27, 45, 9, 2, 6, 17, 40.

86

ESTRUTURA DE DADOS

c) A partir da rvore obtida no inciso anterior, remover os ns: 9, a seguir o 5, e finalmente o 20. 2. Implemente um algoritmo que determine se uma rvore binria de busca efetivamente uma rvore binria de busca. 3. Implemente o mtodo que retorna o maior elemento a partir de um determinado n cujo cabealho : no _ ptr buscaMAX (ABB T). Implemente o mtodo na sua verso recursiva e no recursiva. 4. Dada uma rvore binria de busca, onde cada n constitudo pelas seguintes informaes: NOME, SEXO (M ou F), IDADE e PESO. Sabendo que a rvore foi construda com a chave NOME e que j existe um ponteiro chamado RAIZ que aponta para o n raiz da rvore, construir um algoritmo que, a partir desta rvore, gere duas listas ordenadas por NOME, uma para homens e outra para mulheres. 5. Escreva um algoritmo recursivo que encontre o maior valor armazenado em uma rvore binria de busca j construda. 6. Adapte os algoritmos de insero e remoo em rvores binrias de busca de forma a tratar a ocorrncia de contedos-chave repetidos, mantendo um contador de ocorrncias em cada n. 7. Para a rvore binria a seguir, escreva as sequncias de ns visitados aps a execuo dos percursos pr-ordem, inordem e ps-ordem. Codifique os algoritmos correspondentes a cada um dos percursos.

8. Utilizando as operaes definidas na interface do TAD ABB de nmeros, escreva um mtodo que retorne quantos ns de uma ABB armazenam valores contidos em um intervalo [x1, x2].

Relao entre o nmero de ns de uma rvore binria e sua altura


A cada nvel o nmero potencial de ns numa rvore binria vai dobrando, de forma que para uma altura h da rvore existe um nmero mximo de ns, dado por: 2
0

+2

+2

+ ... + 2

h-1

+2

=2

h+1

- 1 ns

ESTRUTURA DE DADOS

87

Portanto, uma AB de altura h pode ter no mximo O (2h) ns. A partir desta definio temos que o nmero de ns em uma AB dada por n = 2h ns. Para despejar h temos que aplicar a definio de logaritmo: log n = h. log 2. Portanto uma rvore binria com n ns pode ter uma altura mnima de O (log n). Por outro lado, se a rvore tem altura h, deve existir um caminho de comprimento h da raiz at um dos ns, digamos n0, n1, ... nh, e todos os h+1 ns deste caminho devem ficar em nveis diferentes. Assim, a rvore dever ter pelo menos h+1 ns. Esta relao entre o nmero de ns e a sua altura importante, pois significa que a partir da raiz, qualquer n pode ser alcanado em no mximo O (log n) passos. Note que se tivssemos n ns numa lista linear o nmero mximo de passos seria O (n). A altura da rvore uma medida do tempo necessrio para encontrar um n. Esta propriedade atinge a eficincia mxima quando a rvore binria balanceada, ou seja, todos os ns internos, ou quase todos possuem dois filhos. fcil prever que aps vrias operaes de insero e remoo, a rvore tende a ficar desbalanceada. Em especial, a operao de remoo numa ABB dependendo da estratgia utilizada (substituio do n a ser removido pelo maior da sub-rvore esquerda ou o menor da sub-rvore direita), favorece sistematicamente uma das sub-rvores. A soluo a este problema consiste em sempre manter a altura das sub-rvores no mnimo, ou prximo do mnimo. Para isso necessrio de processos de insero e remoo mais complexos que mantenham as sub-rvores balanceadas.

88

ESTRUTURA DE DADOS

Captulo 3
rvores AVL

Uma AVL uma rvore binria de busca dinamicamente equilibrada ou balanceada, na qual se busca manter, a um custo razovel, um tempo de busca prximo quele que se conseguiria se a rvore fosse completa, o que garante que a altura da rvore O(log n). O nome AVL deve-se aos seus criadores, os matemticos ADELSON-VELSKII e LANDIS. A propriedade de balanceamento consiste em manter as sub-rvores esquerda e direita de cada n, na mesma altura, podendo diferir no mximo em 1 nvel. A figura a seguir ilustra uma rvore, onde a raiz se encontra balanceada uma vez que a suas sub-rvores esquerda e direita possuem a mesma altura, no entanto os ns internos no satisfazem essa propriedade.

Com esta restrio, todas as operaes sobre rvores podem ser executadas em tempo O(log n), exceto possivelmente a insero. No entanto, para manter a propriedade de balanceamento, alm dos algoritmos de percurso, incluso e excluso j discutidos, so necessrios algoritmos que restabeleam o equilbrio aps incluses e excluses, caso algum n fique desregulado. Por exemplo, na insero, pode ser preciso atualizar a informao de balanceamento para os ns no caminho de volta para a raiz, pois somente aqueles ns tiveram as suas sub-rvores alteradas. No caso das rvores binrias de busca representadas a seguir, a rvore da esquerda se encontra balanceada uma vez que todos os ns mantem suas sub-rvores com uma diferena de at um nvel. J a rvore da direita apresenta um desbalanceamento na raiz.

ESTRUTURA DE DADOS

89

A insero de 6.5 na primeira rvore provocar o desbalanceamento do n 8. A propriedade de balanceamento restaurada atravs de operaes de rotao. Seja o no desbalanceado. Desde que todo n tem no mximo dois filhos e o desbalanceamento da altura requer que a altura das duas subrvores deferem em 2, a violao da propriedade pode acontecer como consequncia de operaes de insero ou remoo. O fator de balanceamento (FB) de um determinado n r calculado como a diferencia entre a altura da sub-rvore esquerda de r e da sub-rvore direita de r. Se o valor obtido for menor ou igual a 1 o n est balanceado. Caso contrrio o n se encontra desbalanceado. O FB de um n folha 0. Algoritmo que calcula a altura de um n int Altura (ABB no){ int Alt _ Esq, Alt _ Dir; if (no = NULL) Altura := -1 else { Alt _ Esq := Altura (retornaSAD (no)); Alt _ Dir := Altura (retornaSAE (no)); if (Alt _ Esq > Alt _ Dir) Altura := 1 + Alt _ Esq else Altura := 1 + Alt _ Dir;

No caso em que for constatado o desbalanceamento em um determinado n, quatro situaes possveis podem ser constatadas. Tipo I : Se a sub-rvore esquerda maior que a sub-rvore direita (FB > 1), e a sub-rvore esquerda desta sub-rvore esquerda maior que a sub-rvore direita dela, ento realizar uma rotao simples para a direita;

Tipo II : Se a sub-rvore esquerda maior que a sub-rvore direita (FB > 1), e a sub-rvore esquerda desta sub-rvore esquerda me-

90

ESTRUTURA DE DADOS

nor ou igual que a sub-rvore direita, ento realizar uma rotao dupla para a direita;

Tipo III: Se a sub-rvore esquerda menor que a sub-rvore direita (FB < -1), e a sub-rvore direita desta sub-rvore direita menor ou igual que a sub-rvore esquerda dela, ento realizar uma rotao dupla para a esquerda;

Tipo IV: Se a sub-rvore esquerda menor que a sub-rvore direita (FB < -1), e a sub-rvore direita desta sub-rvore direita maior que a sub-rvore esquerda dela, ento realizar uma rotao simples para a esquerda.

A partir das situaes apresentadas, qualquer tipo de desbalanceamento pode ser corrigido aplicando uma das 4 rotaes descritas. Exemplo Comeando a partir de uma rvore vazia, so inseridos os nmeros de (1), (4) e (7). O primeiro problema acontece na insero do (7): a propriedade

ESTRUTURA DE DADOS

91

de balanceamento violada na raiz. Para resolver executada uma rotao simples a esquerda.

A seguir inserida a chave (9), sem prejuzo do balanceamento da rvore. A insero do (8) provoca uma nova violao no n (7) (e tambm na raiz da rvore). Repare que neste caso uma rotao simples a esquerda no resolve o problema.

O desbalanceamento no n (7) resolvido em dois passos, atravs de uma rotao dupla a esquerda. No primeiro passo realizada uma rotao simples a direita envolvendo a sub-rvore do n desbalanceado. J no segundo passo, uma rotao a esquerda envolvendo o n desbalanceado devolve o balanceamento rvore.

A insero do (12) provoca o desbalanceamento da raiz desde que a sub-rvore esquerda de altura 0, enquanto que a direita tem altura 2. para resolver executada uma rotao simples a esquerda.

92

ESTRUTURA DE DADOS

Como resultado da rotao, o n com a chave (8) se torna a nova raiz da rvore, e com isso, a sua sub-rvore esquerda (7) se transforma na nova sub-rvore direita do (4). Continuando o exemplo, a insero da chave (10) desbalanceia o n (9), desencadeando uma nova rotao dupla a esquerda.

importante salientar que se a rvore no fosse AVL, o resultado das inseres teria gerado uma rvore de altura 5, enquanto que a AVL obtida a partir da mesma sequencia de insero possui altura 2.

1. Considerando que a altura (h) de uma rvore dada pelo caminho mais longo desde a raiz at uma folha, explique com as suas palavras a relao existente entre altura (h) de uma rvore binria e a quantidade (mnima e mxima) de ns. a) Qual a relao entre a altura (h) de uma rvore e o tempo requerido (custo) para encontrar um n? b) Em qual situao a busca em uma rvore binria pode atingir eficincia mxima?
ESTRUTURA DE DADOS

93

2. Defina uma rvore AVL estabelecendo as suas propriedades, vantagens e desvantagens da sua utilizao. 3. Dada a seguinte rvore (binria de busca) AVL, simule o processo de insero e remoo das seguintes chaves na rvore na ordem dada: insero 25 - insero 70 - insero 15 - insero 12 - insero 18 - remoo 15. Verifique a cada passo se a propriedade de balanceamento continua sendo mantida. Em caso de desbalanceamento, indicar o n desbalanceado e as operaes de rotao indicadas para resolver o problema.

4. Considerando a seguinte sequncia de caracteres: A, Z, B, Y, C, X, D, P, E, V, F. Simule a construo passo a passo de uma rvore AVL de caracteres, e indique em que situaes ocorrem rotaes simples ou duplas, direita ou esquerda, dos vrios elementos da rvore. 5. Considerando a seguinte sequncia de nmeros: insero 50, insero 20, insero 30, insero 25, insero 10, insero 15, remoo 20, insero 20, insero 40. Simule a construo passo a passo de uma rvo re AVL de nmeros com a sequncia acima, e indique em que situaes ocorrem rotaes simples ou duplas, direita ou esquerda, dos vrios elementos da rvore.

Nesta unidade foram apresentados os conceitos fundamentais sobre rvores e rvores binrias. O TAD rvore Binria de Busca foi definido e implementado, e alguns exemplos de utilizao foram ilustrados, assim como os diferentes percursos possveis sobre a estrutura. Adicionalmente, a conceituao sobre rvores binrias balanceadas, e sua importncia em relao ao aumento no desempenho das operaes realizadas foi relatada. A propriedade de balanceamento e as estratgias para restabelecer o equilibrio na rvore foram detalhados e ilustrados.

94

ESTRUTURA DE DADOS

AHO, J.E. Hopcroft, and J.D. Ullman. Data structures and algorithms. Addison-Wesley, Reading, Mass., 1983. CORMEN T. H., LEISERSON C. E., RIVEST R. L., STEIN C. (2001). Introduction to Algorithms. McGraw-Hill e The Mit Press. HOROWITZ and S. Sahni (1987). Fundamentals of data structures, Computer Science Press. Editora Campus. KNUTH D. E. (1968). The Art of Computer Programming, Vol. 1: Fundamental Algorithms. Addison-Wesley. SZWARCFITER J. l., MARKENZON L. (2010). Estruturas de Dados e Seus Algoritmos. 3. Edio. LTC. ZIVIANI N. (2005). Projeto de Algoritmos com implementaes em Pascal e C, 2da. Edio. Thomson.

ESTRUTURA DE DADOS

95

Unidade

Busca avanada

Objetivos:
A eficincia alcanada para resolver o problema da busca ou recuperao de informao a partir de uma estrutura de dados um indicador da eficincia da estrutura. Nesta unidade so apresentados mtodos especficos de busca que objetivam reduzir a complexidade em relao aos mtodos de busca padro apresentados em unidades anteriores. Em particular, apresentado o uso de tabelas de ndices que possibilitam o acesso direto informao, idealmente. No domnio especifico de tratamento de cadeias a busca digital apresentada como soluo para o problema de casamento de padres. Finalmente, o funcionamento de estruturas auto-ajustveis descrito.

Captulo 1
Tabela de disperso

O armazenamento e recuperao da informao so possivelmente as funcionalidades mais importantes requeridas de um computador. De forma geral, a informao organizada em estruturas que possibilitam que os dados possam ser recuperados da memria e interpretados quando necessrio. A pesquisa por um determinado dado requer que seja estabelecido um critrio, que geralmente baseado na existncia de uma chave de pesquisa que possibilita que ocorrncias da informao sejam corretamente identificadas. Diversas estratgias podem ser utilizadas para realizar uma pesquisa por registros em uma tabela. A escolha pela mais adequada depende principalmente das necessidades e caractersticas da aplicao especfica. Os dois principais fatores que influenciam nesta escolha so o tamanho da entrada, ou seja a quantidade de elementos a serem processados e as operaes mais frequentemente executadas sobre a estrutura. Existem diversos mtodos de pesquisa amplamente utilizados. Dentre eles, a pesquisa sequencial o mtodo mais simples onde, a partir do primeiro registro, a pesquisa realizada em forma sequencial seguindo a ordem apresentada pelos elementos. O processo continua at que a chave for encontrada ou a tabela for percorrida completamente sem sucesso. Esta estratgia foi utilizada no mtodo de busca implementado no TAD Lista. O esforo requerido nesta busca O(n), uma vez que no pior cenrio, a lista precisar ser percorrida na sua totalidade. A rvore de busca e suas variantes abordada na Unidade 4 uma estrutura de dados muito eficiente para armazenamento e recuperao de informao. Neste caso, o custo demandar em mdia O(log n). Tanto a pesquisa sequencial como a aplicada em rvores de busca, so baseadas na comparao entre chaves. Diferentemente, a tcnica baseada em transformao de chave ou hashing utiliza uma funo de transformao aritmtica a partir da qual uma chave mapeada para um endereo de memria utilizando as chamadas tabelas de disperso ou tabelas de hash . A seguir o funcionamento da tabela de disperso apresentado. Seja, por exemplo, a distribuio de expedientes de funcionrios de uma empresa ao longo de um arquivo de pastas, onde cada pasta indica a inicial do sobrenome do funcionrio. A principio considerado que no existe ordem para a colocao dos expedientes dentro de cada pasta do arquivo. Nesse caso o sobrenome seria a chave e a inicial o endereo de armazenamento. Em cincia da computao a tabela de disperso (de hashing, no ingls), uma estrutura de dados especial, que associa chaves de pesquisa a valores. Seu objetivo , a partir de uma chave simples, fazer uma busca rpida e obter o valor desejado em tempo constante.

A chave de pesquisa o campo do registro a partir do qual o registro pode ser referenciado de forma unvoca. Cada registro no conjunto possui um campo chave nico o que possibilita a sua identificao a partir dele.

ESTRUTURA DE DADOS

99

A utilizao de tabela de disperso para o armazenamento e recuperao da informao visa tornar estas operaes mais eficientes em termos de esforo, em relao aos outros mecanismos de busca estudados, alcanando uma complexidade mdia de O(1). O ganho com relao a outras estruturas associativas (como um vetor simples) passa a ser maior conforme a quantidade de dados aumenta. Em contrapartida, em uma tabela de disperso virtualmente impossvel estabelecer uma ordem para os elementos. Em outras palavras, a funo de disperso estabelece uma indexao sobre as chaves mas no preserva a ordem entre elas. O mtodo de pesquisa com uso de transformao de chave envolve duas etapas. 1. Desenvolver e aplicar a funo de transformao aritmtica do valor da chave para um endereo na memria.
A ocorrncia de colises pode ser abordada do ponto de vista probabilistico. O paradoxo do aniversrio estabelece que, se tomadas aleatoriamente 50 pessoas, pelo menos duas pessoas teriam a mesma data de aniversrio ou coliso.

2. Dependendo da quantidade de chaves e da eficincia da funo de transformao na gerao de endereos, pode ser necessrio elaborar uma estratgia de tratamento para colises para tratar os casos em que duas chaves gerem o mesmo endereo. Considere a existncia de n chaves a serem armazenadas na tabela T, de dimenso m. A tabela considerada uma estrutura sequncial, portanto as posies ou endereos se encontram no intervalo [0, m 1]. Se o nmero de chaves n for igual ao nmero de posies na tabela, m, e, alm disso, os valores das chaves forem de 0 a m 1, ento, cada chave x poderia ser armazenada no endereo x correspondente. Tabelas de disperso so tipicamente utilizadas para indexao de grandes volumes de informao, tais como bases de dados. Outros exemplos de uso das tabelas de disperso so as tabelas de transposio em jogos de xadrez para computador.

A funo de disperso
A funo de disperso a responsvel por gerar um ndice a partir de determinada chave. A definio da funo de fundamental importncia, uma vez que se no for adequada para o tratamento dos dados em questo, a manipulao da tabela ter um mau desempenho. O ideal para a funo de disperso que sejam sempre fornecidos ndices nicos para as chaves de entrada. A funo perfeita seria a que, para quaisquer entradas A e B, sendo A diferente de B, fornecesse sadas diferentes. Quando as entradas A e B so diferentes e, passando pela funo de disperso, geram a mesma sada, acontece uma coliso. De forma simplificada temos que: Pos (elemento) = H (elemento, n), onde H a funo de disperso aplicada ao elemento, considerando o tamanho n da tabela.

100

ESTRUTURA DE DADOS

No exemplo, a funo de disperso aplicada sobre a chave nome, para obter um ndice de acesso ao vetor onde o registro armazenado. O registro pode agregar vrios campos de informao, alm do campo chave. No entanto, na prtica, difcil encontrar uma funo de disperso perfeita que consiga espalhar de forma uniformemente esparsa as chaves ao longo da estrutura. Dando sequncia ao exemplo acima, a aplicao da funo de disperso para o nome Luiza pode vir a gerar o mesmo ndice do que Luiz (790 ), provocando uma coliso. Esta situao indesejvel uma vez que reduz o desempenho do sistema. No entanto muito comum acontecer, por isso que diversas tcnicas de tratamento de colises tem sido propostas na literatura. Exemplo de funo de disperso Uma funo de disperso muito simples envolve transformar um caracter em um valor numrico. Isto, na linguagem C, poderia ser feito da seguinte forma: int hashExemplo(char *chave) { return (chave[0]-65); } Dada sua simplicidade esta funo causaria muitas colises, no entanto pode ser utilizada como parte de uma funo mais complexa que possibilite um melhor espalhamento dos dados.

Na prtica, funes de disperso perfeitas ou quase perfeitas so encontradas apenas onde a coliso intolervel, como por exemplo em aplicaes de criptografia, ou quando o contedo da tabela armazenada conhecido previamente.

ESTRUTURA DE DADOS

101

1. Defina o conceito de tabela de disperso e descreva o processo envolvido na aplicao desta tcnica. 2. Estabelea vantagens e desvantagens em relao a outros mecanismos de armazenamento e recuperao de informao. 3. Pesquise na literatura sobre funes de disperso comumente utilizadas e que tem demostrado desempenho aceitvel. a) Mtodo da diviso b) Mtodo da dobra 4. Apresente um exemplo prtico de gerao de uma tabela de disperso utilizando os mtodos pesquisados no item anterior. O tratamento das colises envolve geralmente a utilizao de alguma outra estrutura de dados em conjuno com as tabelas de disperso, tal como uma lista encadeada ou at mesmo rvore rvores balanceadas (AVL). Em outras oportunidades a coliso solucionada dentro da prpria tabela.

Estratgias para resoluo de colises


Considerando que a ocorrncia de colises praticamente inevitvel, um bom mtodo de resoluo de colises essencial, independentemente da qualidade da funo de disperso utilizada. H diversos algoritmos de resoluo de coliso, mas os mais conhecidos so os de encadeamento e sondagem.

Encadeamento
A utilizao de listas encadeadas a soluo mais simples para o tratamento de colises. Neste caso, a partir do ndice em conflito mantido um ponteiro para uma lista encadeada onde so armazenados os registros em conflito. A insero na tabela requer e insero dentro da lista encadeada. Analogamente, a remoo requer atualizar os ndices dentro da lista. O TAD lista na sua verso encadeada atravs de ponteiros foi apresentado na Unidade 3. Graficamente, a soluo de colises atravs de listas encadeadas representada a seguir. A situao de coliso entre as chaves Luiz e Luiza seria resolvida adicionando o registro correspondente chave repetida na lista associada ao ndice.

102

ESTRUTURA DE DADOS

Esta soluo adiciona um nvel de indireo s operaes de insero e recuperao da informao, uma vez que o registro no mais acessado diretamente a partir da chave, no entanto, o custo de acesso continua se mantendo baixo. Estruturas de dados alternativas podem ser utilizadas no lugar das listas encadeadas. Por exemplo, a partir da utilizao de rvores binrias balanceadas (AVL) possvel melhorar o tempo mdio de acesso da tabela disperso para O(log n) ao invs de O(n) demandado no caso da utilizao de listas.

Tcnicas de sondagem
Em contrapartida tcnica de encadeamento, as tcnicas de sondagem para o tratamento de colises no fazem uso de nenhuma estrutura auxiliar para o armazenamento da informao. Em caso de coliso, os registros em conflito so armazenados dentro da prpria tabela, utilizando buscas padronizadas at encontrar um registro vazio ou o registro buscado. Outras formas mais complexas de implementar a tcnica de sondagem consiste em determinar a posio do novo elemento em coliso a partir de uma funo quadrtica, incrementando o ndice exponencialmente. Desta forma, caso a chave procurada no se encontre na posio 10, em uma segunda tentativa ser procurada na posio 100, 1000, e assim por diante. Uma terceira possibilidade envolve a aplicao de uma nova funo de disperso (tambm chamado de double hashing), cuja chave de entrada ser o valor gerado pela funo anterior. Esta soluo pode ser til em casos muito especficos, com enormes quantidades de dados, no entanto a sobrecarga no sistema nem sempre justifica a experincia.

ESTRUTURA DE DADOS

103

1. Explique o conceito de coliso e por que acontecem. 2. Pesquise as diferentes formas de resoluo de coliso e analise suas vantagens e desvantagens. Exemplifique.

104

ESTRUTURA DE DADOS

Captulo 2
Busca digital

O problema de busca geralmente considera a comparao entre uma chave desejada e as chaves que compem um conjunto, que pode ser estruturado de formas convenientes no intuito de melhorar o desempenho das operaes. Diferentemente, no caso da busca digital, a chave constituida de um conjunto de caracteres ou dgitos pertencentes a um alfabeto apropriado. Neste caso especfico, a comparao entre chaves realizada dgito a dgito, individualmente. A busca digital funciona de forma similar busca em dicionrios, decompondo a palavra letra a letra (caracter ou dgito), onde a primeira letra da palavra determina um ndice de pgina onde se encontram as palavras iniciadas por aquela letra. Os mtodos de busca digital so particularmente teis quando as chaves so grandes e de tamanho varivel. A partir desta pesquisa possvel localizar todas as ocorrncias de uma determinada cadeia em um texto, com tempo de resposta O(log n) em relao ao tamanho do texto. Este problema conhecido como casamento de cadeias, no contexto de processamento de cadeias de caracteres. O processamento de cadeias de caracteres envolve duas classes de problemas: casamento de cadeias (do ingls, pattern matching) e compresso de cadeias. O problema de casamento de cadeias envolve a procura pela ocorrncia de um determinado padro em um texto que est sendo editado. Formalmente, o texto T considerado um vetor de tamanho n e o padro P um vetor de tamanho m, com m < = n . Os elementos que compem T e P pertencem a um alfabeto finito de tamanho c. Dadas duas cadeias T e P, deseja-se saber as ocorrncias de P em T. A compresso de texto est relacionada com a representao de um texto original de forma a ocupar menos espao, ou seja utilizando um nmero menor de bits. Mtodos mais modernos de compresso de cadeias possibilitam o acesso direto a texto comprimido sem necessidade de descomprimir o texto, permitindo melhorar a eficincia de sistemas de recuperao de informao e aumentar a economia de espao. No, mtodo de busca digital, tanto o padro procurado quanto o texto so pr-processados a partir da construo de ndices de forma a reduzir a complexidade das operaes para um custo O(log n). No entanto, o tempo de pr-processamento compensado por muitas operaes de busca. A seguir so apresentados brevemente os tipos de ndices mais conhecidos para o pr-processamento de cadeias de forma a agilizar o desempenho das buscas.

As cadeias aparecem no processamento de texto em linguagem natural, dicionrios, sequenciamento de DNA, processamento de imagens, etc. Em cada domnio, um alfabeto especfico utilizado. Exemplos de alfabetos: {0, 1}, {a, b, c, ..., z}, {0, 1, ... 9}.

ESTRUTURA DE DADOS

105

rvore digital
A estrutura mais apropriada para realizar a busca digital atravs da rvore digital. Formalmente, uma sequncia S = {s1, ..., sn} um conjunto de n chaves em que cada si formada por uma sequncia de elementos dj denominados dgitos. Supe-se que existe em S o total de m dgitos distintos que determinam o alfabeto ordenado de S. Os primeiros p dgitos de uma chave compem o prefixo de tamanho p da chave. Uma rvore digital para S uma rvore m-ria T, no vazia, tal que: 1. Se o n v o j-ssimo filho de seu pai, ento v corresponde ao dgito dj do alfabeto S, 1 <= j <= m. 2. Para cada n v, a sequncia de dgitos definida pelo caminho desde a raiz de T at v corresponde a um prefixo de alguma chave de S. Na anlise de um texto em linguagem natural, S seria o conjunto de frases do texto, onde si cada frase que pode ser buscada e n o nmero de frases, e m = 26. Em um caso especfico da rvore digital, no entanto o mais utilizado, temos a rvore digital binria, onde o grau da rvore m = 2. O alfabeto considerado neste caso {0, 1}. A partir da construo da rvore digital com estas caractersticas, as chaves a serem consideradas nas buscas envolvem sequncias binrias.
Chaves 00 0010 010 010111 010110 00100 11 110 1101 rvore digital binria

A partir da rvore gerada possvel observar que algumas chaves binrias so prefixos de outras chaves pertencentes mesma coleo. Por exemplo, o caminho da raiz at o n com contedo correspondente chave 010 que prefixo da chave 010110 correspondente ao caminho at o n . Cada n na rvore pertence a uma chave (ou mais) do conjunto. Por exemplo o n com corresponde chave 010, e faz parte (prefixo) das chaves 010111 e tambm 010110. De acordo com a implementao da rvore digital, cada n na rvore envolve um campo adicional contendo um ponteiro para a informao correspondende chave detectada. Por exemplo, no caso do n existiria um ponteiro de forma a localizar no texto a chave 010. Os ponteiros de ns que no correspondem ao ltimo dgito de uma chave vlida seriam nulos (NULL).

106

ESTRUTURA DE DADOS

Uma vez criada a rvore, a busca acontece como resultado do percurso a partir da raiz: o filho esquerdo representa o dgito 0 e o filhor direita representa o dgito 1. Note que a busca localiza no somente uma chave vlida completa, mas tambm prefixos. A busca por prefixos pode ser de grande utilidade dependendo da aplicao, como por exemplo lingustica.

1. Explique como funciona a busca digital e seu papel no contexto de processamento de cadeias. Mencione reas de aplicao deste tipo de busca. 2. Pesquise sobre compresso de textos em linguagem natural. 3. Crie graficamente uma rvore digital binria a partir do seguinte conjunto de chaves: 00, 0000, 00010, 00011, 0101100, 0101101, 10, 101, 1010.

ESTRUTURA DE DADOS

107

Captulo 3
Estruturas autoajustveis

As operaes de insero e remoo de elementos aplicadas sobre uma determinada estrutura de dado afetam necessariamente a forma da estrutura. J a operao de busca inocua no sentido em que, a principio, no produz nenhuma alterao na forma da estrutura. No caso de estruturas autoajustveis, a operao de busca pode alterar a forma da estrutura de dado objetivando melhorar o desempenho em buscas futuras. Por exemplo, no caso de ser detectada certa frequncia na procura por um determinado componente em uma lista ou rvore, a posio ou nvel do componente na lista ou na rvore, respectivamente, pode ser alterado, de forma a agilizar as futuras buscas pelo mesmo componente. A partir deste comportamento, a complexidade ordinria de uma operao calculada individualmente, e de forma independente, para o pior caso na sua execuo no mais adequada. Em contrapartida, a complexidade amortizada considera a configuraes da estrutura ao longo de uma sequncia de operaes executadas, avaliando as consequncias de cada execuo, de forma acumulada. O conceito de autoajuste pode ser aplicado a diversas estruturas de dados, tais como listas, conjuntos e rvores.

Listas autoajustveis
O TAD Lista foi abordado na Unidade 3. Como foi visto, o tipo lista pode ser implementado utilizando a abordagem de alocao de memria esttica (vetores) ou dinmica (ponteiros). Considerando que na sua verso mais simples no estabelecido um critrio de ordenao entre os elementos, alguns elementos na lista podem ser requisitados mais frequentemente do que outros. A partir desta constatao, uma lista autoajustvel implementa estratgias para reduzir o tempo de acesso em operaes subsequentes. A estratgia geral consiste em posicionar os ns mais procurados mais prximos do inicio da lista, de forma que em futuras buscas possam ser alcanados mais rapidamente. Esta estratgia pode ser implementada utilizando diversos mtodos. O mtodo de mover para frente transfere o n procurado para o inicio da lista. Repare que dependendo da implementao utilizada para implementar a lista, esta operao pode ser custosa. Por outro lado, ns com baixa probabilidade de acesso podem ser eventualmente acessados, tornando mais custosas as buscar por ns com maior probabilidade. No mtodo de transposio uma vez acessado o n procurado, este transferido para a posio imediatamente anterior. Na medida em que o n for acessado, mais prximo do inicio ser posicionado. A implementao do mtodo de contador de frequncias envolve a incorporao de um campo adicional na estrutura do n da lista, responsvel

108

ESTRUTURA DE DADOS

por manter o nmero de acessos efetuados ao respectivo n. Este campo utilizado como chave para a ordenao decrescente dos elementos na lista. Ou seja que os ns mas frequentemente acessados so localizados no inicio, e portanto mais rapidamente alcanados. Alguns mtodos hbridos envolvem a combinao dos mtodos anteriores de forma a tirar vantagem dos beneficios e reduzir as desvantagens dos mtodos no seu formato individual.

1. Explique o funcionamento das estruturas de dados autoajustveis. 2. Quais seriam as adaptaes requeridas para que o TAD Lista apresentado na Unidade 3 se torne TAD Lista Autoajustvel? a) Defina a nova estrutura de dados. b) Implemente ou adapte as operaes necessrias. 3. Pesquise sobre uma outra estrutura estudada ao longo desta disciplina que possa se tornar autoajustvel. Descreva as caractersticas de funcionamento e as adaptaes necessrias.

Nesta unidade foram apresentadas diversas estratgias para armazenamento e recuperao de informao. Inicialmente foram apresentadas as tabelas de disperso ou hash , como uma soluo para o acesso direto ou semidireto informao a partir da gerao de ndices, obtidos como resultado de um processo de transformao tendo como base o valor chave do registro. Mecanismos de tratamento de colises no caso de gerao de ndices repetidos foram indicados. Em relao ao processamento de cadeias de caracteres, foi apresentada a teoria sobre busca digital, que possibilita estabelecer o casamento de chaves, constitudas por caracteres ou dgitos, e texto. Com este objetivo, a estrutura de rvore digital foi apresentada. Finalmente, o funcionamento de estruturas autoajustveis, com foco na sua exemplificao atravs de listas foi descrito, indicando as estratgias de implementao a serem seguidas. De forma geral, todos estes mecanismos e estratgias objetivam tornar mais eficiente o armazenamento e posterior recuperao da informao, de forma a tornar os algoritmos mais acessveis e capazes de lidar melhor com a complexidade cada vez maior requerida pelas aplicaes atuais.

ESTRUTURA DE DADOS

109

AHO, J.E. Hopcroft, and J.D. Ullman. Data structures and algorithms. Addison-Wesley, Reading, Mass., 1983. CORMEN T. H., LEISERSON C. E., RIVEST R. L., STEIN C. (2001). Introduction to Algorithms. McGraw-Hill e The Mit Press. HOROWITZ and S. Sahni (1987). Fundamentals of data structures, Computer Science Press. Editora Campus. KNUTH D. E. (1968). The Art of Computer Programming, Vol. 1: Fundamental Algorithms. Addison-Wesley. SZWARCFITER J. l., MARKENZON L. (2010). Estruturas de Dados e Seus Algoritmos. 3. Edio. LTC. ZIVIANI N. (2005). Projeto de Algoritmos com implementaes em Pascal e C, 2da. Edio. Thomson.

Mariela Ins Corts


doutora em Informtica pela Pontifcia Universidade Catlica do Rio de Janeiro (2003) e mestre em Sistemas de Computao pelo Intituto Militar de Engenharia do Rio de Janeiro (1999). Sua alma mater a Universidade Nacional de La Plata, onde completou os estudos de graduao em Cincias da Computao. Especialista na rea de Engenharia de Software, atualmente professora adjunta na Universidade Estadual do Cear, vinculada ao Curso de Cincias da Computao, onde ministra dentre outras, a disciplina de Estrutura de Dados. Adicionalmente, coordena o Laboratrio de Qualidade e Padres de Software (LAPAQ) e lidera o Grupo de Engenharia de Software e Sistemas Inteligentes (GESSI).

Enyo Jos Tavares Gonalves


Meste em Cincia da Computao pela Universidade Estadual do Cear, Bacharel em Cincia da Computao pela Universidade Estadual do Vale do Acara e Sun Certified Programmer for the Java 2 Platform 1.4. Tem interesse em pesquisa em Engenharia de Software para Siste mas Multi-Agentes(SMAs), mais especificamente envolvendo os seguintes temas: Modelagem de SMAs, Frameworks de SMAs e Testes de SMAs. Atualmente Professor Assistente Nvel 1 da Universidade Federal do Cear e Co-orienta alunos de mestrado e graduao da Universidade Estadual do Cear. Atuou profissionalmente como desenvolvedor de sistemas pelo instituto Atlntico, como professor do curso de Cincias da COmputao do Instituto Federal de Educao Cincia e Tecnologia do Cear e da Universidade Estadual do Vale do Acara.

110

ESTRUTURA DE DADOS

Das könnte Ihnen auch gefallen