Você está na página 1de 136

PROF.

MATEUS CONRAD BARCELLOS DA COSTA

TCNICAS DE PROGRAMAO AVANADA

VITRIA
2008

Governo Federal
Ministro de Educao
Fernando Haddad
CEFETES Centro Federal de Educao Tecnolgica do Esprito Santo
Diretor Geral
Jadir Jos Pela
Diretor de Ensino
Denio Rebello Arantes
Coordenadora do CEAD Centro de Educao a Distncia
Yvina Pavan Baldo
Coordenadoras da UAB Universidade Aberta do Brasil
Yvina Pavan Baldo
Maria das Graas Zamborlini
Designer Instrucional
Danielli Veiga Carneiro
Curso de Tecnologia em Anlise e Desenvolvimento de Sistemas
Coordenao de Curso
Isaura Nobre
Professor Especialista/Autor
Mateus Conrad Barcellos da Costa
DIREITOS RESERVADOS
Cefetes Centro Federal de Educao Tecnolgica do Esprito Santo
Av. Vitria - Jucutuquara - Vitria - ES - (27) 3331.2139
Crditos de autoria da editorao
Capa: Leonardo Tavares Pereira
Projeto grfico: Danielli Veiga Carneiro
Iconografia: Moreno Cunha
Editorao eletrnica: Mateus Conrad B. da Costa, Humberto Wanke, Monia Vignati
Reviso de texto: Karina Bersan Rocha
COPYRIGHT proibida a reproduo, mesmo que parcial, por qualquer meio, sem
autorizao escrita dos autores e do detentor dos direitos autorais.
Catalogao na fonte: Rogeria Gomes Belchior - CRB 12/417
1.
C837

Costa, Mateus Conrad Barcellos da


Tcnicas de programao avanada. / Mateus Conrad Barcellos da. Vitria:
CEFETES, 2008.
132 p. : il.
1. Programao (Computadores). I. Centro Federal de Educao Tecnolgica do
Esprito Santo. II. Ttulo.
CDD 005.1

Ol, Aluno(a)!

um prazer t-lo conosco.


O Cefetes oferece a voc, em parceria com as Prefeituras e com o
Governo Federal, o Curso Tecnologia em Anlise e Desenvolvimento
de Sistemas, na modalidade a distncia. Apesar de este curso ser
ofertado a distncia, esperamos que haja proximidade entre ns, pois,
hoje, graas aos recursos da tecnologia da informao (e-mails, chat,
videoconferncia, etc.) podemos manter uma comunicao efetiva.
importante que voc conhea toda a equipe envolvida neste curso:
coordenadores, professores especialistas, tutores a distncia e tutores
presenciais, porque quando precisar de algum tipo de ajuda, saber a
quem recorrer.
Na EaD Educao a Distncia, voc o grande responsvel pelo
sucesso da aprendizagem. Por isso, necessrio que se organize para
os estudos e para a realizao de todas as atividades, nos prazos
estabelecidos, conforme orientao dos Professores
Especialistas e Tutores.
Fique atento s orientaes de estudo que se encontram
no Manual do Aluno!
A EaD, pela sua caracterstica de amplitude e pelo uso de
tecnologias modernas, representa uma nova forma de aprender,
respeitando, sempre, o seu tempo.
Desejamos-lhe sucesso!

Equipe do CEFETES

ICONOGRAFIA

Veja, abaixo, alguns smbolos utilizados neste material para gui-lo em seus estudos.

Fala do professor.

Conceitos importantes. Fique atento!

Atividades que devem ser elaboradas por voc, aps a leitura dos textos.

Indicao de leituras complementares, referentes ao contedo estudado.

Destaque de algo importante, referente ao contedo apresentado. Ateno!

Reflexo/questionamento sobre algo importante, referente ao contedo


apresentado.

Espao reservado para as anotaes que voc julgar necessrias.

Sumrio
1.

ABSTRAO DE DADOS.......................................................................................................................... 9
1.1
INTRODUO .......................................................................................................................................... 9
1.2
CONCEITOS DE ABSTRAO DE DADOS ................................................................................................. 12
1.2.1 Abstrao em Computao.............................................................................................................. 12
1.2.2 Abstrao de Procedimentos ........................................................................................................... 14
1.2.3 Tipos Abstratos de Dados................................................................................................................ 16
1.2.4 Implementao de Tipos Abstratos de Dados.................................................................................. 23
1.2.5 Avaliao de Implementaes de Tipos Abstratos de Dados .......................................................... 25

2.

TIPOS ABSTRATOS DE DADOS FUNDAMENTAIS. ......................................................................... 30


2.1
PILHAS .................................................................................................................................................. 30
2.1.1 Especificao do TAD Pilha............................................................................................................ 32
2.1.2 Implementao de Pilhas em Arranjos............................................................................................ 34
2.2
FILAS .................................................................................................................................................... 37
2.2.1 Especificao do TAD FILA............................................................................................................ 39
2.2.2 Implementao de Filas em arranjos com deslocamento................................................................ 42
2.2.3 Implementao de Filas com Arranjos circulares........................................................................... 45
2.3
IMPLEMENTAO DE TADS COM ALOCAO DINMICA DE MEMRIA ................................................. 47
2.3.1 Reviso de Alocao Dinmica de Memria................................................................................... 47
2.3.2 Implementao do TAD Pilha ......................................................................................................... 55
2.3.3 Implementao do TAD Fila ........................................................................................................... 59

3.

LISTAS E RVORES................................................................................................................................ 65
3.1
LISTAS CIRCULARES ............................................................................................................................. 65
3.2
LISTA CIRCULAR DUPLAMENTE ENCADEADA ....................................................................................... 75
3.3
RVORES BINRIAS.............................................................................................................................. 82
3.3.1 rvore Binria de Pesquisa............................................................................................................. 83
3.3.2 O TAD rvore Binria de Pesquisa ................................................................................................ 84
3.3.3 Implementao do TAD rvore Binria de Pesquisa ...................................................................... 85

4.

PESQUISA EM MEMRIA PRIMRIA................................................................................................ 99


4.1
PESQUISA SEQENCIAL ...................................................................................................................... 101
4.1.1 Implementao da Pesquisa Seqencial........................................................................................ 102
4.1.2 Tempo de execuo de algoritmos................................................................................................. 103
4.2
PESQUISA BINRIA ............................................................................................................................. 106
4.3
TABELAS HASH................................................................................................................................... 108
4.3.1 Operaes de Insero e Pesquisa em Tabelas Hash.................................................................... 111
4.3.2 Tratamento de Colises ................................................................................................................. 114
4.3.3 Tratamento de Coliso usando endereamento Aberto................................................................. 116

5.

ORDENAO EM MEMRIA PRIMRIA. ...................................................................................... 118


5.1
CONCEITOS BSICOS DE ORDENAO ................................................................................................ 118
5.1.1 Operaes Tpicas de processos de Ordenao ............................................................................ 119
5.2
MTODOS DE ORDENAO ................................................................................................................. 119
5.2.1 Ordenao por Seleo ................................................................................................................. 120
5.2.2 Mtodo da Insero ....................................................................................................................... 121
5.2.3 Mtodo da Bolha ........................................................................................................................... 123
5.2.4 Desempenho dos mtodos de Seleo, Insero e Bolha............................................................... 124
5.2.5 Mtodo de Shell ............................................................................................................................. 124
5.2.6 O Mtodo Quicksort ...................................................................................................................... 128

Ol!
Meu nome Mateus Barcellos Costa, sou professor
e pesquisador do CEFET-ES desde 2005. Atuo na
rea de Engenharia de Software e sou professor de
disciplinas de Programao. Se voc quiser mais
informaes sobre mim e sobre os trabalhos que
desenvolvo, pode visitar minha pgina pessoal em
http://www.sr.cefetes.br/~mcosta.
Produzi o material que ora lhe apresento como
instrumento bsico para o estudo da disciplina de
Tcnicas de Programao Avanada. Nesta
disciplina
iremos
aprofundar
nossos
conhecimentos
em
Programao
de
Computadores usando uma linguagem imperativa
ou procedimental. Exemplos destas linguagens
so C e Pascal. Como de costume no nosso
Curso, iremos adotar a linguagem C, em nossos
exemplos e implementaes. No entanto,
preciso que voc saiba que os conceitos estudados
aqui vo alm da linguagem e podem ser
aplicados em diversos cenrios, na programao
e na Engenharia de Software como um todo.

Tcnicas de Programao Avanada

1. ABSTRAO DE DADOS.

Ol! Neste Captulo iremos discutir e aprender


sobre Abstrao de Dados. Abstrao de Dados
uma tcnica de programao que visa simplificar
o desenvolvimento de programas. Sua aplicao
pode se dar no desenvolvimento de programas
menores. Mas podemos afirmar que seria
impossvel o desenvolvimento de sistemas que
temos hoje, com milhes de linhas de cdigo,
sem o uso de abstrao de dados.

1.1 INTRODUO
Um programa de computador desenvolvido para atender alguma
finalidade prtica , normalmente, um artefato complexo. Por esse
motivo, a atividade de desenvolvimento desses artefatos, a
programao de computadores, est entre as atividades mais
complexas desempenhadas pelo homem. Se voc cursou disciplinas
introdutrias de programao, pode estar se questionando:  Ora,
desenvolver um programa no to complexo assim! Basta
compreender o problema, suas entradas e suas sadas e construir a
soluo usando uma linguagem de programao. Simples no? No!
A histria da programao tem dado provas que programar no to
simples assim.

Figura 1: O Gap Semntico.

Programar uma atividade complexa por diversos aspectos, tanto de


cunho terico quanto prtico. Dentre estes aspectos destacamos os
seguintes:
1. Programar um computador significa desenvolver programas de
computadores (formais e precisos) para atender a finalidades

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 9

Tcnicas de Programao Avanada


prticas definidas em termos de conceitos do mundo real
(informais e imprecisos). Existe um abismo entre o mundo
dos problemas reais e o mundo das solues. Esse abismo
chamado na computao de gap semntico. Transpor o abismo
um dos desafios centrais da programao de computadores e
da Engenharia de Software como um todo. A Figura 1 uma
alegoria que busca mostrar a funo do desenvolvedor de
software: Transpor o abismo entre o mundo informal (dos
problemas) e o mundo formal (das solues computacionais).
Nessa transposio existem muitos desafios e perigos que
podem dificultar a trajetria do desenvolvedor.
2. Muitas vezes, em disciplinas iniciais de programao,
deparamo-nos com o desenvolvimento de programas mais
simples, de cunho didtico. Por exemplo, programas para
calcular mdias ou somatrios. Em outros momentos fazemos
programas para aprender a usar um certo mecanismo, por
exemplo, apontadores. Aqui, estamos nos referindo a
programas de computadores para ajudar pessoas a resolverem
problemas do mundo real, problemas grandes e complexos!
Exemplos desses problemas incluem:
a. Gerenciar as operaes financeiras de uma empresa;
b. Controlar uma aeronave;
c. Controlar os trens de uma malha ferroviria;
d. Produzir edies dirias de um jornal;
e. Gerenciar o processo de produo de um filme.
3. Problemas como esses no so simples de se resolver.
Conseqentemente, programas voltados para essas finalidades
so complexos, levam muito tempo para ficar prontos, tm de
ser desenvolvidos por uma equipe de pessoas, utilizando
diversas tecnologias e seguindo um processo de
desenvolvimento sistemtico.
4. Para atender s funcionalidades esperadas, um programa deve
apresentar um conjunto de caractersticas que juntas vo
tornar o programa efetivamente til e determinaro a
qualidade do mesmo. Essas caractersticas so as seguintes:
a. Um programa deve estar correto, livre de erros;
b. Um programa deve ser robusto. Um programa robusto
ou sistema robusto aquele que consegue funcionar,
mesmo que precariamente, diante de uma adversidade.
Por exemplo, suponha que um programa precise dos
dados x, y e z para realizar uma tarefa. Se este for
robusto, na falta de um dos dados, o programa pode

Pgina 10

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


tentar realizar o processamento possvel com a
ausncia dado;
c. Um programa deve ser eficiente. A eficincia de um
programa est relacionada ao seu tempo de execuo
(eficincia na execuo) ou ao espao em memria
(eficincia na ocupao) de que necessita para executar
(rea de dados). Para um problema h infinitas
solues (programas). Quanto menores esses valores
mais eficiente o programa. Em computao pode-se
verificar se uma soluo tima (mais eficiente
possvel) para um problema;
d. Um programa deve ser compatvel com outros
programas;
e. Um programa deve ser fcil de usar;
f. Um programa deve ser portvel, podendo funcionar em
diferentes plataformas ou sistemas operacionais;
g. Um programa deve ser ntegro, ou seja, deve evitar que
os dados sejam corrompidos ou violados;
h. O processamento realizado pelo programa deve ser
verificvel;
i. O programa ou partes dele devem poder ser utilizados
em outros cenrios diferentes daquele para o qual o
programa foi originalmente desenvolvido.
5. Por ltimo, devemos considerar a atividade de programao
como atividade econmica. Assim como outras atividades
econmicas, o desenvolvimento de software regido por leis
de mercado que impem severas exigncias aos
desenvolvedores. De acordo com essas leis, no basta apenas
desenvolver um programa que atenda finalidade esperada.
Esses programas devem ser desenvolvidos dentro dos prazos e
custos estabelecidos. Alm disso, o programa precisa ter
outras caractersticas importantes que permitam a sua
evoluo. Essas caractersticas so chamadas de fatores
internos. So eles:
a. Facilidade de manuteno;
b. Facilidade de evoluo;
c. Facilidade de entendimento;
d. Modularidade.
Pelos motivos discutidos acima, o desenvolvimento de programas
requer a aplicao de princpios, mtodos e tcnicas que diminuam a
complexidade desse desenvolvimento. A Abstrao de Dados envolve

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 11

Tcnicas de Programao Avanada


uma srie de conceitos e princpios para esse fim. A seguir
discutiremos esses conceitos.

Atividades
Nesta introduo foram levantados cinco aspectos que
tornam o desenvolvimento de software uma tarefa
difcil. Para atacar esses aspectos e tornar o
desenvolvimento de software mais simples so
consideradas
trs
dimenses:
Processo
de
desenvolvimento, Pessoas (partes interessadas:
clientes, desenvolvedores) e Tecnologias de
desenvolvimento. Releia os cinco motivos e tente
escrever um texto resumido, estabelecendo uma
relao entre esses 5 motivos e essas trs dimenses.

1.2 CONCEITOS DE ABSTRAO DE DADOS


1.2.1 Abstrao em Computao
A abstrao um dos conceitos mais importantes da computao.
Sem o uso deste conceito podemos afirmar que a evoluo
apresentada pela computao teria sido mais lenta.
Segundo o dicionrio Michaelis, temos a seguinte definio para a
palavra Abstrao:
1. O ato ou efeito de abstrair. Considerao das qualidades
independentemente dos objetos a que pertencem. Abstrair: Considerar
um dos caracteres de um objeto separadamente; 2. Excluir, prescindir
de.
A finalidade principal de uso de abstrao em qualquer rea do
conhecimento colocarmos foco em um sub-conjunto dos aspectos
de um sistema ou processo complexo. Considere, por exemplo, o
processo de pintar um quadro. A Figura 2 mostra, esquerda um
esquema inicial mostrando as linhas principais do quadro que se
encontra do lado direito (A Virgem, o Menino e SantAna, Leonardo
Da Vinci).

Pgina 12

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 2: Abstrao na Pintura.

Observe que, no desenho, as propores, os detalhes das posturas e


feies so j determinados. Esse processo ajuda o pintor, pois, no
momento da idealizao do quadro, ele no precisa se preocupar com
outros aspectos complexos, como cores, nuances de sombras e
reflexos, para definir a estrutura e a sua aparncia geral. Podemos
dizer ento que o desenho esquerda uma abstrao do quadro.
Em computao, abstrao tambm possui finalidades semelhantes.
Em programao, especificamente, esse conceito est presente quase o
tempo todo, seja nas construes existentes nas linguagens, seja nos
mtodos de programao empregados.
Uma das principais abstraes das linguagens de programao o
conceito de varivel. Uma varivel um conceito abstrato que
esconde diversos aspectos tcnicos que no interessam ao
programador. Quando declaramos uma varivel em um programa, essa
declarao implica em coisas que no iro interferir no seu
desenvolvimento. Por exemplo, por trs de uma varivel do tipo
inteiro em C, (ex. int x;), esto escondidas as caractersticas fsicas
do armazenamento da varivel em memria, a saber:
-

A forma de representao de nmeros inteiros usando base 2


(por exemplo, complemento de 2);

O padro usado pelo hardware (ex. little endian, big endian);

O nmero de bytes que uma varivel do tipo inteiro ocupa;

O endereo da varivel na memria principal;

O conjunto de bits responsvel por armazenar o sinal do


nmero inteiro.

Para o programador em C, geralmente, nenhuma dessas


informaes importante. O que o programador deseja utilizar a
varivel realizando as operaes permitidas aos nmeros inteiros
(operaes aritmticas e comparaes), atribuir, recuperar e
modificar o valor contido na varivel.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 13

Tcnicas de Programao Avanada


Assim podemos dizer que uma varivel permite ao programador
abstrair-se de detalhes que no interessam e no iro influenciar no
comportamento do programa.

Atividades
Os itens 1,2 e 3 so abstraes. Para cada um deles
descreva os aspectos que esto sendo escondidos e
os aspectos que realmente importam ao
programador:
1. O comando

2. Um arquivo
3. A funo scanf

1.2.2 Abstrao de Procedimentos


Podemos afirmar que a grande maioria dos elementos de linguagem
utilizados em uma linguagem de programao de alto nvel so
abstraes. Essas abstraes facilitaram o desenvolvimento de
programas mais complexos e sofisticados, evitando que
programadores precisassem manipular bits e endereos de memria e
interagir diretamente com o sistema operacional.
Uma outra abstrao de programao importante a Abstrao de
Procedimento.
Abstrao de Procedimento
A abstrao de procedimento permite que o programador crie, ele mesmo, sua forma de abstrair, utilizando
os comandos disponveis na linguagem. A possibilidade
de criar procedimentos permite ao programador criar
funcionalidades mais abstratas que escondem a
sequencia de operaes necessria para a realizao de
uma tarefa complexa.

Pgina 14

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


Por exemplo, sabemos que na linguagem C no existe um comando
que seja capaz de ordenar um vetor de inteiros em ordem crescente.
Seria muito bom que pudssemos contar com esse comando, certo?
Mas, como no temos esse comando, iremos criar uma funo
(abstrao de procedimento) que realize essa tarefa para ns. A funo
ordena na Figura 3 essa abstrao.

Figura 3: Funo ordena: Cria uma abstrao do procedimento de ordenao.

Aps a implementao da funo ordena, quando o programador


precisar ordenar um vetor, basta que ele invoque a funo, passando
os parmetros necessrios. Ou seja, ao usar o procedimento, o
programador ir se preocupar apenas com o que a funo faz e no
mais com os detalhes de sua implementao.
Uma abstrao de procedimento deve realizar uma tarefa (por
exemplo, ordenar um vetor de inteiros) que deve ser independente da
forma como este vai ser implementado. O programador deve antes de
tudo ver o procedimento como uma caixa preta, cuja especificao
deve conter trs elementos bsicos (Figura 4):
x

Entrada: O conjunto de dados de entrada necessrio;

Sada: O conjunto de dados produzido pelo procedimento;

Funo: A descrio do que o procedimento faz.


ENTRADA

FUNO

SADA

Figura 4: Os elementos considerados na definio de um procedimento.

Na especificao do procedimento, o programador no deve estar


preocupado com a implementao, mas sim com o comportamento
(funo) do mesmo. Qualquer implementao que realize a funo
especificada ir servir como soluo. Para o caso da ordenao,
veremos adiante neste curso que existem diferentes mtodos de
ordenar um vetor. O mtodo utilizado na funo ordena se chama
ordenao por insero. A implementao interna poderia ser

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 15

Tcnicas de Programao Avanada


substituda por qualquer outro mtodo de ordenao. A prpria
linguagem C oferece em sua biblioteca padro stdlib, uma funo
chamada qsort, que pode ser usada para ordenar vetores. Essa
funo utiliza um outro mtodo de ordenao muito conhecido e
tambm muito rpido, chamado de Quick Sort.

Atividades
1. Suponha que voc tenha disponveis as
seguintes funes em C:
x
x
x
x

Int CalculaMedia(int *notas);


Void
DeterminaMaiorEMenorNotas(int
*v, int * maior, int *menor);
Void leNotas(int *notas);
Void
MostraResultados(int
media,int
maiorNota,
int
menorNota);

Utilizando essas funes, desenvolva um programa em


C que leia as notas de 5 turmas e para cada uma delas,
imprima a mdia, a maior e a menor nota.

1.2.3 Tipos Abstratos de Dados


A abstrao de dados visa aos mesmos objetivos que a abstrao de
procedimentos, mas com relao s estruturas de dados utilizadas nos
programas. A abstrao de dados visa criar novos tipos de dados
definidos em temos de seu comportamento. Esses novos tipos so
chamados de Tipos Abstratos de Dados - TAD.
muito importante que voc perceba que um tipo abstrato de dados
no se resume a uma nova estrutura de dados. Vamos ento discutir
um pouco sobre essa diferena.
Primeiramente, uma estrutura de dados pode ser definida
simplesmente como uma varivel capaz de armazenar mais de um
valor simultaneamente. Assim, um vetor, uma matriz ou um registro
(struct em C) so exemplos de estruturas de dados. A combinao
desses elementos em estruturas mais complexas d origem a outras
estruturas de dados. A Figura 5 apresenta as declaraes de struct
ponto e struct reta, como exemplos de tipos de estruturas
de dado.

Pgina 16

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 5: Estruturas de Dados ponto e reta.

Ao definir a struct ponto, passamos a contar com mais uma


alternativa para definio de tipos de variveis e, conseqentemente,
para a composio de novos tipos de estruturas. Assim a struct
reta foi definida como uma composio de duas variveis do tipo
struct ponto. Essas estruturas podem ser usadas para declarar
tanto variveis como argumentos de funes.
Em C temos ainda a clusula typedef, que permite definir o nome
do novo tipo. Nesse caso, no precisamos usar a palavra reservada
struct na declarao de variveis do tipo definido. Na Figura 6
temos o uso de typedef. Veja que na definio do tipo Reta, o
nome Ponto usado sem a palavra reservada struct.

Figura 6: Definio dos tipos Reta e Ponto.

Estrutura de Dados versus Tipo Abstrato de Dados


A definio de uma estrutura de dados se preocupa em
demonstrar como o objeto representado na memria
de um computador (representao). Nessa definio so
considerados aspectos do tipo: quais as informaes que
sero armazenadas ali e qual a quantidade destas
informaes. A definio de um Tipo Abstrato de
Dados segue uma abordagem diferente. Essa definio
feita em termos das operaes que podem ser realizadas
sobre o tipo.
A definio de um Tipo Abstrato de Dado (TAD)
chamada de especificao e consiste, basicamente, em
definir as operaes relacionadas ao tipo. Dizemos que
essas operaes definem o comportamento do TAD.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 17

Tcnicas de Programao Avanada


Vamos aplicar o conceito de TAD considerando os objetos Reta e
Ponto. Um passo importante na definio do TAD, que j ajuda na
programao de uma maneira geral, que no conseguimos defini-lo
sem conhecermos a sua finalidade e o contexto no qual ser usado.
Em nosso exemplo precisamos saber para qu ns queremos um
ponto e uma reta. Geralmente essa informao conseguida a partir
do enunciado do problema. Assim, vamos supor a seguinte descrio
para o nosso problema envolvendo retas e pontos:
Problema A. necessrio um programa de computador que realize
operaes geomtricas envolvendo pontos e retas localizadas no
plano cartesiano. O programa deve permitir: calcular a distncia do
ponto at a origem do plano cartesiano; calcular a distncia entre
dois pontos; dada a representao da reta por dois pontos, calcular o
ngulo de inclinao da reta, fornecer os parmetros a e b
correspondentes a equao da reta ax + b. Determinar a distncia de
uma reta a um ponto. Evidentemente, o programa deve permitir a
leitura e impresso de pontos e retas conforme a necessidade das
operaes.
Com base na descrio acima podemos identificar a necessidade do
TAD ponto e do TAD Reta, bem como suas operaes. Essas
operaes aparecem sublinhadas no texto do problema e so
apresentadas nas Figuras 7 e 8.

Figura 7: operaes do TAD Ponto para o problema A.

Figura 8: operaes do TAD Reta para o problema A.

Pgina 18

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


Agora, considere que estejamos desenvolvendo um programa para o
problema abaixo:
Problema B. necessrio um programa de computador para
apresentar graficamente figuras geomtricas formadas por pontos e
retas, usando o monitor do computador como plano. O programa
deve permitir: ler um ponto, plotar um ponto na tela, ligar dois pontos
por um segmento de reta; dada uma reta passando por esse ponto,
deslocar um outro ponto com base na equao dessa reta; dada uma
reta representada por dois pontos, plotar esta reta no monitor; dada
uma reta e um valor d, criar uma reta paralela reta dada a uma
distancia d da reta.
As operaes necessrias aos TAD Ponto e Reta neste problema so
apresentadas nas Figuras 9 e 10.

Figura 9: operaes do TAD Ponto para o problema B.

Figura 10: operaes do TAD Reta para o problema B.

Note que nos dois problemas foram definidos os tipos


Ponto e Reta. No entanto, a abstrao necessria difere
de um problema para o outro, interferindo na definio
das operaes. Embora existam essas diferenas, iremos
sempre tentar criar abstraes mais genricas o quanto
for possvel. Quanto mais genrico um TAD, maior o
nmero de problemas em que esse poder ser aplicado.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 19

Tcnicas de Programao Avanada

Embora as operaes no informem nada a respeito da


representao interna de um TAD, elas fornecem ao
programador tudo o que ele precisa para manipular o
TAD. As operaes de um TAD especificam a sua
interface com o restante do programa. Isso significa que
qualquer ao relacionada ao TAD deve ser feita
mediante uma de suas operaes.
Temos como resultado prtico que o programador, ao
usar o TAD, no vai precisar se preocupar com sua implementao interna. Iremos agora analisar esse aspecto
considerando os TAD Ponto e Reta e o problema A.
Na implementao, ponto e reta foram definidos e implementados,
originando dois mdulos independentes: o mdulo Ponto e o mdulo
Reta. Cada mdulo em C normalmente implementado por dois
arquivos: o arquivo .h e o arquivo .c. No arquivo .c teremos a
implementao das operaes do TAD e no arquivo .h teremos a
especificao da interface do TAD. A Figura 11 e a Figura 12
apresentam as interfaces dos mdulos Ponto e Reta, respectivamente.

Figura 11: Interface do TAD Ponto.

Figura 12: Interface do TAD Reta.

Com a implementao dos TADs Ponto e Reta concludas e


devidamente testadas, qualquer outro mdulo do programa poder
utilizar esses tipos por meio das operaes definidas para os mesmos.
Quando um mdulo A utiliza um mdulo B em programao,
dizemos que o mdulo A cliente do mdulo B. Essa relao de
clientela entre os mdulos (ou TADs) de um programa pode ser
representada graficamente por meio de um diagrama de estrutura
modular - DEM.

Pgina 20

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Diagrama de Estrutura Modular


Um diagrama de estrutura modular formado por
retngulos e linhas direcionadas relacionando os
retngulos. Cada retngulo representa um mdulo. As
linhas direcionadas significam cliente de e indicam o
acionamento de operaes contidas no mdulo apontado
pelo mdulo cliente. Esses digramas tambm so
chamados diagramas hierrquicos, pois apresentam a
hierarquia dos mdulos, iniciando por um mdulo que
inicia o programa e acionam os demais mdulos.
Como exemplo, suponha que tenhamos tambm, junto aos mdulos
Ponto e Reta, um mdulo chamado principal. Esse mdulo cliente
dos mdulos Ponto e Reta. A Figura 13 a seguir ilustra o DEM deste
programa. O mdulo que inicia o programa o mdulo principal (e
deve conter uma funo main()). Ele aciona as operaes tanto do
mdulo ponto quanto do mdulo reta. Reta, por sua vez, tambm
cliente do mdulo ponto.

Figura 13: DEM com mdulos Ponto, Reta e Principal.

A Figura 14 ilustra a implementao de um mdulo Principal. Note


que a nica forma de acesso aos TADs Ponto e Reta por meio das
operaes definidas em suas respectivas interfaces.
Use diagramas de estrutura modular sempre que for
iniciar um novo projeto. Defina os TADs e estabelea o
relacionamento entre eles por meio de DEMs. Junto s
linhas, voc pode especificar as operaes do TAD que
so acionadas pelo cliente. Isso vai ajudar voc na
especificao dos TADs.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 21

Tcnicas de Programao Avanada

Atividades
Implementar as operaes do TadPonto e do TadReta
considerando o enunciado do problema 1, da Seo 1.2.3
do texto, e desenvolver um programa usando a funo
principal (do quadro a seguir) de forma a testar as
operaes.

Figura 14: Mdulo Principal para o Problema A.

Pgina 22

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

At o momento, em nosso exemplo envolvendo Ponto e


Reta, no abordamos a questo de como as operaes
sero implementadas propositalmente. que at a
parte que apresentamos do desenvolvimento no
precisamos saber mesmo. Voc por acaso lembra como
se calcula a distncia entre dois pontos? E a distncia
entre uma reta e um ponto? Pois bem, o importante
que voc tenha compreendido a discusso feita e o
exemplo dado, mesmo sem saber responder essas duas
perguntas. Assim espero!

1.2.4 Implementao de Tipos Abstratos de Dados


Um dos principais benefcios da abstrao de dados
separar o comportamento do TAD, especificado por
meio da definio de suas operaes, da sua
implementao. Em nosso exemplo, o que definimos a
respeito dos TAD Ponto e Reta foi o seu
comportamento, as suas operaes. Nesta seo,
discutiremos melhor como separar em um projeto a
definio do comportamento e da implementao de um
TAD.

O projeto completo de um TAD consiste de dois passos:


1. Especificao - Consiste na especificao do comportamento
do TAD;
2. Implementao Implementao das operaes e estruturas
de dados.
Especificao
A especificao de um TAD descreve o que TAD faz, mas omite
informaes sobre como o mesmo implementado. Por omitir
detalhes de implementao, uma nica especificao permite muitas
implementaes diferentes.
A especificao feita por meio da definio das operaes do TAD.
Para detalhar melhor cada uma destas operaes, devemos estabelecer,
para cada operao, dois elementos:
-

Pr-condies: definem as condies necessrias para que a


operao possa ser realizada. Por exemplo, suponha que
desejamos especificar o TAD Conjunto com a operao
listarConjunto. Uma pr-condio para essa operao
que o Conjunto no esteja vazio.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 23

Tcnicas de Programao Avanada


-

Ps-condies: definem o estado do TAD aps a execuo da


operao.
Por
exemplo,
suponha
a
operao
inserirElemento no TAD conjunto. Uma ps-condio
para essa operao seria: elementos no conjunto = elementos
no conjunto + novo elemento. A Figura 15 ilustra a definio
do TAD conjunto.

Figura 15: Especificao do TAD Conjunto.

Implementao
Um TAD implementado por um mdulo de um programa. Uma
nica especificao permite diferentes implementaes para um
mesmo TAD. Uma implementao est correta se esta prov o
comportamento especificado para o TAD. Implementaes corretas
podem diferir uma da outra, por exemplo, em termos do algoritmo ou
da estrutura de dados que elas usam. Essas diferenas interferem na
eficincia (desempenho em tempo de execuo, ou ocupao de
espao) apresentado pelo TAD para realizao das operaes.
Encapsulamento
Para uma abstrao funcionar corretamente, a sua
implementao deve ser encapsulada. Se a
implementao for encapsulada, nenhum outro mdulo
do programa vai depender de detalhes de
implementao do TAD. Encapsulamento garante que
mdulos do programa podem ser implementados e reimplementados independentemente, sem afetar os outros
mdulos do programa.

O encapsulamento geralmente conseguido por meio da separao da


interface e da implementao do mdulo. Conforme j vimos
anteriormente, em C a implementao de um TAD por meio de um
mdulo consiste em duas partes: a especificao da interface do

Pgina 24

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


mdulo por meio do arquivo header (com extenso.h) e da implementao das operaes por meio de um arquivo com extenso .c.

1.2.5 Avaliao de Implementaes de Tipos Abstratos de


Dados
fundamental para um programador saber criticar e
avaliar a qualidade de uma implementao! Uma
implementao baseada em Abstrao de Dados um
indicativo de boa qualidade. Nesta Seo, discutiremos
elementos que permitem que voc verifique se uma
implementao realmente est de acordo com essa
tcnica.

Embora a linguagem C no oferea um mecanismo que impea


realmente que o programador tenha acesso estrutura interna do TAD,
esta uma regra fundamental e deve ser respeitada pelo programador.
Esta regra ou caracterstica de TADs o encapsulamento, discutido na
seo anterior. Dizemos que um TAD encapsulado por suas
operaes no sentido de que a estrutura interna do TAD fica
preservada e invisvel ao restante do programa. Violar essa regra
significa no usar corretamente a Abstrao de Dados.
Localidade
O maior benefcio do encapsulamento chama-se
princpio da Localidade. Esse princpio permite que um
programa seja implementado, entendido e modificado
um mdulo de cada vez. A localidade aumenta a
qualidade do software que est sendo desenvolvido.

Dentre os benefcios oriundos do princpio da localidade temos:


1. O programador de uma abstrao sabe o que necessrio pelo
que est descrito na especificao. Dessa forma, ele no
precisa interagir com programadores de outros mdulos (ou,
pelo menos, essa interao vai ser bem limitada).
2. De forma anloga, o programador de um mdulo que usa a
abstrao sabe o que esperar desta abstrao, apenas pelo
comportamento descrito em sua especificao.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 25

Tcnicas de Programao Avanada

Uma ferramenta que pode contribuir para esse


entendimento a documentao do TAD. Ou seja, a
explicao sobre o seu funcionamento e sobre como
utiliz-lo. Procure sempre fazer uma boa documentao
do TAD. Essa documentao pode vir como um
documento parte que acompanha o mdulo.

3. necessrio apenas o raciocnio local (por mdulo), para saber


o que o programa faz e se est fazendo a coisa certa. Para
estudar e compreender o programa podemos dividi-lo em
mdulos, e analisar um mdulo de cada vez. Em cada caso,
preocupamo-nos em saber se o mdulo faz o que suposto que
faa. Ou seja, se ele cumpre o que est na especificao.
Pode-se assim limitar a ateno para um mdulo, ignorando
tanto os mdulos usados por este quanto os que o utilizam. Os
mdulos que utilizam o mdulo estudado podem ser ignorados
porque dependem apenas de sua especificao e no da sua
implementao. Os mdulos utilizados so ignorados,
raciocinando-se sobre o que eles fazem utilizando apenas sua
especificao em vez de sua codificao. Com isso, tem-se
uma grande economia de esforo, dado que as especificaes
so muito menores que as implementaes. Observando-se
apenas as especificaes evita-se tambm um efeito cascata.
Por exemplo, se tivermos que olhar o cdigo do mdulo que
utilizamos, teremos que olhar tambm o cdigo dos mdulos
que so utilizados pelos mdulos que utilizamos e assim por
diante.
4. Finalmente, a modificao do programa pode ser feita mdulo
por mdulo. Se uma abstrao particular necessita ser
reimplementada para prover um melhor desempenho, corrigir
um erro ou prover uma nova funcionalidade, o mdulo
implementado anteriormente pode ser trocado por uma nova
implementao sem afetar os outros mdulos.
Prototipagem
Localidade tambm prov uma base firme para a
prototipao ou prototipagem. Um prottipo uma
implementao inicial, rudimentar e incompleta de
um programa a ser desenvolvido. Se mantivermos o
princpio da localidade no desenvolvimento do
prottipo, essa implementao inicial pode ir sendo
completada ou substituda por implementaes
melhores sem grande esforo nem re-trabalho.

Pgina 26

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


Localidade tambm prov suporte para evoluo. Abstraes
podem ser utilizadas nesse caso para encapsular modificaes
potenciais no programa. Por exemplo, suponha que desejamos um
programa para ser executado em diferentes mquinas. Podemos
tratar esse problema inventando abstraes que escondam as
diferenas entre as mquinas de forma que, para mover o
programa para uma mquina diferente, apenas essas abstraes
precisem ser reimplementadas. Um bom princpio de projeto
pensar sobre modificaes esperadas e organizar o
desenvolvimento utilizando abstraes que encapsulem as
mudanas.

Domnio da complexidade
Os benefcios da localidade so particularmente
importantes para a abstrao de dados. Estruturas de
dados so muitas vezes complicadas e a viso mais
abstrata mais simples provida pela especificao torna o
resto do programa mais simples. Ainda, mudanas nas
estruturas de armazenamento so uma das principais
formas de evoluo de programas. Portanto, os efeitos
dessas mudanas devem ser minimizados encapsulando
essas estruturas de dados em abstraes de dados.

Se avaliarmos um programa segundo o critrio da abstrao de


dados, devemos observar os seguintes fatores:
1. Os TADs esto realmente encapsulados?
a. O entendimento de cada mdulo do programa
independe dos demais mdulos?
b. O efeito cascata evitado na depurao?
c. possvel reimplementar um mdulo sem afetar os
outros?
2. Potenciais mudanas foram previstas no projeto do TAD?
3. Os TADs oferecem abstraes suficientemente simples das
estruturas de dados que encapsulam?

Atividades
Os cdigos a seguir especificam as interfaces de dois
mdulos: Aluno e Turma.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 27

Tcnicas de Programao Avanada


/******** aluno.h ***********/
typedef struct aluno{
char nome[30];
int matricula;
int cdgcurso;
} Aluno;
void leAluno(Aluno *);
void imprimeAluno(Aluno);
void AlteraAluno(Aluno *);
/******** turma.h **********/
#include "aluno.h"
#define MAXTURMA 100
typedef struct turma {
int nalunos;
Aluno alunos[MAXTURMA];
}Turma;
void insereAluno(Turma *,Aluno); /*insere o
aluno passado como paramentro na turma */
void localizaAluno(Turma *, char *); /*
localiza um aluno na turma pelo nome */
void imprimeTurma(Turma);
void atualizaAlunoDaTurma(Turma *, char *);
Agora, suponha que tenhamos o seguinte mdulo principal,
utilizando esses mdulos:
/************ Modulo Principal
**************/
#include "turma.h"
Turma turma1;
void principal(){
int opcao,i;
aluno a;
char nome[30];
do{
scanf("%d",&opcao);
switch(opcao){
case 1: /* cadastrar aluno */
lealuno(&a);
insereAluno(&turma1,a);
break;
case 2:
scanf("%s",nome);
a= localizaAluno(&turma1, nome);
printf("%s - %d - %d",a.nome,
a.matricula,a.cdgcurso);
break;
case 3: /* imprimir turma */
for (i=0;i<turma.nalunos;i++)
imprimeAluno(turma.alunos[i]);
break;
case 4:

Pgina 28

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


scanf("%s",nome);
atualizaAlunoDaTurma(&turma1,
nome);
break;
}
}

Tarefas:
a) Critique a implementao do mdulo acima com
base nos critrios de avaliao de TADs discutidos
acima.
b) Faa uma implementao da operao
atualizaAlunoDaTurma, respeitando os princpios de
programao baseada em tipos abstratos de dados.

Dijkstra (1930-2002) foi, sem dvida, um dos


cientistas que mais contriburam para o
desenvolvimento da Programao de Computadores.
Terminamos este captulo com uma frase dele, que
resume o conceito de abstrao:
O propsito da abstrao no ser vaga, mas sim,
criar um novo nvel semntico no qual ela possa ser
absolutamente precisa.
Edsger. W. Dijkstra, The Humble Programmer (O
programador Mediocre), Communications of the
ACM, 15(10), 1972.
Reflita sobre isso!

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 29

Tcnicas de Programao Avanada

2. TIPOS ABSTRATOS DE DADOS


FUNDAMENTAIS.

Ol! Aps o estudo e a compreenso dos conceitos que definem a tcnica de Abstrao de
Dados, utilizaremos esses conceitos em nosso estudo at o final da disciplina. Portanto, se voc no
compreendeu ou no se sente ainda plenamente
convencido de que deve utilzar Abstrao de
Dados em seus programas, recomendo que retorne
ao Captulo 2. O motivo disso muito simples.
Daqui para frente estudaremos problemas e solues mais complexos, que exigem muito do estudante em sua capacidade de abstrao. Neste
Captulo, em particular, iniciamos nosso estudo de
um conjunto de TADs muito comuns e
importantes: Os TAD Pilha e Fila.

No decorrer da evoluo da programao, padres e prticas comuns


tm sido observadas e transformadas em conceitos, modelos e mecanismos que podem ser utilizados em mais de uma situao diferente.
Dentre esses elementos temos uma coleo de tipos abstratos de dados
que so comuns a diversas situaes e aplicveis na soluo de uma
grande quantidade de problemas. Dois desses TADs so as Pilhas e as
Filas, que estudaremos em profundidade neste captulo.

2.1 PILHAS
No mundo real uma pilha corresponde a um agregado de objetos que
so acomodados um sobre o outro. A Figura 1 ilustra uma pilha em
que os objetos so caixas.

Pgina 30

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 1: Uma Pilha de Caixas

Os nmeros nas caixas indicam a ordem de empilhamento. Se


quisermos agora remover as caixas da pilha (desempilhar), temos que
remover a caixa 4 primeiro, depois a 3, a 2 e finalmente a 1. No
podemos remover as caixas abaixo da que est no topo da pilha sem
antes remover a do topo. Esse comportamento pode ser definido pela
estilo: O ltimo a entrar o primeiro a sair.
No mundo real temos diversas situaes em que esse comportamento
deve ser respeitado. Assim, o uso de pilhas pode facilitar a soluo
de vrios problemas. Um exemplo tpico de uso de pilha a
operao desfazer, presente na maior parte dos editores de texto.
Quando voce executa a operao desfazer,
a ltima operao
realizada que dever ser desfeita primeiro. Se voc executar o
desfazer novamente, a penltima operao dever ser desfeita, e assim
sucessivamente. Concluindo, precisamos ter sempre a informao de
qual foi a ltima operao realizada. Uma pilha uma forma eficiente
de obtermos esa informao. Se tivermos uma pilha em que
empilhamos a operao que foi feita, teremos no topo da pilha sempre
a operao que devemos desfazer.
Realmente, editores texto que possuem a operao desfazer mantm
uma pilha que guarda informaes sobre as aes que vo sendo
realizadas durante a edio. Por exemplo, no momento em que este
texto era digitado, as informaes passadas via teclado e mouse eram
tambm empilhadas.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 31

Tcnicas de Programao Avanada

A aplicao de pilhas em editores de texto um


exemplo de uma funcionalidade muito comum de uso de
pilha. Essa funcionalidade est presente em outros
cenrios, como em jogos, programas de logistica,
robtica e redes de computadores. O que esses cenrios
tm em comum a necessidade de retroceder por um
caminho de dados ou aes que tenha realizado. Esse
retocesso se d tambm em algoritmos de backtracking,
(algo como voltar na trilha) e muito comum em
algoritmos de busca e recuperao de informao. Veja
a
discusso
sobre
esses
algoritmos
em
http://pt.wikipedia.org/wiki/Backtracking.

2.1.1 Especificao do TAD Pilha


O TAD Pilha pode ser descrito pela seguinte especificao
apresentada na Figura 2. Nessa especificao so definidas as
operaes Empilha, que insere elementos na Pilha e Desempilha, que
remove elementos da Pilha. So definidas tambm as pr-condies e
ps-condies dessas operaes.

Figura 2: especificao do TAD Pilha.

Alm das operaes empilha e desempilha, temos tambm a operao


inicializaPilha, que coloca a Pilha em um estado inicial, com a pilha
vazia. A Figura 3 ilustra uma possvel implementao do TAD Pilha
limitado a 5 (cinco) posies. Cada posio possui um ndice. O topo
mantm o ndice do valor que est presente no topo. Nesse exemplo,

Pgina 32

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


temos o elemento do topo na posio de ndice 5, conforme indica a
figura. Se convencionarmos que os elementos foram inseridos na pilha
na ordem L I C A F, temos que:
O primeiro elemento empilhado foi o L, seguido do I, C, A e F. Logo,
podemos concluir que nessa implementao de pilha a atualizao do
topo consiste em incrementar de 1 na operao empilha e decrementar
de 1 na operao desempilha. As pr-condies tambm podem ser
obtidas da implementao. A operao Pilha Vazia pode ser verificada
por meio do teste do valor do topo. Por exemplo, se iniciarmos a pilha
com topo valendo 0, podemos usar o teste topo == 0 para verificar se
pilha est vazia. J a pr-condio pilha cheia pode ser verificada
considerando o limite da implementao. No nosso exemplo esse
limite 5. Se o topo == 5, a pilha est cheia. Com isso, fica definida
tambm a operao inicializaPilha que deve fazer o topo valer 0
(zero).

Figura 3: Implementao de uma Pilha.

importante neste momento notar que existem muitas


implementaes possveis para a especificao do TAD
pilha (conforme discutido no Capitulo 1). Esse exemplo
apresentado apenas uma das possveis solues.
Um outro detalhe que, alm das operaes empilhar e
desempilhar, as pr-condies de pilha Cheia e pilha
Vazia podem tambm se tornar operaes do TAD Pilha
na implementao. Na prxima seo discutiremos
algumas implementaes de Pilha usando arranjos
estticos.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 33

Tcnicas de Programao Avanada

Atividades
1. Na seqncia a seguir, uma letra significa
empilha e um asterisco significa desempilha.
Determine a seqncia de valores retornados
pela operao desempilha quando essa
seqncia de operaes realizada sob uma
pilha inicialmente vazia.
EAS*Y*QUE***ST***IO*N***
2. Suponha que uma seqncia misturada de
operaes empilha e desempilha realizada.
As operaes empilha empilham inteiros de 0
at 9 ordenadamente. A operao desempilha
desempilha e imprime o valor desempilhado.
Qual das seqncias abaixo no poder ser
impressa?
(a) 4 3 2 1 0 9 8 7 6 5
(b) 4 6 8 7 5 3 2 9 0 1
(c) 2 5 6 7 4 8 9 3 1 0
(d) 4 3 2 1 0 5 6 7 8 9

2.1.2 Implementao de Pilhas em Arranjos


A Figura 3 ilustra por meio de um diagrama uma implementao de
Pilha. Usando arranjos estticos (vetores) e fazendo algumas
adaptaes, podemos criar essa implementao em C. A
implementao, conforme discutido na Seo 1.2.4, ser formada de
duas partes, a interface (arquivo com extenso .h)
e a
implementao das operaes (arquivo com extenso .c).
recomendado primeiro a definio do arquivo de interface e depois a
implementao das operaes. A seguir discutiremos uma possvel
implementao do TAD Pilha, utilizando arranjos.
A Figura 4 mostra o arquivo de interface tadpilha.h. Foi definido
um novo tipo chamado Pilha, formado por dois elementos
principais: Uma varivel inteira topo e o vetor itens, que servir
de continer para a pilha. O vetor itens do tipo Elemento, que
apenas uma redefinio do tipo char. A definio desse tipo
Elemento facilita posteriores modificaes no tipo bsico da pilha. Se
quisermos, por exemplo, alterar a pilha para que esta empilhe e
desempilhe valores inteiros, basta redefinir o tipo Elemento como

Pgina 34

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


int. Foram definidas assinaturas (prottipos) das funes
correspondentes s operaes inicializaPilha, empilha,
desempilha e aos testes das pr-condies, pilhaCheia e
pilhaVazia. Observe que estamos seguindo a notao de
prottipos padro de C. Nessa notao, apenas os tipos dos
argumentos (parmetros das funes) so identificados, sendo os
nomes mesmos desses argumentos apenas na implementao. Note
tambm que a operao desempilha retorna um Elemento. Isso
bastante comum, pois normalmente se deseja fazer alguma coisa com
o elemento desempilhado.

Figura 4: Interface do TAD Pilha com arranjos estticos.

Na Figura 5, temos a implementao das operaes feitas no arquivo


tadPilha.c. A operao inicializaPilha faz o topo da Pilha
receber 0 (zero). PilhaCheia verifica se topo igual a MAX
(tamanho mximo que a pilha pode ter) e PilhaVazia verfica se
topo igual a 0. Na operao empilha temos a seguinte ordem: insere
o elemento e depois incrementa o topo. Isso necessrio porque em C
a primeira posio de um arranjo a 0 (zero) e com a Pilha vazia o
topo est em zero. Assim, o topo estar sempre com um ndice do
elemento no topo + 1. Para compensarmos isso, na operao
desempilha devemos decrementar o topo retornando o elemento
somente aps o topo ser decrementado.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 35

Tcnicas de Programao Avanada

Figura 5: Implementao das operaes do TAD Pilha.

Atividades
1. Empilhamento decrescente. Uma empilhadeira
carrega caixas de 7, 5 e 3 toneladas. H trs pilhas
A, B e C. A pilha A onde se encontram todas as
caixas que chegam no depsito. Com um detalhe:
caixas maiores no podem ser empilhadas sobre
caixas
menores.
Elabore
uma
funo
chegaNoDeposito
(Caixa*
nova,
Pilha* A) que efetue o controle das caixas, de
forma que, caso uma caixa de maior peso do que
uma que j est em A deva ser empilhada, ento,
todas as caixas que esto em A so movidas para as
pilhas auxiliares B (contendo somente caixas de 5

Pgina 36

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


toneladas) e C (contendo somente caixas de 3
toneladas) at que se possa empilhar a nova caixa.
Depois, todas as caixas so movidas de volta para a
pilha A.
2. Implementar o TAD PilhaDupla, usando um

arranjo de 100 posies. PilhaDupla deve usar


um nico arranjo para implementar as duas pilhas.
Alm disso, a ocupao da Pilha deve maximizar o
uso do espao do arranjo, ou seja, enquanto houver
espao no arranjo qualquer uma das duas pilhas
pode utiliz-lo.

2.2 FILAS
Em nosso cotidiano nos deparamos constantemente com filas. Ou
melhor, estamos constantemente entrando e saindo de filas! Muitas
pessoas se aborrecem com as filas. Todavia, podemos dizer que elas
so um mal necessrio. Por exemplo, imaginem se, para entrarem em
um nibus em uma cidade, as pessoas no fizessem uma fila e
simplesmente se amontoassem na porta. Seria um tumulto, as pessoas
que estivessem no ponto h mais tempo poderiam no conseguir entrar
ou ficar sem assento. O mais incrvel que isso acontecia h uns 20
anos e ainda acontece em muitos lugares do Brasil e do mundo!

Figura 6: Fila: O primeiro que chega o primeiro a ser atendido.

Esse exemplo ilustra a idia de que o emprego de filas no dia-a-dia


fundamental para a organizao das atividades feitas pelas pessoas,
sempre que o nmero de clientes de um recurso maior que a
capacidade de atendimento desse recurso. No caso do nibus, o
recurso a porta de entrada, que s atende uma pessoa por vez. Com
mais de uma pessoa no ponto esperando para entrar, necessrio que
elas formem uma fila. Um outro exemplo fila em um banco, cujo
recurso necessrio o caixa. Quando entram mais clientes do que o
nmero de caixas, os clientes devem formar uma fila.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 37

Tcnicas de Programao Avanada


O comportamento de uma fila pode ser descrito pelo estilo: O
primeiro que chega o primeiro a ser atendido. Em uma Fila
organizada e sem prioridades (Figura 6, por exemplo), essa regra
sempre obedecida.
Na programao aplicamos o conceito de fila para tratar casos
semelhantes ao do nibus e ao do banco. Alguns exemplos de
aplicao de filas so:

Fila de espera de passagens areas Suponha, por exemplo,


que voc esteja desenvolvendo um sistema de reservas de
passagens areas. Nesse tipo de sistema, as pessoas fazem
reservas at o recurso (nmero de assentos no vo) se esgotar.
Quando isso acontece, se houver mais pessoas que querem
viajar naquele vo, elas entram em uma fila de espera. Se
houver uma desistncia das reservas, a primeira pessoa dessa
fila ser atendida.

Fila de mensagens Suponha que voc esteja desenvolvendo


um programa A que envie constantemente mensagens a um
programa B. O programa B precisa receber essas mensagens e
process-las. Se o nmero de mensagens que o programa A
envia em um tempo x maior do que a capacidade de
processamento das mensagens no mesmo tempo x pelo
programa B, o programa B dever usar uma fila para guardar
as mensagens at que elas possam ser processadas. Esse um
caso muito comum na Internet. Quando fazemos a requisio
de uma pgina Web, o navegador (programa A) envia uma
mensagem ao servidor Web (programa B). Esse servidor pode
receber mais requisies (mensagens) do que a sua capacidade
de processamento. Nesse caso, ele deve enfileirar as
requisies para que elas no sejam perdidas e para que sejam
atendidas na ordem de chegada.
Teoria das Filas
O estudo das Filas, do ponto de vista estatstico e
probabilstico, denomina-se Teoria das Filas e
compreende uma disciplina de grande interesse de
diversas reas da engenharia, computao e
administrao. Essa disciplina permite, dentre outras
coisas, estimar a capacidade de recursos a serem
construdos (p.exemplo, aeroportos, pontes,
armazns de estocagem), identificar gargalos
(pontos de atraso) em sistemas e estimar o tempo
para a realizao de uma tarefa. Em nosso estudo,
nos concentraremos apenas na implementao e
emprego de filas em programao, e no na
Teoria das Filas.

Pgina 38

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


2.2.1 Especificao do TAD FILA
O tipo abstrato de dados fila pode ser descrito pela especificao da
Figura 7.

Figura 7: Especificao do TAD Fila.

As operaes fundamentais do TAD Fila so inserir e remover.


Para garantir o comportamento esperado em uma fila, definimos que a
insero feita no final da fila e a remoo feita no comeo da fila.
Temos tambm a operao inicializaFila, que coloca a fila em um
estado inicial, no qual a fila deve estar vazia. A partir dessas
operaes e de suas pr e ps-condies podemos deduzir que sero
necessrias as operaes de teste de fila cheia e teste de fila vazia.
Assim como na implementao da pilha precisamos de alguma forma
de identificar o topo, na fila iremos necessitar de alguma maneira de
identificar o seu inicio e seu o fim.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 39

Tcnicas de Programao Avanada

Figura 8: Inseres e remoes em um TAD Fila.

O diagrama da Figura 8 ilustra uma fila com capacidade para cinco


elementos implementada em uma estrutura semelhante a um vetor. O
digrama tambm ilustra a insero de cinco elementos (M1..M5) e
duas operaes de remoo. Note que os valores de incio e fim so
usados para armazenar as posies atuais do incio e do fim da fila.
Inicialmente o valor de incio est em zero. Podemos usar essa
condio para detectarmos se a fila est vazia. Quando o elemento M1
inserido, este colocado na posio 1 e o incio e o fim so
atualizados, ambos para 1. medida que outros elementos so
inseridos, o fim atualizado. Quando o fim chega a 5, temos que a fila
no comporta mais nenhuma insero, isto , a fila est cheia. Assim,
podemos usar essa condio para detectarmos se a fila est cheia ou
vazia.

Pgina 40

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


medida que as remoes ocorrem, o inicio da fila atualizado, de
forma a identificar sempre o elemento a ser removido. Um problema
dessa implementao que uma vez que fim atingiu o valor mximo
(5 neste caso), no so possveis mais inseres, mesmo havendo
outros espaos. Isso ruim, pois torna a fila muito limitada. Para
contornarmos esse problema veremos duas implementaes
diferentes: Remoo com deslocamento e Fila circular. Na remoo
com deslocamento, medida que os elementos so removidos, os
elementos remanescentes so deslocados para o incio do arranjo.

Figura 9: Implementao com Deslocamento.

A Figura 9 mostra a implementao com deslocamento. Note que,


nessa implementao, aps a remoo de todos os elementos, o valor
de incio permaneceu com 1 e o valor de fim passou a ser zero. Assim,
a condio de fila vazia no pode ser verificada pelo teste de incio =
0. Um possvel teste fim = 0 ou fim menor que incio. A seguir
vamos ver uma implementao em C usando arranjos para essa fila.
Posteriormente veremos a implementao utilizando fila circular.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 41

Tcnicas de Programao Avanada

Atividades
Ordenar uma fila utilizando 2 pilhas como variveis
auxiliares. Ao final da ordenao o elemento no incio da
fila deve ser menor que o segundo da fila e assim
sucessivamente. A ordenao deve ser feita apenas em
termos das operaes insere, remove, filaVazia,
empilha, desempilha e pilhaVazia. A funo
deve ter a seguinte organizao:
void ordena_2p (Fila* f){
Pilha p1, p2;
...
}

2.2.2 Implementao
deslocamento

de

Filas

em

arranjos

com

De forma similar da implementao de Pilha iremos definir um


mdulo em C para implementao da Fila. Na Figura 10 temos a
definio da interface (arquivo filaecd.h) do TAD Fila.

Figura 10: Interface do TAD Fila.

A Figura 11 apresenta o arquivo filaecd.c, contendo a implementao


das operaes da Fila com deslocamento na remoo.

Pgina 42

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 11: Implementao do TAD Fila Com deslocamento.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 43

Tcnicas de Programao Avanada


O cdigo est comentado e pretende ser auto-explicativo. A operao
insereNaFila insere os elementos passados como parmetro
(elem). Para inserir na fila, inicialmente o valor de fim
incrementado, visto que este foi inicializado com valor 1. Dessa
forma a primeira insero insere na posio 0 do vetor, a segunda na
posio 1 e assim sucessivamente. A operao mais complexa a
remoo. Para remover, inicialmente o elemento no incio da fila
passado por referncia por meio do parmetro (elem *).
Posteriomente os elementos remanescentes na Fila so deslocados de
uma posio. Dessa forma o elemento do incio da fila ocupa
novamente a posio 0 do vetor.
O cdigo da Figura 12 (arquivo principal.c) permite testar a Fila.

Figura 12: Mdulo para teste do TAD Fila.

A funo testeFilaecd declara uma fila (q) inicializa a fila, insere os


inteiros de 0 a 9 e depois remove os elementos e os imprime. Note que
todo o processamento feito usando as operaes do Tad Fila.

Atividades
4. Implementar as operaes imprimir Fila para o TAD Fila
implementado anteriormente.

Pgina 44

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


2.2.3 Implementao de Filas com Arranjos circulares
Analisando a implementao do TAD Fila da seo
anterior podemos notar que, embora a fila esteja
corretamente implementada, existe um problema de
eficincia na remoo de um elemento. Estou me
referindo aos deslocamentos necessrios para que a
remoo seja feita e os espaos vagos no vetor
possam ser reaproveitados. Veremos agora outra
maneira de implementar o TAD Fila, em que esses
deslocamentos no so necessrios.
Essa
implementao chama-se Fila Circular.
Funo Sucessor
Em um arranjo simples, cujas posies vo de 0 a t, podemos
identificar facilmente qual o elemento que sucede uma determinada
posio i. Por exemplo, se i =0, o sucessor de i = 1, se i=1 sucessor de
i = 2. Ou seja, o sucessor de i = i+1, para i variando entre 0 e t-1.
Nesse caso, no existe o sucessor de t.
Agora, se definimos que o sucessor de t = 0, temos ento que todos os
ndices do arranjo possuem sucessor. A Figura 13 ilustra essa situao.
Conforme pode ser observado, existe uma circularidade entre os
ndices.

Figura 13: Fila Circular.

Com vetores variando entre 0 a N-1, que o caso da linguagem C, a


funo sucessor pode ser obtida elegantemente por meio da funo:
sucessor(i) = (i+1) mod n, onde mod o operador
resto.
Quando utilizamos essa funo para avanarmos o ndice de um
arranjo para a prxima, dizemos que estamos usando um arranjo
circular.
TAD FILA baseado em Arranjo Circular
Com um arranjo circular, possvel deslocar o incio e o fim da fila
por todo o vetor, sem correr o risco da perda de espao e sem a
necessidade de realocar os elementos da fila. Nessa implementao as

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 45

Tcnicas de Programao Avanada


operaes de inserir e remover, bem como as condies de Fila Cheia
e Fila vazia precisam ser baseadas na funo sucessor. A Figura 14
apresenta a lgica dessas operaes, agora definida em termos da
funo sucessor.

Figura 14: Especificao das operaes de um TAD Fila Circular.

A Figura 15 apresenta a implementao das operaes. Note que no


necessrio um novo arquivo header, pois este o mesmo da
implementao do mdulo filaecd. Esse fato ilustra um aspecto
importante da implementao de TADs: A implementao pode ser
modificada sem necessidade de se alterar a interface. Outro aspecto da
implementao com arranjo circular, que uma das posies do
arranjo perdida. Isso necessrio para diferenciar as condies de
Fila Vazia e Fila Cheia.

Atividades
1. Reimplemente a Fila Circular, considerando que o elemento a ser
inserido um paciente de hospital (pessoa). Os seguintes dados so
importantes para o paciente: nome, idade, horrio de chegada e
enfermidade.
2. Implemente tambm a operao imprimeFila para essa nova Fila.

Pgina 46

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 15: Implementao das operaes de Fila em um arranjo Circular.

2.3 IMPLEMENTAO DE TADS COM ALOCAO


DINMICA DE MEMRIA
2.3.1 Reviso de Alocao Dinmica de Memria
O objetivo da alocao dinmica de memria utilizar espaos da
memria de tamanho arbitrrio. Em adio, a alocao dinmica de
memria permite criar estruturas de dados encadeadas. A alocao de
espao sob demanda utilizada quando o espao de memria
necessrio para um conjunto de dados varia durante a execuo do
programa. J o encadeamento prov um estilo eficiente de representar
conjuntos de dados em C e de implementar as estruturas de
armazenamento de Tipos Abstratos de Dados.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 47

Tcnicas de Programao Avanada


A alocao dinmica de memria necessita de suporte da Linguagem
de Programao. Em C, esse suporte fornecido por um conjunto de
funes disponveis na biblioteca alloc. As principais funes dessa
biblioteca so a funo malloc, que aloca um espao na memria e
retorna um ponteiro para o espao alocado e a funo free, que
libera espaos de memria alocados por meio da funo malloc.
Exemplo de uso de alocao de espao sob demanda
Uma das vantagens da alocao dinmica permitir a alocao de
espao de acordo com a necessidade. Por exemplo, suponha que um
programa necessite de um arranjo para guardar N nmeros inteiros.
Usando alocao esttica de memria, como no sabemos a
quantidade precisa de nmeros, devemos fazer uma estimativa do
valor mximo de nmero e declarar o vetor com base nessa estimativa.
A funo alocEstatica da Figura 16 ilustra esta situao.

Figura 16: Alocao Esttica de memria.

Note que o valor lido para n pode variar de 1 a 100. Quanto menor o
valor de n, maior o desperdcio de espao alocado.
Usando alocao dinmica teremos o valor de n que, lido, pode ser
usado como parmetro da chamada da funo malloc, para alocar um
conjunto de n inteiros, ou seja, um vetor de n inteiros. A funo
alocDinamica na Figura 17 idntica em termos de
funcionalidade funo alocEstatica. Contudo, esta utiliza
alocao dinmica.

Pgina 48

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 17: Vetor com Alocao dinmica.

Note que na alocao dinmica no h limites para n, e este poder


assumir, em teoria, qualquer valor maior que zero (n>0). A funo
malloc possui apenas um parmetro formal: o nmero de bytes a
serem alocados. Normalmente esse nmero de bytes determinado
multiplicando o tamanho em bytes do tipo base a ser alocado pelo
nmero de elementos. No exemplo, o tipo base o int. Foi usada a
macro sizeof para determinar o tamanho exato do tipo int, que
pode variar entre diferentes mquinas, sistemas operacionais e
linguagens. Qualquer tipo pode ser utilizado como parmetro de
sizeof, inclusive tipos definidos pelo usurio.
Listas Simplesmente Encadeadas
Uma outra finalidade do uso de alocao dinmica e apontadores
permitir a implementao de estruturas encadeadas utilizando
estruturas auto referenciadas.Uma estrutura auto referenciada
possui, dentro seus campos, um campo que pode referenciar estruturas
idnticas a ela mesma. Portanto, uma estrutura auto referenciada pode
apontar para outra estrutura do mesmo tipo que ela.
O cdigo na Figura 18 define um tipo Ponto que auto referencivel.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 49

Tcnicas de Programao Avanada

Figura 18: Estrutura auto referenciada.

O tipo Ponto definido pelo typedef um tipo ponteiro para a


struct ponto. Essa struct por sua vez, possui dentro dela os
campos x,y (coordenadas do ponto), cor (cor do ponto) e
proximoPonto, que uma varivel do tipo ponteiro para struct
ponto. A varivel proximoPonto que permite que uma varivel
do tipo struct ponto possa se ligar (apontar) a outra estrutura do
tipo struct ponto.

Figura 19: A struct ponto.

Lista simplesmente Encadeada


A estrutura de dados encadeada mais simples que temos
a lista simplesmente encadeada. Uma lista
simplesmente encadeada um agregado de elementos
de um mesmo tipo, em que cada elemento armazenado
em um espao alocado dinamicamente. medida que
elementos so inseridos na lista, esses espaos so
criados e vo sendo encadeados de forma que:
- O endereo do primeiro ou do ltimo elemento da lista
mantido em uma varivel do tipo ponteiro;
- Os demais elementos so acessados a partir do seu
incio ou do seu fim. Isto possvel porque cada nodo
da lista possui um campo que aponta para o prximo
elemento da lista.

A struct ponto pode servir para implementarmos uma lista.


Visualmente, uma lista encadeada de pontos pode ser ilustrada pela
Figura 20 a seguir:

Pgina 50

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 20: Exemplo de lista simplesmente encadeada.

lPontos uma varivel do tipo ponteiro para struct ponto


(Ponto com P maisculo). Inicialmente a lista est vazia. Assim
conveniente fazermos a varivel lPontos apontar para um valor
Seguro, evitando possveis invases de espao de memria
indevidos. Este valor seguro NULL.
Para inserirmos um nodo na lista de pontos, criamos o nodo,
utilizando malloc e guardamos o endereo deste nodo em
lPontos;
Para manter o encadeamento, devemos fazer o proximoPonto do
nodo alocado apontar para o endereo anteriormente contido em
lPontos. O excerto de cdigo apresentado na Figura 21 implementa
esta operao de insero.

Figura 21: Inserindo um ponto na lista de pontos.

Note que foi necessrio guardar o valor de lPontos em aux, Isso


ocorre porque, quando malloc chamada para criar o novo Ponto, o
endereo retornado atribudo a lPontos fazendo com que o seu
endereo anterior seja perdido.
conveniente implementar uma lista simplesmente encadeada como
um TAD, encapsulando sua estrutura por meio de operaes bem
definidas. Essas operaes compreendem a insero, a remoo
e outras que por ventura sejam necessrias (por exemplo,
imprimeLista). A seguir, iremos implementar uma lista encadeada
cujo objetivo armazenar uma lista de pessoas. Cada pessoa
definida pelo seu nome, seu cdigo e seu telefone. Na implementao
definimos um mdulo elemento e o mdulo Tadlista. As Figuras 22 e
23 apresentam a definio da interface desses dois mdulos:

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 51

Tcnicas de Programao Avanada

Figura 22: Interface do TAD Elemento.

Figura 23: Interface do TAD Lista.

A implementao da operao inicializaLista (Figura 24)


consiste em atribuir o valor NULL a Lista passada por referncia.
Segue essa implementao:

Figura 24: Implementao da operao inicializaLista.

A implementao da insero (Figura 25) segue exatamente o mesmo


procedimento usado no exemplo da lista de pontos.

Figura 25: Implementao da operao insereNaLista.

A operao de remoo visa remover um elemento da lista tendo sido


informado o cdigo do elemento. Esse procedimento deve tambm
retornar o elemento a ser removido. A remoo deve usar a funo
free para liberar o espao alocado pelo nodo removido. Alm disso,
deve ser tambm preservado o encadeamento da lista. De acordo com
esses objetivos temos que realizar uma pesquisa na lista com o
objetivo de encontrar o nodo a ser eliminado. Como resultado dessa
pesquisa existem duas possibilidades:

Pgina 52

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


* O elemento est na lista. A pesquisa pra quando encontrar o
elemento.
* O elemento no est na lista. A pesquisa chega at o fim da lista
(NULL).
Formulamos ento o algoritmo recursivo apresentado na Figura 26.

Figura 26: algoritmo para remoo de um elemento na Lista.

A Figura 27 apresenta uma implementao para a operao de


remoo baseada no algoritmo da Figura 26.

Figura 27: Implementao da operao removeDaLista.

A operao pesquisaNaLista visa retornar um elemento cujo


cdigo passado como parmetro. Essa pesquisa feita por meio de
um loop, que percorre a lista at encontrar o elemento ou chagar ao
seu final. Temos novamente duas situaes: busca com sucesso ou
busca sem sucesso. Na Figura 28, temos a implementao desta
operao.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 53

Tcnicas de Programao Avanada

Figura 28: Implementao da operao pesquisaNaLista.

A Figura 30 apresenta a implementao da operao


imprimeLista, que utiliza a operao imprimeElemento do
TAD elemento (Figura 29). A operao imprimeLista deve
percorrer a lista at o final imprimindo o contedo de seus elementos.
Seguem as implementaes das operaes imprimeElemento
arquivo elemento.c) e imprimeLista (arquivo tadLista.c). A
operao imprimeLista recursiva. A cada chamada da
recursividade, passado um apontador para o prximo elemento da
lista. A condio de parada da recusividade chegar ao final da Lista
(NULL).

Figura 29: Implementao da operao imprimeElemento do TAD Elemento.

Figura 30: Implementao da operao imprimeLista.

Pgina 54

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Atividades
1. Implementar uma operao para o TAD Lista
que insira os elementos no seu final.
2. Implementar uma operao para o tadLista

que transforme a lista em uma lista ordenada.


Essa operao deve inserir os elementos de
modo que a lista permanea sempre em ordem
crescente a partir de seu inicio. A chave de
ordenao a ser utilizada deve ser o cdigo do
elemento.

2.3.2 Implementao do TAD Pilha


A implementao do TAD Pilha com alocao dinmica de memria
possui como vantagem principal o fato de podermos considerar a sua
capacidade de armazenamento como sendo infinita. Ou seja, usando
alocao dinmica no precisamos testar se a Pilha est cheia para
fazer um empilhamento. Outra vantagem est na simplicidade da
implementao. O quadro abaixo ilustra a definio do tipo Pilha
como uma estrutura dinmica encadeada. Podemos afirmar que uma
pilha uma lista onde os elementos so inseridos no incio e
removidos do incio. Para efeitos de implementao da pilha,
chamamos o incio de topo.
A Figura 31 apresenta o arquivo de interface TadPilhaAD.h com a
definio da estrutura de dados Pilha e das operaes. Note
novamente que as operaes so as mesmas apresentadas no mdulo
Pilha.h visto anteriormente.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 55

Tcnicas de Programao Avanada

Figura 31: Interface do TAD Pilha com alocao dinmica

Para a definio da Pilha dinmica, definido o tipo Nodo que um


tipo ponteiro para struct nodo (em minsculo). Pilha uma estrutura
que contm apenas uma varivel: o topo. Esse topo, por sua vez, do
tipo Nodo.
Uma varivel do tipo Pilha uma varivel esttica. Essa varivel
uma estrutura contendo como nico campo o topo. O topo, por sua
vez, que um apontador.
Pilha p;
p.topo=NULL;
NULL
topo

p
Figura 32: Representao do da estrutura de dados dinmica Pilha.

Topo uma varivel do tipo ponteiro para struct nodo. Assim


topo pde ser inicializado com NULL. Essa condio pode ser
utilizada para detectarmos se a Pilha est vazia. A Figura 33 apresenta
as operaes inicializaPilha e pilhaVazia seguindo exatamente essas
decises de implementao.

Pgina 56

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 33: Implementao das operaes inicializaPilha e pilhaVazia.

A operao empilha pode ser especificada da seguinte forma:


1. Cria uma nova estrutura do tipo struct nodo;
2. Faz o prox da nova estrutura apontar para a estrutura para a
qual o topo da Pilha aponta;
3. Faz o topo da pilha apontar para o novo nodo.
Seguindo os passos acima, aps inserirmos o primeiro elemento na
pilha (valor 1), e supondo que o nodo foi alocado a partir do
endereo 300h da memria, teremos a configurao apresentada na
Figura 34.

300h

NULL

topo

prox
1
item

p
300h
Figura 34: Diagrama da Pilha com um nodo (um elemento empilhado).

Se empilharmos agora um segundo elemento (valor 2), e supondo que


o novo nodo foi alocado na posio 400h, teremos a seguinte
configurao apresentada na Figura 35.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 57

Tcnicas de Programao Avanada

400h

NULL

300h

topo

prox

prox

item

item

300h

400h

p
Figura 35: Empilhando o elemento 2.

Inserindo agora o elemento 3 e supondo a alocao no endereo 500h


teremos a configurao da Figura 36.

500h
topo

NULL

300h

400h

Prox

prox

prox

item

item

item

300h

400h

500h

Figura 36: inserindo o elemento 3.

A remoo de um elemento na pilha dinmica implica nos seguintes


passos:
1. se a pilha no est vazia:
a. guarda o valor que est no topo;
b. salva o endereo que est no topo em uma varivel
auxiliar;
c. atribui o endereo do prox do topo ao topo;
d. libera o espao ocupado pelo nodo que estava no topo.
Executando esses procedimentos, a regra fundamental da pilha, o
ltimo que chega o primeiro que sai, sempre respeitada. A Figura
37 apresenta a implementao das operaes empilha e desempilha:

Pgina 58

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 37: Implementao das operaes empilha e desempilha.

Atividades
Reimplementar o TadPilha, usando o TAD Lista, (visto na
reviso de Alocao Dinmica), como cliente. Nessa nova
implementao o tipo Pilha deve ser definido em termos do
tadLista e as implementaes de empilha e desempilha e
filaVazia devem ser feitas com base nas operaes de
remoo e insero.

2.3.3 Implementao do TAD Fila


A Figura 38 presenta o arquivo TadFilaAD.h. Assim como na
implementao da Pilha, foi utilizada uma estrutura chamada nodo
contendo um campo item do tipo Elemento e um campo prox para
estabelecer o encadeamento dos nodos. O tad Fila por sua vez uma
estrutura contendo os campos inicio e fim que so apontadores para struct
nodo (Nodo). Uma varivel to tipo TadFila uma estrutura contendo esses
dois campos. Por exemplo, a seqncia:

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 59

Tcnicas de Programao Avanada

Figura 38: Interface do TAD Fila com alocao dinmica.

TadFila q;

NULL

q.inicio=NULL;
q.fim=NULL;

inicio
NULL
fim
q

Figura 39: diagrama de memria da estrura dinmica Fila.

A Figura 39 ilustra a varivel q. Analogamente a uma Pilha, podemos


inicializar a Fila colocando o Valor NULL em inicio e fim. Alm
disso, podemos usar a condio incio = NULL para detectar se a Fila
est vazia. A Figura 40 apresenta a implementao destas operaes.

Figura 40: Implementao das operaes inicializaFila e filaVazia.

Pgina 60

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


Aps a insero de um elemento (1) na Fila, supondo que o nodo vai
ser alocado na posio 300h, temos a configurao apresentada na
Figura 41.
300h

NULL

inicio

prox

300h

fim

item

300h

Figura 41: Inserindo o elemento 1 na Fila.

Inserindo mais um elemento (2) e supondo que o nodo foi alocado no


endereo 400h, temos a insero apresentada na Figura 42.
300h

400h

NULL

inicio

prox

prox

400h

fim

item

item

300h

400h

Figura 42: Inserindo o elemento 2.

Note que o contedo do apontador fim foi atualizado. Essa operao


deve ser cuidadosa para que os ponteiros no fiquem perdidos.
Existem duas situaes que devem ser tratadas diferentemente:
quando a Fila est vazia e quando no est vazia. A seguinte
seqncia de passos deve ser utilizada:
1. aloca o novo nodo
2. atribui os valores ao novo nodo
3. Se a fila est vazia
a. incio = novonodo
b. fim = novonodo
4. Se no
a. o prox do nodo apontado por fim recebe o novonodo
b. fim=novonodo

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 61

Tcnicas de Programao Avanada


O cdigo que implementa a operao insere apresentada na
Figura 43.

Figura 43: Implementao da operao insereNaFila.

A remoo deve guardar o valor que est no fim da Fila, atualizar o


ponteiro de Fim e liberar o nodo que estava no fim. Os seguintes
passos devem ser seguidos:
1. Se a Fila no est vazia
a. guarda o valor contido no nodo a ser eliminado (que
est no inicio da Fila)
b. guarda o endereo do nodo a ser eliminado (inicio) em
uma varivel auxiliar (aux)
c. inicio recebe o prximo de inicio
d. libera a rea apontada por aux
O cdigo que implementa a operao removeDaFila apresentado
na Figura 44.

Figura 44: Implementao da operao removeDaFila.

Pgina 62

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


O cdigo apresentado na Figura 45 ilustra a utilizao do TadFila.
Note que, fora a mudana nos arquivos de incluso, este programa o
mesmo que foi usado para testar a implementao da fila com
deslocamento.

Atividades
1. Adicionar a
TadFila.

operao

imprimeFila

ao

2. Adicionar a operao removePrioritario ao

TadFila. Esta operao deve permitir a remoo


com prioridade na Fila. A prioridade vai se basear
no valor inserido no campo item. A execuo de
removePrioritario deve remover o nodo da
fila cujo item for o maior.

Figura 45: Mdulo para teste do TAD Fila.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 63

Tcnicas de Programao Avanada

3. LISTAS E RVORES.
Ol, Neste Captulo continuaremos o nosso estudo
de Tipos Abstratos de Dados, focalizando
implementaes que utilizam alocao dinmica de
memria. Iremos estudar mais sobre listas
encadeadas e tambm sobre estruturas chamadas de
rvores. Nosso estudo de Listas baseia-se em
variaes do TAD Lista estudado no Captulo 2. Da
mesma forma como fizemos para a lista
simplesmente encadeada, para cada variao iremos
especificar e implementar as operaes para
inicializar a lista, inserir um elemento na lista,
remover e recuperar um elemento existente na lista.

3.1 LISTAS CIRCULARES


A primeira variao que estudaremos chama-se Lista Circular. Nessa
Lista, no existe o ltimo elemento. Aquele elemento da lista
simplesmente encadeada que antes apontava para NULL ir agora
apontar para o incio da Lista, criando ento um conjunto circular de
nodos.
e

prox

prox

prox

Figura 1: Lista Circular Simplesmente Encadeada

Com essa estrutura, em uma lista circular no temos mais a noo de


Fim de Lista (o nodo que apontava para NULL). A Figura 1 ilustra
uma lista encadeada circular contendo trs nodos. Conforme podemos
observar, essa estrutura pode ser implementada com nodos idnticos
aos de uma Lista simples. Entretanto a interface do TAD
ListaCircular ir apresentar algumas mudanas. A Figura 2
apresenta a implementao dessa interface.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 65

Tcnicas de Programao Avanada

Figura 2: Interface do TAD Lista (Circular). Similar a Lista simples.

Em uma Lista circular ir ter sempre um elemento de acesso, apontado


por uma varivel do Tipo Lista, por exemplo:
Lista l;

A operao de inicializao atribui NULL varivel l. A Figura 3


Apresenta essa implementao, que idntica de uma lista
simplesmente encadeada.

Figura 3: Implementao de inicializaLista para lista circular.

As inseres na lista podero ser feitas de duas formas: direita


(depois do nodo apontado por l) e esquerda (antes do nodo apontado
por l). A Figura 4 ilustra as operaes de inicializao e insero em
uma lista circular, supondo uma varivel l do tipo Lista. Na Figura os
valores 100h, 200h, .. representam os endereos de memria de cada
nodo da lista. Inicialmente l inicializada e no aponta para nenhum
endereo de memria. Em seguida, feita uma insero, que pode ser
tanto direita quanto esquerda. Nessa primeira insero, l passa a
apontar para o nodo inserido e o prox do nodo inserido aponta para ele
mesmo. Em seguida feita uma insero direita (depois) do nodo
apontado por l. Nesse caso, o prox do novo nodo recebe o valor do
prox de l e prox de l passa a ser o nodo inserido.

Pgina 66

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

NULL

inicializa Lista l

l
100h
e

100h

prox
1

100h

Insero - direita ou esquerda

l
100h
100h

200h
prox

prox

200h

100h

Insero direita

l
300h

300h
e

100h
prox

100h

200h
prox

200h

prox
2

300h

l
Insero esquerda

Figura 4: Seqncia de operaes em uma Lista Circular

A ltima operao uma insero esquerda, (antes) do nodo


apontado por l. Nessa operao, o procedimento se inicia de forma
idntica insero direita:
1. Cria novo nodo;
2. Prximo de novo nodo recebe o prximo de l;
3. Prximo de l recebe o endereo do novo nodo;
No entanto, ao final da operao de insero esquerda o
incio da lista passa a apontar para o nodo recm criado
(prximo dela).
A Figura 5 apresenta as implementaes dessas operaes.
Note que a operao insereaDireita usada na operao
insereaEsquerda. Aps a sua chamada apenas o valor de
l atualizado passando a apontar para o nodo recm
adicionado.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 67

Tcnicas de Programao Avanada

Figura 5: Implementao das operaes de insero

Para a operao de remoo iremos considerar duas possibilidades:


remoo direita e Remoo de um elemento arbitrrio.
300h
300h

100h
prox

200h
prox

100h

200h

prox
2

300h

l
300h
300h

200h
prox

200h

prox
300h

l
300h
300h

prox
3

300h

l
NULL

Figura 6: Seqncia de Remoes Direita

A remoo direita implica em remover o elemento que est direita


(depois) do elemento inicial da lista. Esse elemento exatamente o
elemento apontado pelo prox de do nodo inicial. A Figura 6 ilustra
uma seqncia de operaes de remoo direita sobre a lista l.
Conforme podemos observar, o valor de l permanece o mesmo
durante as remoes, mudando apenas quando a lista fica vazia. A
seguintes alteraes nos apontadores so necessrias:
se (l igual ao prximo de l)
l recebe NULL
seno
prximo de l recebe o prx do nodo a ser
eliminado.

A implementao de removeaDireita apresentada na figura 7.

Pgina 68

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 7: Implementao da Remoo direita

Pergunta: Por que no optamos por remover sempre


o elemento inicial da lista? Para responder a essa
pergunta, tente implementar essa operao. Voc
ver que vai necessitar alterar o valor do prox do
elemento que aponta para l. Como no temos acesso
direto a esse elemento por meio de l, ser necessrio
percorrer a lista inteira at encontr-lo. Assim essa
operao fica ineficiente.
A remoo de um elemento arbitrrio da lista a operao de
eliminao desse elemento, dada uma chave de busca do mesmo. Por
exemplo, suponha que queiramos eliminar o nodo da lista l com valor
2 (vide Figura 6) Nesse caso, o nodo que contm o elemento 2 deve
ser inicialmente localizado. Alm do nodo em si, necessrio
encontrar o nodo cujo prox aponta para o nodo a ser eliminado. Para
isso podemos usar dois apontadores auxiliares.
Na excluso, as seguintes situaes devem ser consideradas:
x

Remoo de um elemento genrico da lista que seja diferente


do elemento apontado por l;

Remoo do elemento da lista que apontado por l (incio da


lista);

Remoo do ltimo elemento da lista.


A Figura 8 ilustra esses casos.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 69

Tcnicas de Programao Avanada


300h
300h

100h
prox

200h
prox

100h

prox
2

200h

300h

l
300h
e

300h

Remoo do elemento 2

100h
prox

prox

200h

300h

l
Situao 1: Remoo de um elemento Genrico da lista
300h
300h

100h
prox

e
1

100h

200h
prox

prox
2

200h

300h

l
200h
Remoo do elemento 3

200h

100h

prox
2

100h

prox
200h

l
Situao 2: Remoo de elemento apontado por l
100h
100h

prox
100h

Remoo do elemento 1

NULL

l
Situao 3: Remoo do ltimo elemento da lista

Figura 8: Situaes para Remoo de um Elemento Arbitrrio da Lista

Na Situao 1, o elemento que se deseja eliminar o 2. Esse caso


pode ser considerado o caso normal da lista. Para eliminar esse
elemento, o prox do nodo anterior a ele (100h) dever apontar para o
prximo dele (300h). Na segunda situao, temos que o nodo a ser
eliminado o mesmo apontado por l (incio da lista). Nesse caso o
valor de l precisa ser atualizado, apontando para o anterior do nodo
que ser eliminado.
Na terceira situao o nodo a ser eliminado o ltimo. Logo, l precisa
ser atualizado para NULL. O seguinte algoritmo pode ser utilizado
para a remoo:
Elemento removeElemento(Lista l, int codigo){
se l est vazia
1. retorna elemento vazio
seno
2. localizo elemento
Se elemento procurado no existe
retorno elemento vazio
seno
3. o prximo do anterior do elemento procurado
recebe o prximo do elemento procurado
4. guardo o elemento a ser retornado
se o elemento procurado o elemento apontado por
l

Pgina 70

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


se a lista possui mais de um elemento
5. l recebe o anterior do elemento procurado
seno
6. l recebe NULL
7. retorna elemento

Figura 9: Implementao da operao removeElemento

A Figura 9 apresenta a implementao da operao removeElemento,


que remove um elemento arbitrrio da lista circular. paux1 e
paux2 so apontadores auxiliares utilizados para percorrer a lista,
localizar o nodo que contm o elemento procurado (paux2) e o
nodo anterior a ele (paux1).
Inicialmente, paux1 recebe o valor de l e paux2 o prximo de l. O
do{ ..}while(paux2!=*l); realiza a busca do elemento. Se o
elemento encontrado, a busca pra devido ao comando break. Se o
elemento no existe, a lista toda percorrida e a busca pra quando
paux2 obtm o valor de *l.
Ao terminar a busca, devemos verificar se o elemento foi realmente
encontrado. Se no foi encontrado, a operao retorna um elemento
vazio. Caso contrrio, a eliminao se d, fazendo o prox do paux1
apontar para o prox de paux2. Em seguida as situaes 2 e 3 (vide

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 71

Tcnicas de Programao Avanada


Figura 8) de remoo so verificadas e, se necessrio, o valor de l ser
atualizado.
As demais operaes do TAD (imprime e pesquisa) baseiam-se em
varreduras na lista a partir do nodo inicial. Para essas operaes,
sempre utilizado um apontador auxiliar, que ao final de cada repetio
no lao de busca atualizado recebendo o prximo nodo da lista.
Esse apontador inicializado com o valor do nodo inicial da lista e a
condio de parada ele voltar a ser igual ao endereo do nodo inicial.
Por isso, utilizamos sempre o do{ .. }while(..); em vez de
while(..){ .. }. Mesmo sendo iniciado com o valor do
endereo inicial, quando o teste do lao atingido, o apontador
auxiliar atualizado, passando a apontar para o seu prximo. Assim,
somente depois de percorrer a lista inteira que o apontador auxiliar
valer novamente o endereo do nodo inicial. As figuras 10 e 11
apresentam as implementaes das operaes pesquisaNaLista,
imprimeLista e imprimeListadeNomes, que utilizam essa
tcnica.

Figura 10: Implementao da operao pesquisaNaLista

A operao pesquisaNaLista visa procurar um elemento cujo


cdigo igual ao valor de codigo (argumento da funo).
O TAD Elemento
A estrutura do elemento armazenado na lista a
mesma do TAD elemento armazenado na lista
simplesmente encadeada. Foi adicionada mais uma
operao, chamada imprimeNome, que imprime
apenas o nome do elemento. Assim, a interface do
TAD Elemento utilizado nessa implementao de
listas circulares possui a seguinte estrutura:

Pgina 72

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 11: Operaes imprimeLista e imprimeListaDeNomes

As duas operaes de impresso adotam a mesma estratgia. A


diferena entre elas que a operao imprimeLista vai imprimir
todos os dados de cada elemento. J a operao
imprimeListasDeNomes vai imprimir somente os nomes de cada
elemento, usando uma formatao que facilita a depurao e o
entendimento das operaes. O programa mdulo principal da

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 73

Tcnicas de Programao Avanada


implementao de listas circulares utiliza essa operao e apresenta
sua impresso. A Figura 12 apresenta a funo testeListaCircular.

Figura 12: Implementao do Mdulo Principal para Testar a ListaCircular.

Pgina 74

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


Aps a execuo de testeListaCircular a seguinte sada
gerada:

Cada linha da sada o resultado de uma chamada de


imprimeListaDeNomes.

Atividades
a) Implementar
uma
operao
insere
ordenado. Utilizando essa operao para inserir
elementos, a partir do nodo inicial da lista, o
prximo de cada elemento deve ser maior que o
seu antecessor;
b) Implementar uma operao para concatenar duas
listas circulares A e B. O resultado deve ser uma
lista contendo todos os elementos das duas listas,
de forma alternada. Ou seja: o primeiro da lista A,
o primeiro da lista B, o segundo da lista A, o
segundo da lista B, e assim sucessivamente.

3.2 LISTA CIRCULAR DUPLAMENTE ENCADEADA


Muitas operaes envolvendo listas encadeadas podem ser facilitadas
se cada nodo conhecer o seu antecessor. Uma lista circular duplamente
encadeada possui exatamente essa caracterstica. Alm do apontador
para o prximo elemento, cada nodo da lista vai ter um apontador para
o elemento anterior.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 75

Tcnicas de Programao Avanada

NULL

inicializaLista
100h

l
ant

100h

100h

e
1

prox
100h

Insere(1)

100h

200h
ant

200h

e
2

100h

ant

prox
100h

200h

e
1

prox
200h

Insere(2)

300h
300h

ant
100h

e
3

100h

200h

prox

ant

200h

300h

e
2

prox
100h

ant
200h

e
1

Insere(3)

prox
300h

Figura 13: lista duplamente encadeada

A Figura 13 ilustra uma seqncia de inseres em uma lista circular


duplamente encadeada. Inicialmente a lista est vazia: l possui o valor
NULL. Os campos ant e prox so respectivamente os apontadores
para os nodos anterior e prximo de cada nodo da lista. No modo de
insero adotado, temos duas situaes distintas ao inserir um
elemento: A lista est vazia ou a lista no est vazia. Quando a lista
est vazia, l, o prximo e o anterior do novo nodo recebem todos o
mesmo valor: o endereo do novo nodo. Isto mostrado na insero
do elemento 1 (um) na lista). Quando a lista no est vazia, alm dos
apontadores do prox e ant do novo nodo, os apontadores do nodo
anterior e posterior ao nodo apontado por l (alm do prprio l) devero
tambm ser atualizados. Observe as inseres dos elementos 2 e 3 na
lista e veja como os ponteiros so modificados. Para manter o
encadeamento correto, as seguintes atualizaes so necessrias:
1. O prximo do anterior a l recebe o novo
nodo;
2. O prximo do novo nodo recebe l;
3. O anterior do novo nodo recebe o
anterior de l;
4. O ponteiro anterior de l recebe p;
5. l recebe o endereo do novo nodo.
Esses passos esto identificados com os nmero de 1 a 5 na
implementao da insero (Figura 15).

Pgina 76

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Ateno: Na Figura 13, a varivel l do tipo ponteiro


para o nodo da lista. Na implementao que iremos
apresentar, essa varivel ir sempre apontar para o
ltimo nodo inserido na lista. Contudo, outras
implementaes so possveis.
Como de costume, implementaremos a lista circular duplamente
encadeada como um Tipo Abstrato de Dados. A Figura 14 apresenta a
interface desse TAD.

Figura 14: Interface do TAD Lista Circular Duplamente Encadeada

A inicializao segue o mesmo princpio de uma lista simplesmente


encadeada. O apontador inicial da lista aponta para NULL. A
implementao da operao inicializaLista idntica da lista
Circular (Figura 3). Na implementao da operao de insero,
iremos considerar o modo apresentado na Figura 13. A Figura 15
apresenta a implementao das operaes inicializaLista e
insereNaLista. Iremos considerar uma lista de elementos do tipo
Elemento definido para a lista circular (vide TAD Elemento, pag. 59).

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 77

Tcnicas de Programao Avanada

Figura 15: Implementao das operaes inicializa e insere

Iremos apresentar duas formas de remoo: Remoo do elemento


apontado por l e remoo de um elemento arbitrrio.

Figura 16: Eliminao do nodo apontado por l

A Figura 15 apresenta a implementao da operao de remoo do


nodo apontado por l. Para tornar a implementao mais simples foram
usados dois apontadores (do tipo Lista) auxiliares: proximo e
anterior. O elemento a ser removido (apontado por l) o
elemento entre o prximo e o anterior. Assim, para manter o
encadeamento, prximo e anterior devero apontar um para o outro.
Como o nodo apontado por l vai ser eliminado, o valor contido em l
deve ser atualizado, passando a apontar para proximo.

Pgina 78

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

300h
300h

ant
100h

e
3

ant

prox
200h

300h

200h

100h

200h
e
2

ant

prox
100h

200h

100h

e
2

prox
300h

200h

100h

proximo

anterior

200h
ant

e
1

100h
prox
100h

ant
200h

e
1

prox
200h

Figura 16: Remoo do nodo apontado por l

Novamente, caso a lista no esteja vazia, duas situaes so possveis


e necessitam de tratamentos diferentes: A lista possui apenas um (1)
nodo ou a lista possui mais de um nodo. Caso a lista possua apenas
um nodo, basta guardar o contedo do elemento a ser eliminado,
liberar o nodo e atribuir NULL a varivel l.
J quando a lista possui mais de um nodo, a seguinte seqncia de
atualizaes dos apontadores deve ocorrer:
1. anterior recebe o anterior de l;
2. prximo recebe o prximo de l;
3. prximo de anterior recebe prximo;
4. Anterior de prximo recebe anterior;
5. Libera o nodo apontado por l;
6. Faz l apontar para prximo.
Na Figura 15 essa seqncia enumerada com os nmero de 1 a 6.
A operao de remoo de um elemento arbitrrio semelhante
eliminao em uma lista circular simplesmente encadeada. O nodo
contendo o elemento procurado deve ser localizado na lista por meio
de uma busca seqencial. Em caso de sucesso (se o elemento existir
na lista), tanto os apontadores do nodo anterior ao eliminado quanto os
do nodo posterior devem ser atualizados tambm. A Figura 17
apresenta a implementao dessa operao. So consideradas as
seguintes situaes:
1.
2.
3.
4.

A lista est vazia;


O elemento procurado no existe;
S existe um nodo na lista (a lista vai ficar vazia!);
O nodo a ser eliminado o nodo apontado por l.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 79

Tcnicas de Programao Avanada

Figura 17: Operao de remoo de um elemento arbitrrio

Para imprimir a lista, implementamos duas operaes:


imprimeSentidoHorario e
imprimeSentidoAntiHorario. A Figura 18 apresenta essas
operaes.

Pgina 80

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 18: Operaes de Impresso da Lista.

Por ltimo, temos a operao pesquisaNaLista. Essa operao


pode ser feita de forma idntica operao pesquisaNaLista
para listas circulares simplesmente encadeadas (Figura 10). Assim,
no iremos repetir seu cdigo aqui. No entanto, esse cdigo pode ser
encontrado no mdulo ListaDupla, implementado e
disponibilizado no ambiente de aprendizado.

Atividades
2. Implementar uma operao para remover os elementos
de uma lista cujo cdigo maior que 10.
Implementar uma funo removeEntrePares que
remove os elementos que so pares da lista. Ou seja, o
anterior e o prximo do elemento so elementos cujo
cdigo um nmero par.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 81

Tcnicas de Programao Avanada


3.3 RVORES BINRIAS

At o presente momento, focalizamos o estudo de


estruturas de dados encadeadas lineares ou
seqenciais. Nessas estruturas, existe a noo de
antecessor e prximo, para cada nodo. Nesta Seo
iremos estudar uma nova estrutura encadeada
denominada rvore. Essas estruturas so chamadas
assim pela semelhana de sua estrutura com as
ramificaes de uma rvore.

Conceitualmente, uma rvore um tipo especial de um modelo


matemtico denominado grafo. Em termos de estrutura de dados,
uma rvore um conjunto de nodos ligados. Um desses nodos
denominado raiz. Os demais nodos da rvore so acessados a partir
do nodo raiz.
rvore Binria
Uma rvore binria um tipo especial de rvore que
possui uma estrutura formada por:
x

Um nodo raiz

Uma sub rvore esquerda

Uma sub rvore direita

A Figura 20 apresenta uma rvore binria. O nodo contendo o valor


10 o nodo raiz. Esse nodo permite o acesso as subrvores esquerda e
direita. Note que a definio recursiva. Assim como o nodo raiz, o
nodo 5 tambm possui ligaes para as suas subrvores esquerda e
direita. Os nodos que no possuem nenhuma subrvore so chamados
de nodos folha. Na Figura 20, os nodos 1, 3, 6, 8, 11, 14 e 20 so
nodos folha. Um nodo pode tambm possuir apenas a subrvore
esquerda ou a subrvore direita. Na Figura 20, o nodo 18 possui
apenas a subrvore direita. Em rvores, usamos tambm a
terminologia Filho e Pai para caracterizar os nodos. Um nodo pai em
uma rvore binria pode possuir dois filhos, o filho esquerdo (raiz da
subrvore esquerda) e o nodo direito (raiz da subrvore direita).

Pgina 82

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


3.3.1 rvore Binria de Pesquisa
Uma rvore binria pode ser usada como uma estrutura altamente
eficiente para a busca de informaes. Essa estrutura chama-se rvore
binria de pesquisa.
rvore Binria de Pesquisa
Uma rvore Binria de Pesquisa uma rvore Binria
na qual:
x Os nodos possuem uma chave de busca nica;
x Considerando a chave de busca, os elementos da
sub-arvore esquerda so menores que o
elemento do nodo raiz e os elementos da
subrvore direita so maiores que a do nodo
raiz.

A rvore da Figura 20 uma rvore de binria de pesquisa.


Nodo RAIZ
10
sub-rvore
direita

sub-rvore
esquerda
15

12

11

18

14

NULL

20

Figura 20: rvore Binria de Pesquisa

Note que todos os elementos da subrvore esquerda do nodo raiz so


menores que 10 e todos os elementos da subrvore direita so maiores
que 10. Essa regra aplicvel em todas as ramificaes das
subrvores. Por exemplo, a subrvore esquerda do nodo 5 s possui
elementos menores que 5. J a subrvore direita desse nodo s possui
elementos maiores que 5.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 83

Tcnicas de Programao Avanada

Atividades
1. Desenhe uma rvore binria de busca cuja
seqncia de inseres de elementos foi: 30 10 20
50 35 e 44.
2. Desenhe uma rvore binria de pesquisa, em que
as chaves so letras para a insero da seqncia
de letras que compem o seu nome e seu
sobrenome, excluindo as repeties e partindo de
uma rvore inicialmente vazia.
3.

Desenhe uma rvore resultante da retirada da 3 e


da 8 letra da seqncia composta por seu nome +
sobrenome.

3.3.2 O TAD rvore Binria de Pesquisa


Para tornar a manipulao de rvores binrias de pesquisa mais
simples, iremos definir um tipo abstrato de dados, considerando suas
operaes primitivas. Essas operaes so apresentadas na Figura 21.

Figura 21: especificao do TAD rvore.

Pgina 84

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


A inicializao da rvore leva essa rvore para o estado de vazia, sem
nenhum nodo. Essa operao s deve ser utilizada no incio da
operao da rvore. Aps isto, uma rvore s se tornar vazia se todos
os seus elementos forem excludos.
As operaes de insero devem respeitar a regra bsica da rvore
binria de pesquisa: Toda subrvore esquerda de um nodo N s
possui elementos com chaves de busca menores que a do nodo N; e
toda subrvore direita de um nodo N s possui elementos com
chaves de busca maiores que a do nodo N. Assim, ao inserir um
elemento na lista, deve-se definir a posio em que ele ser inserido,
com base nessa regra.
A operao de pesquisa visa encontrar um elemento contido na rvore
dada, um valor de chave de busca. Essa pesquisa deve se basear
tambm nessa regra. Isso tornar a pesquisa extremamente eficiente se
comparada com a pesquisa em uma lista seqencial. Por exemplo,
suponha que estejamos procurando o elemento 8 na rvore da Figura
20. A pesquisa inicia-se pelo nodo raiz (10). As chaves so
comparadas. Como 8 menor que 10, sigo a pesquisa pela rvore
esquerda e comparo 8 agora com o nodo (5). Dessa vez (8) maior e
agora sigo pela subrvore direita, comparando com o nodo (7). Mais
uma vez, 8 maior e sigo procurando na subrvore direita onde
finalmente o nodo 8 encontrado.
A remoo deve seguir o mesmo princpio da pesquisa para localizar o
nodo a ser removido. A remoo em si tambm deve ser
implementada de forma que a regra de rvores binrias de pesquisa
no seja violada.

3.3.3 Implementao do TAD rvore Binria de Pesquisa


A Figura 22 apresenta a implementao da interface do TAD
rvoreBinria.

Figura 22: Interface do TAD rvore Binria

O nodo da rvore possui, como nas implementaes anteriores, o


campo de informao e o do tipo Elemento. Cada nodo da rvore

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 85

Tcnicas de Programao Avanada


possui tambm dois apontadores, esq e dir, que apontam
respectivamente para as subrvores esquerda e direita do nodo.
Alm das operaes j previstas no TAD, inclumos a operao
imprimeOrdemCrescente.
Quando declaramos uma varivel do tipo Arvore, estamos definindo
uma varivel capaz de armazenar um ponteiro para struct nodo.
Usaremos essa varivel para apontar para o nodo raiz da rvore. Se
ainda no existe nenhum nodo na rvore, esse ponteiro deve apontar
para NULL. A operao de inicializao idntica s operaes de
inicializao de listas encadeadas e atribui NULL ao ponteiro que
aponta para a raiz da rvore. A Figura 23 apresenta est operao

Figura 23: Implementao da operao de inicicalizao da rvore.

Recursividade
rvores so estruturas definas recursivamente. Dessa
forma, a recursividade ser um mecanismo
fundamental para simplificar a implementao das
operaes sobre essas estruturas. Caso voc no esteja
se sentido seguro quanto recursividade, recomendo
que volte ao material de programao II e estude o
assunto.
Insero em rvores Binrias de Pesquisa
A operao de insero pode ser descrita pelo seguinte algoritmo:

Pgina 86

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Esse algoritmo tenta inserir o elemento em uma subrvore ainda vazia.


O algoritmo se inicia recebendo um ponteiro para o nodo raiz da
rvore. Se o ponteiro no apontar para NULL, a rvore no estar vazia
e a raiz j est ocupada. Assim, existem duas opes: Inserir o
elemento esquerda da raiz ou direita. Essa deciso tomada
comparando-se a chave de busca (cdigo) do nodo a ser inserido com
a chave de busca do nodo da raiz. Se a chave do nodo a ser inserido
menor que a do nodo raiz, o algoritmo tenta inserir na sub arvore
esquerda. Se for maior tenta-se inserir na subrvore direita. Lembrese de que na rvore binria de pesquisa as chaves de busca so nicas.
Ou seja, no pode haver dois ou mais nodos com a mesma chave.
Assim se o cdigo do nodo a ser inserido for igual ao cdigo do nodo
raiz, o algoritmo termina e no corre a insero.
Por exemplo, suponha a insero de um elemento com cdigo igual a
4 na rvore da Figura 20. Nesse caso, o algoritmo se inicia
comparando 4 com 10 (raiz da rvore). Como 4 menor, a operao
novamente executada (recursivamente), agora tentando inserir o 4 na
subrvore esquerda da raiz. Esse processo se repete recursivamente
at que a subrvore direita do nodo 3 seja atingida. Essa subrvore
vazia. Conseqentemente, o ponteiro dir do nodo 3 est apontando
para NULL. O algoritmo ento aloca o nodo para o elemento com
cdigo igual a 4 e atribui o endereo desse novo nodo ao ponteiro
dir do nodo 3.
A Figura 24 ilustra a rvore da Figura 20, agora com o nodo 4
inserido. A linha pontilhada mostra o percurso das chamadas

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 87

Tcnicas de Programao Avanada


recursivas at a insero do elemento. A Figura 25 apresenta a
implementao da funo de insero. Essa operao recebe como
parmetros um ponteiro para rvore (*t) e o elemento a ser inserido
(e).
Nodo RAIZ
10
sub-rvore
direita

sub-rvore
esquerda
15

12

11

18

14

NULL

20

Figura 24: Insero do elemento 4 na rvore.

O primeiro if testa se o valor de *t NULL. Nesse caso o elemento


inserido. Caso contrrio, ocorrem chamadas recursivas da funo
insere, para a esquerda ou para a direita, conforme algoritmo. ainda
possvel que o elemento j exista na rvore. Nesse caso a mensagem
J existe um nodo com esta chave! impressa.
As chamadas recursivas so feitas passando o endereo dos
apontadores: insere(&(*t)->esq,e); ou insere(&(*t)>dir,e); Isso necessrio, pois o contedo desses apontadores
dever ser alterado na insero.

Pgina 88

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 25: TAD Arvore Binria: implementao da operao Insere.

Figura 26: TAD Arvore Binria: implementao da operao Pesquisa

Atividades
4. Desenhar a insero dos elementos 13, 0 e 16 na
rvore da Figura 24.
Pesquisa em rvores Binrias de Pesquisa
A operao pesquisa visa retornar um elemento contido na rvore
t, sendo passado um valor de cdigo (chave de busca). O Elemento
encontrado deve ser passado por meio do parmetro ret, que um
ponteiro para Elemento. Essa operao tambm implementada de
forma recursiva e deve receber o endereo da raiz da rvore. Como a
rvore no sofre alteraes na pesquisa, apenas o valor do endereo do
nodo raiz e (e das subrvores nas chamadas recursivas) suficiente.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 89

Tcnicas de Programao Avanada

Eficincia da Pesquisa
A eficincia da pesquisa em uma rvore binria de
pesquisa a sua maior vantagem. Para localizar um
elemento em uma rvore com N elementos e construda
aleatoriamente, so necessrias aproximadamente log2
N consultas. Para se ter um idia do que isso representa,
uma pesquisa seqencial em uma lista linear contendo
1,000,000 de elementos realiza em mdia 500,000
consultas para encontrar um elemento. Em uma rvore
essa mesma pesquisa gastaria log2 1,000,000 20
consultas.
Isso acontece porque, a cada verificao, metade dos
dados
a
serem
pesquisados

descartada
(correspondente a subrvore direita ou esquerda do
elemento verificado).
A pesquisa s degradada quando a rvore construda
de tal forma que a sua estrutura se torna uma lista
linear. Isso acontece, por exemplo, se os elementos da
rvore forem inseridos em ordem, de acordo com a
chave de busca. Por Exemplo, a construo de uma
rvore com a seqncia 1, 2,3,20,30, 40,41,42, vai
produzir uma lista linear.
Remoo em rvores Binrias de Pesquisa
Para a remoo de um elemento da rvore devemos considerar dois
casos distintos:
1. O elemento a ser removido est em um nodo que possui, no
mximo, uma subrvore;
Nesse caso, a remoo mais simples, podendo ocorrer:
a) quando esq do nodo aponta para NULL;
b) quando dir do nodo aponta para NULL;
c) quando esq e dir apontam para NULL.
2. O elemento a ser removido est em um nodo que possui as
duas subrvores.
A Figura 27 apresenta a remoo do elemento 11 que no possui
filhos, ou seja, no possui nem subrvore direita nem esquerda.

Pgina 90

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


Remoo do elemento 11

15

12

15

18

14

11

12

18

20

14

20

Figura 27: Removendo Elemento sem Filhos.

Nesse caso a remoo simples, bastando que o elemento seja


encontrado e o nodo removido.
15

Remoo do elemento 18

15
12

18
12

11

14

20

20
11

14

Figura 28: Removendo um Elemento com Apenas um Filho

A Figura 28 apresenta a remoo do elemento 18, que possui


subrvore direita. Nesse caso, como o nodo no possui subrvore
esquerda, basta que o filho direito (20) ocupe o lugar do elemento 18.
Isso pode ser realizado fazendo o apontador dir do nodo 15 apontar
para o filho direito do nodo 18. Quando o nodo s possui subrvore
esquerda, essa operao ocorre de maneira simtrica. Ou seja, o nodo
a ser eliminado substitudo por seu filho esquerdo.
A Figura 29 apresenta agora a remoo de um nodo que possui as
duas subrvores. Nessa situao, a remoo pode ser feita de duas
maneiras: substituindo o elemento removido por seu sucessor ou
substituindo o nodo removido por seu antecessor.
Sucessor e antecessor de um nodo em uma rvore
binria de busca
Sucessor - Filho mais esquerda de sua subrvore
direita.
Antecessor - Filho mais direita de sua subrvore
esquerda.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 91

Tcnicas de Programao Avanada


Remoo do elemento 15
Troca pelo sucessor

18
15
12
12

18
14

11
11

20

14

20
14
Troca pelo antecessor

12

11

18

20

Figura 29:Remoo de um Nodo que Possui as Duas Subrvores.

O sucessor do nodo 15 o nodo 18 e representa o elemento que


sucede o 15, considerando a ordenao dos elementos na rvore, pela
chave de busca. Considerando a rvore do exemplo, temos a seguinte
ordem de sucesso: [11,12,14,15,18,20]. O antecessor, por outro lado,
o nodo que possui o elemento imediatamente maior que o elemento
a ser removido. No caso, o antecessor de 15 o elemento 14.
Por que sucessor e antecessor?
Devemos substituir o nodo por seu sucessor ou seu
antecessor para no violar a regra de formao da
rvore binria de pesquisa, em que devemos ter
elementos menores esquerda de cada nodo e
elementos maiores direita de cada nodo.
Para implementar a remoo, primeiramente temos que localizar o
nodo a ser removido. Para isso utilizamos recursividade. A
Figura 30 apresenta o incio da operao de remoo. O elemento a ser
eliminado o elemento com chave de busca igual a cdigo. A
operao faz a busca pelo elemento a ser eliminado na rvore,
posicionando t na varivel ponteiro (*t) que aponta para o nodo a
ser eliminado. Por exemplo, no caso da remoo do nodo 11, essa
varivel corresponde ao ponteiro esq do nodo 12.

Pgina 92

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 30: Incio da Operao de Remoo: o Nodo Localizado.

Caso o nodo com o cdigo procurado no exista, a pesquisa segue at


achar um apontador que aponte para NULL. Enquanto isso no ocorre
e o elemento no encontrado, a busca segue ou para a subrvore
esquerda ou para a subrvore direita. Quando o elemento
encontrado (o ltimo else executado) , a operao precisa verificar
se o elemento a ser eliminado est no caso 1 (um nodo que possui, no
mximo, uma subrvore) ou no caso 2 (em um nodo que possui duas
subrvores) .
Vamos discutir separadamente os casos 1 e 2.
A Figura 31 apresenta o excerto de cdigo de que trata o caso 1. Para
esse caso, basta verificar que uma das subrvores vazia. O Fato das
duas serem vazias indiferente. Optamos por testar primeiro se a
subrvore esquerda vazia. Nesse caso, uma varivel auxiliar (aux)
usada para guardar o valor do endereo do nodo a ser eliminado. O
ponteiro que antes apontava para o nodo a ser eliminado (t) passa a
apontar para o nodo direita. Caso a subrvore esquerda no seja
vazia, verificamos se a subrvore direita vazia. Nesse caso, o
ponteiro t passa a apontar para o nodo esquerda do nodo a ser
eliminado. Em ambos os casos, o nodo eliminado liberado por meio
da funo free.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 93

Tcnicas de Programao Avanada

Figura: 3.31: Remoo: verificado se o nodo possui no mximo uma subrvore.

Figura 32: Remoo quando o nodo possui as duas subrvores.

A Figura 32 apresenta a implementao do caso 2 (o nodo possui as


duas subrvores). Para facilitar essa operao, em vez de eliminarmos
o nodo que contm o elemento a ser eliminado, o contedo do nodo a
ser eliminado ser substitudo pelo seu antecessor e o nodo antecessor
que ser eliminado. Esse procedimento realizado pela operao
antecessor, chamada pela funo remove.

Figura 33: Implementao da Operao Antecessor.

A Figura 33 apresenta a implementao dessa operao, que tambm


utiliza recursividade para a localizao do nodo antecessor. Veja na
Figura 32 que a chamada de antecessor passa:

Pgina 94

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


x o endereo do nodo a ser eliminado (*t), no lugar do
parmetro q;
x o ponteiro para subrvore esquerda do nodo a ser eliminada
((*t)->esq), no lugar do parmetro r;
Conforme a definio de antecessor (pag. 76), a partir da raiz da
subrvore esquerda, so feitas chamadas recursivas passando sempre
o ponteiro para a subrvore direita, at que o nodo mais direita seja
encontrado. Quando isso ocorre, a recursividade determina a execuo
das seguintes aes:
Substituir o elemento do nodo a ser eliminado pelo elemento
de seu antecessor :
q->e=(*r)->e;
2. Guardar o endereo do antecessor em uma varivel auxiliar:
paux = *r;
3. Fazer a referncia para o antecessor receber o endereo do
filho esquerdo do antecessor: *r= (*r)->esq;
4. Remover o nodo que possua o antecessor: free(paux);
1.

*t

*t

15

14
r

12

11

12

18

14

20

11

18

14

13

20
paux

13

antecessor(*t,&((*t)->esq));
q

*t

antecessor(q,&(*r)->dir);
..
q->e=(*r)->e;
paux = *r;

14
q

*t

12

14
18
r

12
11

14

11
13
*r= (*r)->esq;

18

20
paux

20

13

free(paux);

Figura 33: Remoo do elemento 15 da lista. O antecessor o elemento 14.

A Figura 34 ilustra a execuo da operao antecessor desde a sua


chamada para eliminar o elemento 15. Nessa rvore, veja que o
antecessor o nodo 14, que possui subrvore esquerda. Assim, ao

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 95

Tcnicas de Programao Avanada


final da remoo, o ponteiro dir do nodo que contm o elemento 12
vai ter que apontar para o nodo esquerda de 14.

Atividades
5. Implementar a funo sucessor, equivalente a
antecessor usada na operao remove. Depois,
modificar a operao remove para que o elemento a ser
removido seja substitudo por seu sucessor.
Impresso em rvores de Pesquisa Binria
Para imprimir os elementos de uma rvore binria de busca, basta
percorrer a rvore usando recursividade. possvel, inclusive,
imprimir os elementos da rvore em ordem, crescente ou decrescente.
O Cdigo da Figura 34 apresenta a implementao da impresso em
ordem crescente.

Figura 34: impresso dos elementos em ordem crescente.

Essa operao visita todos os nodos da rvore, fazendo chamadas


recursivas esquerda e direita de cada nodo. Quando um nodo folha
esquerda encontrado:
x a recursividade interrompida;
x o elemento desse nodo impresso;
x a recursividade ativada, chamando o nodo direita do nodo
impresso;
Essa forma de impresso baseia-se no caminhamento central, no qual
os elementos sero visitados ordenadamente.

Pgina 96

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

18

12

11

20

14

imprime(18)// esq
imprime(12)//esq
imprime(11)//esq
fim da recursao
printf(11)
printf(12)
imprime(14) // dir
fim da recursao
printf(14)
printf(18)
imprime(20)//dir
fim da recursao
printf(20)

Figura 35: Seqncia de impresso para o Caminhamento Central.

A Figura 35 ilustra a execuo da operao de impresso utilizando


caminhamento central. A ocorrncias de imprime correspondem
ordem das chamadas recursivas da operao imprimeElemento
da Figura 34. Veja que essa representao meramente algortmica
(no usamos ponteiros). O comando printf corresponde ao
printf na implementao da Figura 34.
Implementamos, alm do TAD ArvoreBinaria, um mdulo
(principal) para teste. No apresentamos esse mdulo aqui, mas o
mesmo se encontra disponvel no material on-line.
Anlise da rvore Binria de Pesquisa
Conforme citamos no incio dessa seo, rvores
binrias de pesquisa so excelentes estruturas para o
armazenamento e a recuperao de informaes. Isso
se deve eficincia de suas operaes de insero,
remoo e pesquisa. J comentamos a eficincia da
pesquisa. A insero e a remoo eficientes tornam o
custo de manuteno dos dados baixo. Ou seja, novos
dados podem ser inseridos e outros removidos sem
comprometer a eficincia do sistema. Outra facilidade
a listagem ordenada dos dados (impresso), que nem
sempre possvel em estruturas de pesquisa. Usando
Hashing (Cap. 4) por exemplo, no possvel listar os
dados ordenadamente.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 97

Tcnicas de Programao Avanada

Atividades
6. Implementar a operao imprime de forma que os
elementos da rvore sejam impressos:
x

em ordem decrescente

x na ordem em que foram inseridos


Utilize o TAD rvore Binria para implementar uma
agenda telefnica de celular. Veja as funes de agenda
existentes em um telefone celular e tente implement-las.

Enfim, terminamos este captulo. Como comum no


estudo de estruturas de dados dinmicas, este captulo
deve ter exigido de voc um grande esforo de
concentrao e de raciocnio lgico. Espero que tenha
realizado todas as tarefas e estudado de forma
complementar o livro texto, pois, somente assim, o
estudo ter o efeito desejado. At o prximo captulo!

Pgina 98

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

4. PESQUISA EM MEMRIA PRIMRIA.


Ol! Iremos neste Captulo tratar do assunto
pesquisa. A palavra pesquisa, aqui, tem o
significado estrito de busca. Iremos buscar objetos
de informao. Voc certamente j pesquisou
muitas coisas na sua vida: brinquedos, roupas,
chaves, livros e pessoas esto entre as coisas que
mais procuramos! Se voc j fez isso, j deve ter
se aborrecido ao no encontrar (ou demorar muito
para encontrar) o objeto ou pessoa que procura.
Mas, ao demorar a encontrar um objeto, voc j se
perguntou se est procurando da maneira correta?
Normalmente,, difcil encontrar algo em um
conjunto de elementos se no usarmos a estratgia
de busca apropriada para o modelo de organizao
do conjunto? Neste Captulo iremos discutir e
aprender sobre essas estratgias de busca e discutir
aspectos da pesquisa de diferentes organizaes do
conjunto onde procuramos. Mo obra ento!
A pesquisa em memria primria envolve a busca por objetos de
informao armazenados em estruturas de dados instanciadas na
memria primria do computador. No iremos tratar aqui da pesquisa
em memria secundria, que envolve outras tcnicas.
Nosso estudo vai compreender a pesquisa simples, onde sabemos
exatamente qual o objeto que queremos. Normalmente sabemos qual
esse objeto por meio de uma informao que o diferencia de todos os
demais objetos. Chamaremos essa informao de chave de pesquisa.
Chave de Pesquisa
A pesquisa em memria primria ser feita com
base em uma CHAVE DE PESQUISA. A chave
de pesquisa pode ser um elemento de dado do
objeto. Por exemplo, o RG de uma pessoa, o CNPJ
de uma empresa ou o nmero de matrcula de um
estudante. Pode ser tambm o nome de um pas, ou
o ISBN de um livro. O importante da chave de
pesquisa que ela seja nica, de forma a permitir
que cada elemento do conjunto seja unicamente
identificvel pela sua chave de pesquisa.
A idia bsica da pesquisa, portanto, : dado um conjunto de dados e
uma chave, localizar um elemento nesse conjunto cujo valor da chave
de pesquisa seja o mesmo da chave usada. A chave de pesquisa

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 99

Tcnicas de Programao Avanada


escolhida e definida pelo programador com base no problema
especfico que ele est tratando. Por exemple, em um conjunto de
dados que cataloga os computadores de uma empresa, a chave de
pesquisa pode ser o nmero de srie do computador ou de seu
patrimnio.
O conjunto pode ser organizado e armazenado usando diferentes
estruturas e tipos abstratos de dados: Vetores, listas encadeadas,
rvores. J estudamos no captulo anterior o algoritmo de pesquisa em
listas e em rvores binrias de pesquisa. Neste captulo iremos analisar
em maiores detalhes esses e outros algoritmos.
Em uma pesquisa, o conceito de eficincia muito importante. A
eficincia pode ser medida pelo nmero de inspees realizadas at
encontrar o objeto procurado. Evidentemente, quanto menos inspees
forem feitas, mais eficiente ser a pesquisa.
Inspeo
Uma inspeo consiste na operao de comparao
da chave procurada com a chave de busca de um
objeto, visando verificar se o objeto em questo
que procuramos.
Iremos estudar algoritmos de pesquisa para as trs seguintes situaes:
1. Os dados esto dispostos de forma desordenada e desconhecida
em uma lista linear (um vetor ou uma lista encadeada). Esse
cenrio pode ser comparado a uma busca onde no h pistas
sobre em que lugar o objeto est. Dessa forma, a nica
alternativa que temos realizar uma busca exaustiva visitando
todos os lugares at o objeto ser encontrado. A nica forma de
determinar se o objeto no est presente inspecionar todos os
lugares.
2. Os dados esto dispostos de forma ordenada em uma lista
linear (um vetor ou uma lista encadeada). Nesse cenrio, a
busca facilitada porque os objetos foram guardados usando
alguma forma de ordenao baseada na chave de busca. Se os
objetos forem armazenados, por exemplo, colocando os
objetos em uma seqncia iniciando pelo menor e terminando
pelo maior, a busca poder ser feita sem a necessidade de
inspecionar todos os objetos.
3. Os dados esto dispostos em de forma no ordenada, porm as
posies onde os dados esto localizados podem ser
calculadas usando a chave de pesquisa. Essa situao a que
acontece nas chamadas tabelas Hash onde os elementos so
inseridos em posies calculadas a partir de sua chave de
pesquisa.

Pgina 100

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


Iremos estudar a aplicao de trs mtodos de ordenao aplicveis a
esses cenrios. Os mtodos consistem em Pesquisa Seqencial,
Pesquisa Binria e Hashing. As sees a seguir detalham esses
mtodos.

Atividades
Suponha um baralho contendo 40 cartas todas
diferentes, distribudas de forma totalmente aleatria.
Pense em uma carta especfica e responda:
a) Qual a propobilidade da primeira carta do
baralho ser a que voc pensou?
b) Qual a propobilidade da segunda carta ser a
que voc pensou? E da terceira?
c) Qual a probabilidade de encontrar a carta aps
4 tentativas?
d) Em mdia quantas cartas tero que ser

inspecionadas para voc encontrar a carta que


pensou?

4.1 PESQUISA SEQENCIAL


A pesquisa seqencial realizada inspecionando-se o conjunto de
objeto seqencialmente, do incio para o fim ou vice-versa. Duas
situaes podem ocorrer:
Pesquisa com sucesso: O elemento encontrado em uma das
posies do conjunto
Pesquisa sem sucesso: O conjunto e completamente percorrido e o
elemento no encontrado.
Normalmente fazemos dois testes: verificamos se o elemento
procurado corresponde ao objeto inspecionado e verificamos se o
limite do conjunto de objetos foi atingido. Por exemplo, o cdigo
abaixo faz isso:

Para melhorar essa implementao, iremos apresentar um algoritmo


de pesquisa seqencial que utiliza uma sentinela. O uso de sentinelas
torna a pesquisa seqencial mais eficiente.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 101

Tcnicas de Programao Avanada

Sentinela
Sentinela um valor conhecido que inserido em
uma posio especfica de um arranjo ou de uma
lista. O objetivo usarmos o valor do sentinela
para pararmos um processamento ou uma busca.
Por exemplo, quando buscamos um valor x em um
vetor que vai de 0 a n, e inserimos o valor x como
sentinela na posio n+1. Assim, a busca pode ser
feita at encontrarmos o valor do sentinela, sem a
necessidade de testarmos se chegamos at o limite
do arranjo. O cdigo abaixo ilustra este cenrio:
// buscando x
v[n+1] = x; // atribui o sentinela
i = 0;
while (v[i] != x) {
i++;
}

4.1.1 Implementao da Pesquisa Seqencial


Continuaremos a apresentar nossas implementaes respeitando o
conceito de TAD. Neste capitulo, iremos usar o TAD Tabela, que
nada mais conjunto do tipo Elemento (j visto em listas encadeadas).
O tipo tabela apresentado na Figura 1.

Figura 1: Interface do TAD Tabela

As implementaes das operaes inicializaTabela, tabelaCheia e


insereElemento so apresentadas na Figura 2. A Figura 3 apresenta a
implementao da operao de pesquisaSeqElemento. Essa operao
possui como parmetro a tabela onde pesquisar e o valor da chave
utilizada para a pesquisa. A funo retorna -1 em caso de pesquisa
sem sucesso e o ndice da posio do elemento procurado, em caso de

Pgina 102

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


pesquisa sem sucesso. Note que foi usado o sentinela (inserido na
posio n+1 da tabela).

Figura 2: Implementao das operaes do TAD Tabela

Figura 3: Implementao da operao pesquisaSequencial

4.1.2 Tempo de execuo de algoritmos


Os mtodos de pesquisa so um bom tpico em nosso curso para
introduzirmos algumas noes sobre desempenho de algoritmos. Para
iniciar esta discusso, vamos nos reportar a uma pergunta? possvel
determinar quanto tempo operao de pesquisa seqencial leva
para encontrar um elemento?

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 103

Tcnicas de Programao Avanada


Existem importantes elementos esto envolvidos nesta pergunta. A
saber:
1. A Mquina que ser usada para executar o programa.
2. O tamanho total dos dados
Evidentemente, o tempo de uma pesquisa vai mudar dependendo do
computador que for utilizado. Quanto mais rpido o computador, mais
rpida ser a pesquisa. A mudana de desempenho de um computador
para outro pode ser expresso por uma constante C. Assim diremos que
o tempo gasto por um programa para executar pode ser expresso por
uma funo.
T f(n).C
Em que C a constante associada ao computador. n, por sua vez, o
tamanho da entrada de Dados. Ou seja, o tempo de execuo da
funo de pesquisa uma funo do tamanho da entrada de
dados.
Funo de complexidade de tempo
Quando analisamos o tempo de execuo comum
deixarmos a constante C de lado e nos concentramos na
funo f(n). Essa funo importante, pois ela nos d
uma medida de tempo de execuo independente do
computador que ser utilizado para executar a operao.
A funo f(n) denominada de funo de complexidade
de tempo.

Um outro aspecto importante na anlise de desempenho de algoritmos


so os diferentes casos ou cenrios de execuo possveis. So
geralmente considerados os seguintes casos:
x Melhor Caso: Compreende a melhor situao para o
algoritmo. A situao em que a resposta ser obtida de forma
mais rpida.
x Caso Mdio: Compreende a mdia de todos os casos
considerando as distribuies de probabilidade tpicas para os
dados em questo.
x Pior Caso: Compreende a pior situao para o algoritmo em
questo.
Podemos determinar a funo de complexidade de tempo para estes
trs casos para o algoritmo de pesquisa seqencial:
Melhor caso: f(n) = 1, ocorre quando o elemento procurado o
primeiro a ser inspecionado.

Pgina 104

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


Pior caso: f(n) = n, ocorre quando o elemento procurado o ltimo
elemento do conjunto a ser inspecionado.
Caso mdio: f(n) = (n+1)/2
O caso mdio obtido da seguinte forma: seja x o elemento procurado
e C = {c1,c2,c3..cn}, o conjunto de elementos a ser pesquisado.
Considera-se para este clculo que a possibilidade de encontrar o
elemento procurado igualmente provvel para qualquer posio do
conjunto de elementos pesquisado. Ou seja, P(x=c1) = P(x=c2) = ...
P(x=cn) = 1/n.
Temos ainda que, para encontrar o elemento procurado na i-sima
posio do conjunto, so necessrias i inspees. Por exemplo, para
encontrar o elemento na primeira posio necessria uma
comparao. Para encontrar o elemento na segunda posio so
necessrias duas comparaes. E assim por diante.
Sendo assim, temos:
f(n) = 1 * P(x=c1) +2 * P(x=c2)+3* P(x=c3) + .. + n* P(x=cn)
f(n) = 1 * 1/n + 2 * 1/n + 3 * 1/n + ... + n * 1/n
f(n) = (1+2+3+...+n) *1/n
f(n) = n*(n+1)/2 *1/n
f(n) = (n+1)/2

Atividades
1. Desenvolva um programa utilizando o TAD
Tabela que mea o tempo de execuo da pesquisa
seqencial. Altere o cdigo da tabela para aceitar
um conjunto de at 100.000 itens. Pesquise por
alternativas para medir o tempo de execuo de
um programa. Planeje sua estratgia para medir o
tempo.
2. No estudo da pesquisa seqencial, a busca no

leva em conta a organizao dos dados no


conjunto. Caso os dados se encontrem ordenados,
por exemplo, em ordem crescente, a pesquisa
seqencial pode tirar partido desta ordenao
interrompendo a busca ao encontrar um elemento
maior que o que foi procurado. Implemente um
nova operao no TAD Tabela que realize esta
pesquisa considerando que os dados esto
ordenados em ordem crescente. Para testar esta
operao os dados devem ser inseridos ordenadamente na tabela.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 105

Tcnicas de Programao Avanada


4.2 PESQUISA BINRIA
Caso o conjunto de dados de pesquisa esteja ordenado, podemos
utilizar a pesquisa binria para encontrar elementos no conjunto. A
Pesquisa binria consiste em uma tcnica do tipo Dividir para
Conquistar (Divide to Conquer), na qual o conjunto de dados
pesquisado sistematicamente reduzido metade a cada inspeo
realizada.

Figura 4: Diviso dos dados na Pesquisa Binria

A Figura 4 representa o mtodo de diviso dos dados que ocorre na


pesquisa binria. O quadro inteiro representa o conjunto completo dos
dados. As inspees so feitas no elemento central dos dados. Se o
elemento inspecionado menor que procurado, o algoritmo descarta
todos os elementos que so maiores que o elemento inspecionado. Ou
seja, a metade dos dados descartada (parte amarela). O algoritmo
segue o mesmo procedimento agora inspecionando o elemento central
dos elementos que sobraram, at encontrar o elemento ou no
restarem mais elementos a serem inspecionados. Utilizando este
mtodo, a pesquisa binria consegue localizar o elemento desejado
com desempenho muito melhor que a pesquisa seqencial. As divises
sucessivas levam a localizao de elemento em tempo logartmico,
conforme veremos a seguir.
Vejamos agora a pesquisa binria usando como exemplo um vetor
ordenado de elementos a seguir:
0

A D E F G

5 6
J

M N O

Suponha que o elemento procurado seja o D.


Suponha tambm que os limites inferior e superior do vetor sejam
denotados pelas variveis inicio e fim.
No comeo da pesquisa inicio = 0 e fim = 8

Pgina 106

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


A pesquisa iniciada inspecionando o elemento central do Vetor. Este
elemento determinado pela mdia entre inicio e fim:
3. meio = (inicio+fim)/2 = 4
Para primeira inspeo meio = 4; Como D menor que G, toda a
metade superior do vetor descartada. No algoritmo este descarte
feito recalculando o valor de fim:
4. fim = meio-1 = 3
O valor de meio recalculado agora para determinar o meio da
metade inferior:
5. meio = (inicio+fim)/2 = 1
Agora, com meio = 1, o item procurado encontrado.
O algoritmo completo da pesquisa binria mostrado na
implementao da operao pesquisaBinria para o TAD Tabela
(Figura 5).

Figura 5: Implementao da operao pesquisaBinria

Conforme j mencionado, a pesquisa binria apresenta


comportamento logartmico. A Funo de complexidade de tempo
dada por:
f(n) = log2(n)
Para ilustrar o que significa esta eficincia logartmica, suponha que
voc esteja procurando registros em uma tabela com 1.000.000 de
registros. Se voc utiliza a pesquisa seqencial, vai levar em mdia
(n+1)/2 = ~ 500.000 inspees para cada pesquisa. Utilizando a
pesquisa binria, cada pesquisa vai ter um custo de log2 1.000.000 = ~
20.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 107

Tcnicas de Programao Avanada


Ou seja, usando pesquisa seqencial realiza-se em media 500.000
inspees para encontrar um elemento; ao passo que com a pesquisa
binria sero necessrias, em mdia, apenas 20 (vinte) inspees!

Atividades
1. Desenvolva um programa utilizando o TAD
Tabela que mea o tempo de execuo da pesquisa
seqencial. Altere o cdigo da tabela para aceitar
um conjunto de at 100.000 itens. Pesquise por
alternativas para medir o tempo de execuo de
um programa. Planeje sua estratgia para medir o
tempo.
2. Implemente uma verso recursiva da pesquisa
binria.

4.3 TABELAS HASH


At o momento, discutimos mtodos de pesquisa baseados na
comparao explcita da chave de busca. Nesses mtodos, se
pesquisamos algum objeto com chave de pesquisa igual a X,
procuramos at encontrar o objeto com o valor de identificador igual a
X. Nesta seo iremos estudar uma abordagem completamente
diferente. Trata-se das tabelas Hash, mtodo tambm conhecido como
espalhamento.
Embora diferente, o mtodo de espalhamento bastante simples e
intuitivo. A fixao dos conceitos de endereo e funo hash vai
facilitar o entendimento do mtodo.

Tabela Hash: O mtodo de espalhamento permite o


armazenamento e recuperao de dados em
estruturas onde cada posio possui um ndice
como, por exemplo, um vetor. Chamaremos estas
estruturas simplesmente de tabela hash.
Endereo: Corresponde ao valor de um ndice na
tabela. Os endereos iro variar de 0 at N-1, onde
N o tamanho mximo da tabela hash.
Funo hash: uma funo aritmtica que tem
como entrada uma chave e que calcula um valor

Pgina 108

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

inteiro de um endereo vlido na tabela Hash.


A funo a seguir um exemplo de funo hash.
int h (char * chave){
int tam, i,soma=0;
tam = strlen(chave);
for(i=0;i<tam;i++) {
soma+=abs(chave[i]);
}
return soma%N;
}

Esta funo recebe uma string como parmetro e


retorna valores entre 0 e N-1.
A funo abs da biblioteca da linguagem C e
retorna o valor inteiro correspondente ao cdigo
ASCII de um caractere. Para determinar o valor a
ser retornado, a funo faz um clculo aritmtico
baseado no cdigo ASCII de cada caractere que
forma a string. O valor calculado o resto entre a
soma obtida e N, que nos d um valor entre 0 e N1.

Quando um registro vai ser inserido na tabela, a posio de insero


determinada pela funo Hash, tomando como entrada a chave de
pesquisa utilizada. Normalmente, as chaves de pesquisa usadas em
tabelas Hash so valores alfanumricos (strings), por exemplo, nomes
de pessoas.
Um funo Hash pode ser qualquer funo aritmtica que gere valores
de endereos a partir da chave de pesquisa. No entanto, existem
funes Hash melhores que as outras. As seguintes caractersticas
devem ser buscadas na definio de uma funo Hash:
x Ser de computao simples e de baixo custo;
x Gerar valores de endereo de forma uniforme, de maneira a
tentar distribuir os dados uniformemente na tabela. Ou seja, a
probabilidade de gerao dos endereos entre 0 e N-1, pela
funo Hash deve a mesma.
Para o mtodo re espalhamento a chave de pesquisa deve ser nica.
Conforme Figura 6, a funo hash h calcula um endereo com base no
valor da chave k. Se esta chave no for nica para os registros a serem
armazenados, o mesmo valor de endereo ser fatalmente calculado
para dois registros diferentes.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 109

Tcnicas de Programao Avanada


O princpio bsico do mtodo de espalhamento a gerao de
endereos dentro da tabela por meio da funo Hash. Esta gerao
ocorre nas seguintes situaes:
(1) Insero de um registro: Para inserir um registro, a chave (que
deve se nica) usada para calcular o endereo de
armazenamento do registro.
(2) Recuperao de um registro: Para recuperar um registro

armazenado, com base em um valor chave de pesquisa. Neste


caso a chave informada usada para determinar o possvel
endereo de armazenamento do registro procurado.

Figura 6: A funo hash determina o ndice com base na chave de pesquisa.

Um problema que fatalmente ocorre em funes Hash o clculo de


um mesmo endereo para dois valores de chave diferentes. Este
problema chamado de coliso.
Coliso
A coliso em tabelas hash ocorre quando o mesmo
endereo na tabela calculado para diferentes
valores de chave. Por exemplo, a funo Hash
int h (char * chave){
int tam, i,soma=0;
tam = strlen(chave);
for(i=0;i<tam;i++) {
soma+=abs(chave[i]);
}
return soma%N;
}
Retorna o mesmo valor para strings contendo os
mesmos caracteres. Por exemplo, as chaves maria
e maira, iriam produzir um mesmo valor embora
sejam valores diferentes.

Pgina 110

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


A coliso no pode ser evitada, mas deve ser tratada. A seguir
veremos como tratar colises em implementaes de tabelas Hash.

4.3.1 Operaes de Insero e Pesquisa em Tabelas Hash


Veremos como feita a insero e a pesquisa em uma tabela Hash.
Veremos primeiro uma verso sem tratamento de coliso.
Implementaremos estas funes como operaes do TAD tabelaHash.

Figura 7: TAD TabelaHash sem tratamento de coliso

A Figura 7 apresenta o TAD TabelaHash sem tratamento de coliso.


A tabela utilizada consiste de um vetor de registros do tipo
Elemento. Apenas lembrando, o tipo Elemento possui os seguintes
campos:
char nome[20];
int codigo;
char telefone[10];

O campo nome ser usado como chave de pesquisa. Assim, fica


convencionado que os registros armazenados na tabela no
podero ter o mesmo nome.
Usaremos o campo codigo para determinar se um endereo da
tabela est ocupado ou no. Para tanto, na inicializao da tabela,
atribuiremos o valor -1 ao cdigo. O valor -1 no campo cdigo
indicar que o endereo est desocupado.
O cdigo da operao inicializaTabela mostrado na Figura 8.
Conforme pode ser observado, a tabela possui tambm um contador n
que mantm o nmero de elementos da tabela. Implementamos
tambm uma funo lgica chamada de enderecoOcupado, que
retorna TRUE se um endereo (end) estiver ocupado e FALSE, caso
contrrio. Esta funo apresentada na Figura 8.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 111

Tcnicas de Programao Avanada

Figura 8: Inicializao da Tabela Hash e funo enderecoOcupado.

A funo Hash utilizada baseada na funo h, j apresentada. No


entanto, para calcular o valor da soma, cada caractere foi multiplicado
pela sua posio (i+1), evitando a coliso de nomes com mesmo
conjunto de caracteres. A Figura 9 apresenta esta implementao.

Figura 9: implementao da funo hash

A insero de elementos na tabela segue o seguinte algoritmo:

A implementao da operao de insero mostrada na Figura 10.

Pgina 112

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Figura 10: Implementao da operao insereElemento.

Note que, se o endereo calculado j estiver ocupado, ocorre uma


coliso que no tratada. Um aviso de coliso enviado ao usurio e
a insero do novo elemento simplesmente no ocorre.
Conforme j mencionado, colises em tabelas Hash so inevitveis,
mesmo para uma tabela 10 vezes maior que o nmero de registros a
ser armazenado, a probabilidade de colises ainda muito grande.
Este comportamento ilustrado pelo paradoxo do aniversrio.

Paradoxo do aniversrio: Se tomarmos um grupo


de mais de 25 pessoas de forma totalmente aleatrio,
a probabilidade de que haja entre estas pessoas pelo
menos duas que fazem aniversrio na mesma data
do ano maior que 50%. Esta medida
curiosamente verdadeira, considerando-se que a data
de aniversrio de uma pessoa uma varivel
aleatria, estas datas deveriam ser uniformemente
distribudas entre os dias do ano.

O paradoxo do aniversrio est associado com tabelas Hash.


Considere uma tabela Hash com 365 endereos disponveis. Cada
endereo corresponde a um dia do ano. Ao inserirmos 25 registros
nesta tabela, usando uma funo h totalmente aleatria, a chance de
haver uma coliso de 50%.
Na pesquisa por um elemento, um valor de chave deve ser informado.
Com base neste valor o endereo calculado. Se o endereo estiver
ocupado, o valor do campo nome do elemento comparado com a
chave de pesquisa para verificar se o elemento que l est realmente
o elemento procurado. Neste caso o valor de end retornado. Caso
contrrio o elemento procurado no existe na tabela. A operao de
pesquisa apresentada na Figura 11.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 113

Tcnicas de Programao Avanada

Figura 11: Implementao da operao pesquisa.

4.3.2 Tratamento de Colises


Na implementao que realizamos at agora, quando uma coliso
ocorre, o dado simplesmente no inserido. Evidentemente este no
o comportamento esperado de nenhum sistema de armazenamento de
informaes. Assim, ao invs de simplesmente abortar a insero,
iremos tratar o evento da coliso permitindo a insero de vrios
elementos com chaves diferentes que mapeiam para o mesmo
endereo.
Conforme observado na TAD TabelaHash apresentado, na insero,
quando o endereo vazio obtido, o elemento inserido no mesmo.
A tabela itens um vetor de Elemento e cada endereo se refere
a apenas um elemento.
Veremos duas formas de tratar a coliso:
(1) Com listas encadeadas
(2) Com endereamento aberto
No tratamento de colises com listas encadeadas, a estrutura da tabela
e alterada. Ao invs de uma tabela de registros definida uma tabela
de listas encadeadas, onde cada lista encadeada ser o conjunto de
registros inseridos cujas chaves de pesquisa foram mapeadas para o
mesmo endereo. A Figura 12 ilustra esta abordagem.

Figura 12: Tratamento de Coliso com Listas Encadeadas

Pgina 114

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


A Tabela formada de um vetor de ponteiros para N listas
encadeadas. Agora, na insero, o endereo end calculado e o
elemento inserido na lista encadeada apontada pelo ponteiro da
posio end.
A Figura 13 apresenta a implementao da interface do TAD
tabelaHash com com tratamento de coliso por meio de lista
encadeada. Este TAD utiliza como cliente o tadLista implementado no
Captulo 3. A nica modificao neste Tad foi na operao pesquisa
que agora utiliza o campo nome do registro Elemento como chave e
recebe a string chave como parmetro para realizar a pesquisa. O
TadLista reapresentado na Figura 14.

Figura: 13: Interface do TAD Tabela Hash

Figura 14: Interface do TAD Lista Encadeada

A Figura 15 apresenta a implementao das operaes do TAD


TabelaHash.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 115

Tcnicas de Programao Avanada

Figura 15: operaes inicializaTabela, insereElemento e pesquisaElemento

4.3.3 Tratamento de Coliso usando endereamento Aberto


Outra abordagem para tratar as colises o uso de endereamento
aberto (open addressing). Nessa abordagem, a estrutura de dados da
tabela a mesma originalmente estabelecida (um vetor de registros).
A tcnica de endereamento aberto consiste nos seguintes
procedimentos:
Insero:
(1) Calcular o endereo usando a funo Hash para o valor de
chave do registro;
(2) Se o endereo estiver ocupado, procurar nas posies vizinhas
ao endereo calculado uma posio vazia.
Pesquisa:
(1) Calcular o endereo usando a funo Hash e a chave de
pesquisa fornecida;
(2) Procurar, a partir do endereo at:
a. Encontrar o elemento procurado (pesquisa com
sucesso);
b. Encontrar uma posio vazia ou o fim da tabela
(pesquisa sem sucesso).

Pgina 116

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Atividades
8. Modificar a implementao inicial de Hash (sem
tratamento de coliso) para suportar colises com a tcnica
de endereamento aberto.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 117

Tcnicas de Programao Avanada

5.

ORDENAO EM MEMRIA PRIMRIA.


Ol. Neste captulo chegaremos ao fim de nosso
estudo na disciplina de TPA. Reservei para a
ltima etapa o tema Ordenao. A ordenao em
computao rene um conjunto de algoritmos que
permite ordenar um conjunto de dados segundo
uma determinada chave de ordenao. Neste
captulo iremos estudar alguns desses principais
algoritmos. Se voc vasculhar a Internet vai
encontrar a maioria desses algoritmos
implementados. Assim voc poder se perguntar:
para que estudamos esses mecanismos se as suas
implementaes j esto prontas? E mais, porque
estudar vrios mtodos de ordenao se existe um
particularmente que mais rpido que os outros?
A resposta simples: Porque estes algoritmos e
suas variaes renem tcnicas de programao
que so de muita valia na resoluo de outros
problemas, alem de tocarem em aspectos
complexos que, ao serem absorvidos pelo
estudante so capazes de aprofundar sua
capacidade de raciocnio e habilidades em
desenvolver programas. Vamos a ele ento.

5.1 CONCEITOS BSICOS DE ORDENAO


A ordenao consiste em rearranjar um conjunto de objetos em ordem

crescente ou decrescente, levando-se em conta uma chave ordenao.


A ordenao possui motivaes bvias. Em geral, colocamos dados de
forma ordenada para:
x Facilitar a obteno de uma informao ao se observar um
conjunto de dados. Por exemplo, a visualizao da
classificao de candidatos em um concurso fica mais fcil se
a lista de candidatos estiver ordenada pelo nmero de pontos
que fizeram.
x Facilitar a recuperao de uma informao. Por exemplo: obter
os pontos que um candidato em um concurso fez, sabendo o
seu nome, fica mais fcil se a lista de candidatos estiver
ordenada por nome.

Pgina 118

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


A ordenao pode ser feita considerando diferentes tipos de dados
para a chave, inteiros, reais, strings. O que importa estabelecer as
comparaes nos algoritmos de acordo com o tipo de dado da chave
de ordenao. Na ordenao de um arranjo de registros, com a tabela
de elementos usada no captulo anterior, apenas a chave de ordenao
usada. Os demais campos do registro so irrelevantes.

5.1.1 Operaes Tpicas de processos de Ordenao


Nos diferentes mtodos de ordenao, algumas operaes ocorrem
com mais freqncia e o desempenho dos mtodos est geralmente
associado com a realizao dessas operaes. As duas operaes que
mais afetam o desempenho dos algoritmos de ordenao so as
operaes de troca e de comparao:
x Troca: Consiste na troca de valores entre duas posies do
arranjo que est sendo ordenado. Esta operao tem custo
elevado e a que mais afeta o desempenho dos algoritmos. A
operao de troca geralmente suportada por uma funo. A
Figura 1 apresenta uma implementao da funo troca;
x Comparao: consiste nas comparaes entre dois valores
contidos em posies do arranjo com o objetivo de saber qual
dentre as duas menor. Embora de menor custo, esta operao
tambm afeta bastante o desempenho dos algoritmos devido ao
fato de serem feitas muitas comparaes nos processos de
ordenao.

Figura 1: Implementao da funo troca

5.2 MTODOS DE ORDENAO


Iremos estudar 5 mtodos de ordenao diferentes neste captulo.
A saber:
1.
2.
3.
4.
5.

Seleo
Insero
Bolha
Shell
Quicksort

Dependendo da aplicao e situao, o uso de um mtodo pode ser


mais conveniente que o outro. Em geral, o quicksort apresenta-se com
melhor desempenho na maioria das situaes. O Mtodo da bolha o

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 119

Tcnicas de Programao Avanada


menos eficiente. Porem a sua simplicidade o torna conveniente para
ordenar pequenos vetores (com tamanho menor que 20). A seguir
discutimos cada um destes algoritmos individualmente.

5.2.1 Ordenao por Seleo


Este mtodo tem como estratgia selecionar o menor elemento
remanescente do conjunto no ordenado e mover este elemento para
sua posio correta. Por exemplo, suponha um arranjo com 4
elementos.
O processo de ordenao por seleo determina quem o menor
elemento e o insere na primeira posio do vetor. Para tanto, o
elemento que estava na posio inicial precisa ser colocado na posio
onde estava o menor. Em seguida o segundo menor encontrado e
inserido na segunda posio do arranjo. O Algoritmo segue assim
sucessivamente at encontrar o ltimo elemento e inseri-lo na ltima
posio.
A Figura 2 apresenta a implementao do algoritmo de seleo.
Implementao:

Figura 2: Implementao da Ordenao por Seleo

Tomando como exemplo o arranjo


int B[] = {10,3,7,20,1,2,11,0,5,4};
a execuo da funo seleo ir imprimir a seguinte seqncia de
valores intermedirios para o arranjo B at a sua ordenao completa:
10
0
0
0
0
0
0
0
0
0

Pgina 120

3
3
1
1
1
1
1
1
1
1

7
7
7
2
2
2
2
2
2
2

20 1
20 1
20 3
20 3
3 20
3 4
3 4
3 4
3 4
3 4

2
2
2
7
7
7
5
5
5
5

11
11
11
11
11
11
11
7
7
7

0 5 4
10 5 4 (fim
10 5 4 (fim
10 5 4 (fim
10 5 4 (fim
10 5 20 (fim
10 7 20 (fim
10 11 20 (fim
10 11 20 (fim
10 11 20 (fim

da
da
da
da
da
da
da
da
da

interao
interao
interao
interao
interao
interao
interao
interao
interao

i=0)
i=1)
i=2)
i=3)
i=4)
i=5)
i=6)
i=7)
i=8)

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


O algoritmo de seleo utiliza o ndice i como limite inferior da parte
do arranjo que ainda no est ordenado (de i at n-1). medida que o
arranjo vai sendo ordenado este limite vai avanando (lao mais
externo). O lao mais interno tem como objetivo encontrar o menor
elemento dentre os elementos que ainda no foram ordenados. min
iniciado sempre com o valor de i. Em seguida o lao mais interno (do
j) se encarrega de verificar se no restante do vetor (posies de i+1 at
n-1) existe um valor menor que a[min]. Toda vez que isso ocorre, o
valor de min atualizado. Ao final de um lao mais interno, a
varivel min vai conter o ndice do menor valor no arranjo dentre os
elementos que no foram ainda ordenados.
Conforme pode ser visto na sada do programa, na primeira interao
de i, i=0, o menor elemento contido no vetor localizado e inserido
na posio 0. Esta insero feita pela operao de troca que ocorre
ao final de cada iterao do lao mais externo.
Note que as trocas ocorrem independentemente de haver sido
encontrado um valor menor que a[i]. Neste caso haver uma troca
entre duas posies idnticas, pois o valor de min vai ser igual a i.
Isso ocorreu nas iteraes 6,7 e 8. Caso seja importante melhorar o
desempenho do algoritmo esta troca entre posies iguais pode ser
evitada comparando-se o valor de min com i. Se estes forem iguais a
troca no precisa ser feita.

5.2.2 Mtodo da Insero


Este mtodo similar ao que o jogador de cartas utiliza: Cada
elemento a ser ordenado reposicionado entre os ordenados
movendo-se os elementos maiores que ele uma posio para a direita e
posteriormente inserindo-o na posio vaga.
A Figura 3 apresenta a implementao do algoritmo de Insero.

Figura 3: Implementao do mtodo de ordenao por Insero

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 121

Tcnicas de Programao Avanada


A funo imprimevetor chamada a cada iterao do lao while
(mais interno) e ao fim de cada lao mais externo tambm. A
execuo desta funo sobre o arranjo
int B[] = {10,3,7,20,1,2,11,0,5,4};
produz a seguinte sada:
10 3 7 20 1 2 11 0 5 4
10 10 7 20 1 2 11 0 5 4
3 10 7 20 1 2 11 0 5 4 (fim
3 10 10 20 1 2 11 0 5 4
3 7 10 20 1 2 11 0 5 4 (fim
3 7 10 20 1 2 11 0 5 4 (fim
3 7 10 20 20 2 11 0 5 4
3 7 10 10 20 2 11 0 5 4
3 7 7 10 20 2 11 0 5 4
3 3 7 10 20 2 11 0 5 4
1 3 7 10 20 2 11 0 5 4 (fim
1 3 7 10 20 20 11 0 5 4
1 3 7 10 10 20 11 0 5 4
1 3 7 7 10 20 11 0 5 4
1 3 3 7 10 20 11 0 5 4
1 2 3 7 10 20 11 0 5 4 (fim
1 2 3 7 10 20 20 0 5 4
1 2 3 7 10 11 20 0 5 4 (fim
1 2 3 7 10 11 20 20 5 4
1 2 3 7 10 11 11 20 5 4
1 2 3 7 10 10 11 20 5 4
1 2 3 7 7 10 11 20 5 4
1 2 3 3 7 10 11 20 5 4
1 2 2 3 7 10 11 20 5 4
1 1 2 3 7 10 11 20 5 4
0 1 2 3 7 10 11 20 5 4 (fim
0 1 2 3 7 10 11 20 20 4
0 1 2 3 7 10 11 11 20 4
0 1 2 3 7 10 10 11 20 4
0 1 2 3 7 7 10 11 20 4
0 1 2 3 5 7 10 11 20 4 (fim
0 1 2 3 5 7 10 11 20 20
0 1 2 3 5 7 10 11 11 20
0 1 2 3 5 7 10 10 11 20
0 1 2 3 5 7 7 10 11 20
0 1 2 3 5 5 7 10 11 20
0 1 2 3 4 5 7 10 11 20 (fim

da iterao i=1)
da iterao i=2)
da iterao i=3)

da iterao i=4)

da iterao i=5)
da iterao i=6)

da iterao i=7)

da iterao i=8)

da iterao i=9)

Na execuo da funo o lao mais externo usado para delimitar os


elementos do arranjo ainda no inspecionados. A varivel x usada
para guardar o valor do elemento a ser inserido (a[i]). Na primeira
iterao este elemento o 3. Na segunda o 7. Na terceira o 10 e
assim por diante. Nem sempre o elemento em x ser substitudo. Por
exemplo, na iterao i=3, o elemento x igual a 10 e no ter a sua
posio alterada. O lao while tem a finalidade de percorrer o
arranjo nas posies entre (i-1 e 0) procurando valores menores que
x. medida que estes valores so encontrados eles vo sendo

Pgina 122

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


deslocados para a direita. O lao while termina quando
encontrado um elemento menor que x ou o limite do vetor atingido.

5.2.3 Mtodo da Bolha


O Mtodo da Bolha consiste em percorrer o vetor trocando os
elementos adjacentes caso necessrio. Por este motivo, este mtodo
realiza muitas trocas.
A implementao desse mtodo apresentada na Figura 4.

Figura 4: Mtodo da Bolha

A execuo do mtodo da bolha sobre o vetor


int B[] = {10,3,7,20,1,2,11,0,5,4};
produz a seguinte sada:
10 3 7 20 1 2
3 10 7 20 1 2
3 7 10 20 1 2
3 7 10 1 20 2
3 7 10 1 2 20
3 7 10 1 2 11
3 7 10 1 2 11
3 7 10 1 2 11
3 7 10 1 2 11
3 7 1 10 2 11
3 7 1 2 10 11
3 7 1 2 10 0
3 7 1 2 10 0
3 7 1 2 10 0
3 1 7 2 10 0
3 1 2 7 10 0
3 1 2 7 0 10

11 0 5 4
11 0 5 4
11 0 5 4
11 0 5 4
11 0 5 4
20 0 5 4
0 20 5 4
0 5 20 4
0 5 4 20
0 5 4 20
0 5 4 20
11 5 4 20
5 11 4 20
5 4 11 20
5 4 11 20
5 4 11 20
5 4 11 20

(troca
(troca
(troca
(troca
(troca
(troca

10
10
20
20
20
20

e
e
e
e
e
e

Centro Federal de Educao Tecnolgica do Esprito Santo

3)
7)
1)
2)
11)
0)

Pgina 123

Tcnicas de Programao Avanada


3
3
1
1
1
1
1
1
1
1
0

1
1
3
2
2
2
2
2
2
0
1

2
2
2
3
3
3
3
0
0
2
2

7
7
7
7
0
0
0
3
3
3
3

0
0
0
0
7
5
5
5
4
4
4

5 10 4 11 20
5 4 10 11 20
5 4 10 11 20
5 4 10 11 20
5 4 10 11 20
7 4 10 11 20
4 7 10 11 20
4 7 10 11 20
5 7 10 11 20
5 7 10 11 20
5 7 10 11 20

5.2.4 Desempenho dos mtodos de Seleo, Insero e


Bolha
Para a anlise de desempenho de mtodos de ordenao deve levar em
contar o nmero de comparaes e o nmero de trocas realizadas.
O Mtodo da Seleo realiza aproximadamente n2/2 comparaes e n
trocas, pois para cada i de 1 at n-1 ocorre uma troca e n-1
comparaes. Assim temos que no final ocorrem n-1 trocas e (n-1 +
(n-2) + ... 2 +1 = n(n-1)/2 comparaes.
O mtodo da Insero realiza aproximadamente n2/4 comparaes e
n2/8 trocas no caso mdio. No entanto, esse mtodo linear para
arranjos parcialmente ordenados, o que o torna um mtodo
conveniente para estes casos.
O mtodo da Bolha realiza n2/2 comparaes e n2/2 trocas no caso
mdio e no pior caso.
Realize testes de mesa para os mtodos de seleo,
insero e bolha para os seguintes vetores:
A = {10,0,3,2,5}, B={5,4,3,2,1}, C={1,1,2,2,0,0}.

5.2.5 Mtodo de Shell


O mtodo que estudaremos agora foi inventado por Criado por Donald
Shell em 1959. Conforme comentado na Seo 5.2.4, o mtodo da
Insero bastante eficiente ao ordenar arranjos que j esto
parcialmente ordenados. Shell observou esta caracterstica e criou um
mtodo onde o mtodo de insero aplicado sucessivamente.
Em seu mtodo, o algoritmo de insero aplicado para ordenar
subconjuntos do arranjo completo. Estes subconjuntos so pegos
considerando uma distncia entre os elementos. Para cada execuo
do mtodo de Insero considerada um distncia d. d iniciado com
um valor que vai sendo decrementado at chegar a 1. Para cada valor
de d, os elementos do arranjo localizados a uma distncia d entre si
so ordenados.

Pgina 124

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


Por exemplo, em um arranjo,
6. a = {a0,a1,a2,a3,a4,a5,a6,a7,a8,a9}
E considerando uma srie de distncias d = {5,3,1}. Nas iteraes com
distncia d = 5, o mtodo da insero ser aplicado aos elementos do
arranjo localizados a uma distncia 5 entre si. Os elementos so pegos
do arranjo a partir da posio a0, na primeira iterao, a1 na segunda,
a2 na terceira e assim sucessivamente.
Assim para a distncia 5 teremos a ordenao dos elementos:
{a0,a5} (primeira iterao)
{a1,a6} (segunda iterao)
{a2,a7} (terceira iterao)
{a3,a8} (quarta iterao)
{a4,a9} (quinta iterao)
Para a distncia 3 teremos a ordenao dos elementos:
{a0,a3,a6,a9} (primeira iterao)
{a1,a4,a7} (segunda iterao)
{a2,a5,a8} (terceira iterao)
{a3,a6,a9} (quarta iterao)
{a4,a7} (quinta iterao)
{a5,a8} (sexta iterao)
{a6,a9} (stima iterao)
Para a distncia 1, teremos a ordenao do arranjo completo
7. {a0,a1,a2,a3,a4,a5,a6,a7,a8,a9}
iterao)

(primeira

8.
A cada iterao distncia d reduzida de acordo com alguma
seqncia. Na utiliza iterao esta distncia reduzida a 1. Este passo
corresponde ao mtodo de insero original.
Vejamos um exemplo concreto, considerando o arranjo a = {35,
28, 16, 07, 12, 08,04} e utilizando a seqncia de
distncias {3,1}:
Para d = 3 o mtodo ordena os elementos que esto a uma distncia 3
entre si. Na tabela abaixo estes elementos esto em negrito:

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 125

Tcnicas de Programao Avanada


35

28

16

07

12

08

04

35 est
ordenado, 7
comparado

07

28

16

35

12

08

04

{07,35} est
ordenado, 4
comparado

04

28

16

07

12

08

35

{04,07,35}
est
ordenado

04

28

16

07

12

08

35

28 est
ordenado,
12
comparado

04

12

16

07

28

08

35

{12,28} est
ordenado

04

12

16

07

28

08

35

16 est
ordenado,
35
comparado

04

12

08

07

28

16

35

{08,16} est
ordenado

Aps a ordenao parcial feita com d=3, a distncia reduzida a 1 e o


vetor completamente ordenado.
Para implementao do mtodo de Shell, implementa-se uma funo
(Shell) que corresponde ao mtodo de insero parametrizado pela
distncia. Esta implementao apresentada na Figura 5.

Figura 5: Implementao da funo Shell

Note que a funo shell corresponde exatamente funo


insercao, se substituirmos o d pelo valor 1.

Pgina 126

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


Para concluirmos a implementao do mtodo de Shell, basta agora
implementarmos uma funo que gere a seqncia de distncias e a
chave a funo Shell para cada distncia da srie. A Figura 6 apresenta
uma implementao da funo shellSort, que executa o mtodo com a
srie {5,2,1}.

Figura 6: Implementao do mtodo de Shell com distncias 5,2 e 1

A execuo de shellsort1 sobre o vetor


int B[] = {10,3,7,20,1,2,11,0,5,4}; produz a
seguinte sada:
10 3 7 20
Distancia d=
10 3 7 20
2 3 7 20
2 3 7 20
2 3 7 20
2 3 0 20
2 3 0 20
2 3 0 5
2 3 0 5
Distancia d=
2 3 2 5
0 3 2 5
0 3 2 5
0 3 2 5
0 3 1 5
0 3 1 5
0 3 1 5
0 3 1 5
0 3 1 5
0 3 1 5
0 3 1 5
0 3 1 5
0 3 1 5
0 3 1 4
Distancia d=
0 3 1 4
0 3 3 4
0 1 3 4
0 1 3 4
0 1 3 4
0 1 3 3
0 1 2 3
0 1 2 3
0 1 2 3
0 1 2 3

1
5
1
1
1
1
1
1
1
1
2
1
1
1
2
2
2
2
2
2
2
2
2
2
2
1
2
2
2
2
4
4
4
4
4
4

2 11
10
10
10
10
10
10
10
10

11
11
11
11
11
11
11
11

10
10
10
10
10
10
10
10
7
7
7
7
5
5

11
11
11
11
11
11
11
11
11
11
11
11
11
11

5
5
5
5
5
5
5
5
5
5

0 5
0 5
0 5
7 5
7 5
7 20
7 20
7 20

4
4
4
4
4
4
4
4

7
7
7
7
7
7
7
10
10
10
10
7
7
7

20
20
20
20
20
20
20
20
20
20
20
20
20
20

4
4
4
4
4
4
4
4
4
4
10
10
10
10

11 7
11 7
11 7
11 7
11 7
11 7
11 7
11 7
11 7
11 11

20
20
20
20
20
20
20
20
20
20

10
10
10
10
10
10
10
10
10
10

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 127

Tcnicas de Programao Avanada


0
0
0
0
0

1
1
1
1
1

2
2
2
2
2

3
3
3
3
3

4
4
4
4
4

5
5
5
5
5

7
7
7
7
7

11
11
11
11
10

20
20
20
11
11

10
10
20
20
20

Conforme pode ser observado, a seqncia de distncias pode variar.


A nica restrio que termine com 1. No existe uma seqncia
ideal.
Donald
Knuth
(vale
a
pena
ver
http://pt.wikipedia.org/wiki/Donald_Knuth), mostrou empiricamente
que a seqncia ( 1,4, 13,40,121,364,1093..) apresenta eficincia 20 %
maior que outras seqncias.
A Figura 7 apresenta a funo shellsort2 que executa a funo Shell
usando esta seqncia.

Figura 7: Implementao do mtodo de Shell usando a seqncia de Knuth

5.2.6 O Mtodo Quicksort


At o momento, foram estudados mtodos de ordenao cuja funo
de complexidade prxima de n2. Ou seja, complexidade quadrtica.
Nos melhores casos, o mtodo da insero e Shell podem chegar
prximo de um comportamento linear. O mtodo quicksort baseia-se
em uma estratgia de dividir para conquistar (vide pesquisa binria),
tornando-o assim um mtodo que apresenta complexidade logartmica
(sublinear), no caso mdio. Este comportamento do quicksort o torna
um mtodo de ordenao extremamente rpido.

Pgina 128

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada


O algoritmo Quicksort foi inventado por C.A.R. Hoare em 1960,
durante visita a Universidade de Moscou (Russia), ainda como
estudante.
A idia fundamental do quicksort consiste em:
Primeiro dividir: a seqncia a ser ordenada a particionada em duas
partes b e c, de tal modo que todos os elementos da primeira parte b
so menores ou iguais a todos os elementos da segunda parte c. Em
seguida conquistar: as duas partes so ordenadas separadamente por
meio da aplicao recursiva do mesmo procedimento. Por ltimo
recombinar. A recombinao das duas partes ordenadas em separado
produz uma seqncia tambm ordenada, dado que os elementos da
primeira parte b so menores ou iguais a todos os elementos da
segunda parte c.
O processo de particionamento da seqncia feito por meio da
escolha de um elemento piv. Por exemplo, Seja o arranjo
{f,e,d,h,a,c,g,b} e o valor d como o elemento escolhido para
fazer a primeira partio. O elemento escolhido chamado de piv.
Aps a primeira iterao com o valor d como piv, teremos a seguinte
configurao para o vetor: {b,c,a,d,h,e,g,f}
Neste passo o processo repetido para cada sub vetor [b,c,a] e
[h,e,g,f]
A Figura 8 apresenta uma implementao da operao de
particionamento. Nessa implementao o piv sempre o elemento do
meio do vetor.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 129

Tcnicas de Programao Avanada

Figura 8: funo particiona

A Figura 9 apresenta a funo ordenaQS que aplica o mtodo sobre


um arranjo com limites esq e dir.

Figura 9: Implementao da funo ordenaQS

A implementao da funo quicksort, apresentada na Figura 10


consiste apenas no encapsulamento da funo ordenaQS em uma
funo cujos parmetros so apenas o arranjo e seu tamanho.

Figura 10: implementao da funo quicksort

Pgina 130

Centro Federal de Educao Tecnolgica do Esprito Santo

Tcnicas de Programao Avanada

Atividades
1. Realizar os experimentos com os 5 mtodos de ordenao
estudados. No caso do shellsort utilizar a seqncia de Knuth.
a) Realizar testes com todos os mtodos para vetores de tamanho
20000, 40000, 60000, 80000, 100000, 150000, 200000, 250000,
300000, 350000, 400000 e 500000.
b) Utilizar um software que trace grficos (Excel, por exemplo) e
traar um grfico de desempenho dos mtodos utilizados. O
grfico deve ter os seguintes eixos: eixo x: tamanho do vetor. Eixo
y: tempo de execuo. Colocar as curvas de todos os mtodos no
mesmo grfico para facilitar a comparao.
c) Fazer uma anlise dos resultados obtidos (descritiva).
2. Sabemos que a eficincia do Shellsort depende da seqncia de
distncias utilizada. Assim, neste exerccio, primeiramente voc
deve inventar uma seqncia de distncias sua para ser utilizada
no Shellsort. Posteriormente, escreva uma funo myShellsort que
execute o Shellsort com uma seqncia produzida por voc.
Invente uma seqncia sua! Voc pode utilizar a mesma estrutura
que foi utilizada para as funes shelsort1 e shellsort2. Compare
os resultados de tempo obtidos com a sua seqncia com os
obtidos com a seqncia de Knuth.

Centro Federal de Educao Tecnolgica do Esprito Santo

Pgina 131

Tcnicas de Programao Avanada


Referncias utilizadas na elaborao deste material
1. LISKOV B. Data Abstraction and Hiararchy. In
OOPSLA87: Conference on Object Oriented Programming
Systems Languages and Applications. Addendum to the
proceedings on Object-oriented programming systems,
languages and applications, 1987.
2. TENENBAUM A. M. Data Structs using C. Prentice Hall Int.
Editions, 1990.
3. ZIVIANI N. Projeto de Algoritmos.
Pioneira, 2003.

Pgina 132

Segunda Edio.

Centro Federal de Educao Tecnolgica do Esprito Santo

Você também pode gostar