Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação...

download Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

of 136

Transcript of Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação...

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    1/136

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    2/136

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    3/136

    PROF. MATEUS CONRAD BARCELLOS DA COSTA

    TÉCNICAS DE PROGRAMAÇÃO AVANÇADA

    VITÓRIA2008

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    4/136

    Governo FederalMinistro de EducaçãoFernando HaddadCEFETES – Centro Federal de Educação Tecnológica do Espírito SantoDiretor GeralJadir José PelaDiretor de EnsinoDenio Rebello ArantesCoordenadora do CEAD – Centro de Educação a DistânciaYvina Pavan BaldoCoordenadoras da UAB – Universidade Aberta do BrasilYvina Pavan BaldoMaria das Graças ZamborliniDesigner InstrucionalDanielli Veiga Carneiro

    Curso de Tecnologia em Análise e Desenvolvimento de SistemasCoordenação de CursoIsaura NobreProfessor Especialista/AutorMateus Conrad Barcellos da Costa

    DIREITOS RESERVADOSCefetes – Centro Federal de Educação Tecnológica do Espírito SantoAv. Vitória - Jucutuquara - Vitória - ES - (27) 3331.2139Créditos de autoria da editoraçãoCapa: Leonardo Tavares PereiraProjeto gráfico:Danielli Veiga CarneiroIconografia:Moreno CunhaEditoração eletrônica:Mateus Conrad B. da Costa, Humberto Wanke, Monia VignatiRevisão de texto:Karina Bersan RochaCOPYRIGHT – É proibida a reprodução, mesmo que parcial, por qualquer meio, semautorização escrita dos autores e do detentor dos direitos autorais.

    Catalogação na fonte: Rogeria Gomes Belchior - CRB 12/4171.

    C837 Costa, Mateus Conrad Barcellos da

    Técnicas de programação avançada. / Mateus Conrad Barcellos da. – Vitória:CEFETES, 2008.132 p. : il.

    1. Programação (Computadores). I. Centro Federal de Educação Tecnológica doEspírito Santo. II. Título.

    CDD 005.1

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    5/136

    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 Análise e Desenvolvimentode Sistemas, na modalidade a distância. Apesar de este curso ser

    ofertado a distância, esperamos que haja proximidade entre nós, pois,hoje, graças aos recursos da tecnologia da informação (e-mails, chat,videoconferência, etc.) podemos manter uma comunicação efetiva.

    É importante que você conheça toda a equipe envolvida neste curso:coordenadores, professores especialistas, tutores a distância e tutores presenciais, porque quando precisar de algum tipo de ajuda, saberá a

    quem recorrer. Na EaD – Educação a Distância, você é o grande responsável pelo

    sucesso da aprendizagem. Por isso, é necessário que se organize paraos estudos e para a realização de todas as atividades, nos prazosestabelecidos, conforme orientação dos Professores

    Especialistas e Tutores.Fique atento às orientações de estudo que se encontram

    no Manual do Aluno! A EaD, pela sua característica 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

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    6/136

    ICONOGRAFIA

    Veja, abaixo, alguns símbolos utilizados neste material para guiá-lo em seus estudos.

    Fala do professor.

    Conceitos importantes. Fique atento!

    Atividades que devem ser elaboradas por você, após a leitura dos textos.

    Indicação de leituras complementares, referentes ao conteúdo estudado.

    Destaque de algo importante, referente ao conteúdo apresentado. Atenção!

    Reflexão/questionamento sobre algo importante, referente ao conteúdoapresentado.

    Espaço reservado para as anotações que você julgar necessárias.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    7/136

    Sumário1. ABSTRAÇÃO DE DADOS..........................................................................................................................9

    1.1 I NTRODUÇÃO.......................................................................................................................................... 9

    1.2 CONCEITOS DE ABSTRAÇÃO DE DADOS................................................................................................. 12 1.2.1 Abstração em Computação.............................................................................................................. 12 1.2.2 Abstração de Procedimentos........................................................................................................... 14 1.2.3 Tipos Abstratos de Dados................................................................................................................ 16 1.2.4 Implementação de Tipos Abstratos de Dados.................................................................................. 23 1.2.5 Avaliação de Implementações de Tipos Abstratos de Dados .......................................................... 25

    2. TIPOS ABSTRATOS DE DADOS FUNDAMENTAIS. ......................................................................... 30 2.1 PILHAS.................................................................................................................................................. 30

    2.1.1 Especificação do TAD Pilha............................................................................................................ 32 2.1.2 Implementação de Pilhas em Arranjos............................................................................................ 34

    2.2 FILAS.................................................................................................................................................... 37 2.2.1 Especificação do TAD FILA............................................................................................................ 39 2.2.2 Implementação de Filas em arranjos com deslocamento................................................................ 42 2.2.3 Implementação de Filas com Arranjos circulares........................................................................... 45

    2.3 IMPLEMENTAÇÃO DETADS COM ALOCAÇÃO DINÂMICA DE MEMÓRIA.................................................47 2.3.1 Revisão de Alocação Dinâmica de Memória................................................................................... 47 2.3.2 Implementação do TAD Pilha ......................................................................................................... 55 2.3.3 Implementação do TAD Fila ........................................................................................................... 59

    3. LISTAS E ÁRVORES................................................................................................................................65 3.1 LISTASCIRCULARES............................................................................................................................. 65 3.2 LISTACIRCULARDUPLAMENTE ENCADEADA....................................................................................... 75 3.3 ÁRVORESBINÁRIAS.............................................................................................................................. 82

    3.3.1 Árvore Binária de Pesquisa............................................................................................................. 83 3.3.2 O TAD Árvore Binária de Pesquisa ................................................................................................ 84 3.3.3 Implementação do TAD árvore Binária de Pesquisa ...................................................................... 85

    4. PESQUISA EM MEMÓRIA PRIMÁRIA................................................................................................99 4.1 PESQUISASEQÜENCIAL...................................................................................................................... 101

    4.1.1 Implementação da Pesquisa Seqüencial........................................................................................ 102 4.1.2 Tempo de execução de algoritmos................................................................................................. 103

    4.2 PESQUISABINÁRIA............................................................................................................................. 106 4.3 TABELASHASH................................................................................................................................... 108

    4.3.1 Operações de Inserção e Pesquisa em Tabelas Hash.................................................................... 111 4.3.2 Tratamento de Colisões ................................................................................................................. 114 4.3.3 Tratamento de Colisão usando endereçamento Aberto................................................................. 116

    5. ORDENAÇÃO EM MEMÓRIA PRIMÁRIA. ...................................................................................... 118

    5.1 CONCEITOSBÁSICOS DE ORDENAÇÃO................................................................................................ 118 5.1.1 Operações Típicas de processos de Ordenação............................................................................ 119 5.2 MÉTODOS DEORDENAÇÃO................................................................................................................. 119

    5.2.1 Ordenação por Seleção ................................................................................................................. 120 5.2.2 Método da Inserção....................................................................................................................... 121 5.2.3 Método da Bolha ........................................................................................................................... 123 5.2.4 Desempenho dos métodos de Seleção, Inserção e Bolha............................................................... 124 5.2.5 Método de Shell ............................................................................................................................. 124 5.2.6 O Método Quicksort ...................................................................................................................... 128

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    8/136

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    9/136

    Olá!

    Meu nome é Mateus Barcellos Costa, sou professore pesquisador do CEFET-ES desde 2005. Atuo naárea de Engenharia de Software e sou professor dedisciplinas de Programação. Se você quiser maisinformações sobre mim e sobre os trabalhos quedesenvolvo, pode visitar minha página pessoal emhttp://www.sr.cefetes.br/~mcosta.Produzi o material que ora lhe apresento comoinstrumento básico para o estudo da disciplina deTécnicas de Programação Avançada. Nestadisciplina iremos aprofundar nossosconhecimentos em Programação deComputadores usando uma linguagem imperativaou procedimental. Exemplos destas linguagenssão C e Pascal. Como de costume no nossoCurso, iremos adotar a linguagem C, em nossosexemplos e implementações. No entanto, é preciso que você saiba que os conceitos estudadosaqui vão além da linguagem e podem seraplicados em diversos cenários, na programaçãoe na Engenharia de Software como um todo.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    10/136

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    11/136

    Técnicas de Programação Avançada

    Página 9Centro Federal de Educação Tecnológica do Espírito Santo

    1. ABSTRAÇÃO DE DADOS.

    Olá! Neste Capítulo iremos discutir e aprendersobre Abstração de Dados . Abstração de Dados éuma técnica de programação que visa simplificaro desenvolvimento de programas. Sua aplicação pode se dar no desenvolvimento de programasmenores. Mas podemos afirmar que seriaimpossível o desenvolvimento de sistemas quetemos hoje, com milhões de linhas de código,sem o uso de abstração de dados.

    1.1 INTRODUÇÃOUm programa de computador desenvolvido para atender algumafinalidade prática é, normalmente, um artefato complexo. Por essemotivo, a atividade de desenvolvimento desses artefatos, a programação de computadores, está entre as atividades maiscomplexas desempenhadas pelo homem. Se você cursou disciplinasintrodutórias de programação, pode estar se questionando: Ora,desenvolver um programa não é tão complexo assim! Bastacompreender o problema, suas entradas e suas saídas e construir asolução usando uma linguagem de programação. Simples não? Não!A história da programação tem dado provas que programar não é tãosimples assim.

    Figura 1: OGap Semântico.

    Programar é uma atividade complexa por diversos aspectos, tanto decunho teórico quanto prático. Dentre estes aspectos destacamos osseguintes:

    1. Programar um computador significa desenvolver programas decomputadores ( formais e precisos ) para atender a finalidades

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    12/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 10

    práticas definidas em termos de conceitos do mundo real(informais e imprecisos ). Existe um abismo entre o mundodos problemas reais e o mundo das soluções. Esse abismo échamado na computação de gap semântico. Transpor o abismo

    é um dos desafios centrais da programação de computadores eda Engenharia de Software como um todo. A Figura 1 é umaalegoria que busca mostrar a função do desenvolvedor desoftware: Transpor o abismo entre o mundo informal (dos problemas) e o mundo formal (das soluções computacionais). Nessa transposição existem muitos desafios e perigos que podem dificultar a trajetória do desenvolvedor.

    2. Muitas vezes, em disciplinas iniciais de programação,deparamo-nos com o desenvolvimento de programas maissimples, de cunho didático. Por exemplo, programas para

    calcular médias ou somatórios. Em outros momentos fazemos programas para aprender a usar um certo mecanismo, porexemplo, 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 operações financeiras de uma empresa; b. Controlar uma aeronave;c. Controlar os trens de uma malha ferroviária;

    d. Produzir edições diárias de um jornal;e. Gerenciar o processo de produção de um filme.3. Problemas como esses não são simples de se resolver.

    Conseqüentemente, programas voltados para essas finalidadessão complexos,levam muito tempo para ficar prontos, têm de

    ser desenvolvidos por uma equipe de pessoas , utilizando diversas tecnologias e seguindo um processo de desenvolvimento sistemático .

    4. Para atender às funcionalidades esperadas, um programa deve apresentar um conjunto de características que juntas vão tornar o programa efetivamente útil e determinarão aqualidade do mesmo . Essas características são 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 dosdados x, y e z para realizar uma tarefa. Se este forrobusto, na falta de um dos dados, o programa pode

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    13/136

    Técnicas de Programação Avançada

    Página 11Centro Federal de Educação Tecnológica do Espírito Santo

    tentar realizar o processamento possível com aausência dado;

    c. Um programa deve ser eficiente. A eficiência de um programa está relacionada ao seu tempo de execução (eficiência na execução) ou aoespaço em memória (eficiência na ocupação) de que necessita para executar(área de dados). Para um problema há infinitassoluções (programas). Quanto menores esses valoresmais eficiente o programa. Em computação pode-severificar se uma solução é ótima (mais eficiente possível) para um problema;

    d. Um programa deve ser compatível com outros programas;

    e. Um programa deve ser fácil de usar;f. Um programa deve ser portável, 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

    verificável;i. O programa ou partes dele devem poder ser utilizados

    em outros cenários diferentes daquele para o qual o programa foi originalmente desenvolvido.

    5. Por último, devemos considerar a atividade de programaçãocomo atividade econômica. Assim como outras atividadeseconômicas, o desenvolvimento de software é regido por leisde mercado que impõem severas exigências aosdesenvolvedores. De acordo com essas leis, não basta apenasdesenvolver um programa que atenda à finalidade esperada.Esses programas devem ser desenvolvidos dentro dos prazos e

    custos estabelecidos . Além disso, o programa precisa teroutras características importantes que permitam a suaevolução. Essas características são chamadas de fatoresinternos. São eles:

    a. Facilidade de manutenção; b. Facilidade de evolução;c. Facilidade de entendimento;d. Modularidade.

    Pelos motivos discutidos acima, o desenvolvimento de programasrequer a aplicação de princípios, métodos e técnicas que diminuam acomplexidade desse desenvolvimento. A Abstração de Dados envolve

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    14/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 12

    uma série de conceitos e princípios para esse fim. A seguirdiscutiremos esses conceitos.

    Atividades

    Nesta introdução foram levantados cinco aspectos quetornam o desenvolvimento de software uma tarefadifícil. Para atacar esses aspectos e tornar odesenvolvimento de software mais simples sãoconsideradas três dimensões: Processo dedesenvolvimento, Pessoas (partes interessadas:clientes, desenvolvedores) e Tecnologias de

    desenvolvimento. Releia os cinco motivos e tenteescrever um texto resumido, estabelecendo umarelação entre esses 5 motivos e essas três dimensões.

    1.2 CONCEITOS DE ABSTRAÇÃO DE DADOS

    1.2.1 Abstração em ComputaçãoA abstração é um dos conceitos mais importantes da computação.Sem o uso deste conceito podemos afirmar que a evoluçãoapresentada pela computação teria sido mais lenta.Segundo o dicionário Michaelis, temos a seguinte definição para a palavra Abstração:1. O ato ou efeito de abstrair. Consideração das qualidadesindependentemente dos objetos a que pertencem. Abstrair: Considerarum dos caracteres de um objeto separadamente; 2. Excluir, prescindirde.A finalidade principal de uso de abstração 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 umesquema inicial mostrando as linhas principais do quadro que seencontra do lado direito(A Virgem, o Menino e Sant’Ana, Leonardo Da Vinci).

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    15/136

    Técnicas de Programação Avançada

    Página 13Centro Federal de Educação Tecnológica do Espírito Santo

    Figura 2: Abstração na Pintura.

    Observe que, no desenho, as proporções, os detalhes das posturas e

    feições são já determinados. Esse processo ajuda o pintor, pois, nomomento da idealização do quadro, ele não precisa se preocupar comoutros aspectos complexos, como cores, nuances de sombras ereflexos, para definir a estrutura e a sua aparência geral. Podemosdizer então que o desenho à esquerda é uma abstração do quadro.Em computação, abstração também possui finalidades semelhantes.Em programação, especificamente, esse conceito está presente quase otempo todo, seja nas construções existentes nas linguagens, seja nosmétodos de programação empregados.Uma das principais abstrações das linguagens de programação é o

    conceito de variável. Uma variável é um conceito abstrato queesconde diversos aspectos técnicos que não interessam ao programador. Quando declaramos uma variável em um programa, essadeclaração implica em “coisas” que não irão interferir no seudesenvolvimento. Por exemplo, por trás de uma variável do tipointeiro em C, (ex. int x;), estão “escondidas” as características físicasdo armazenamento da variável em memória, a saber:

    - A forma de representação de números inteiros usando base 2(por exemplo, complemento de 2);

    - O padrão usado pelohardware (ex.little endian, big endian);

    - O número de bytes que uma variável do tipo inteiro ocupa;- O endereço da variável na memória principal;- O conjunto de bits responsável por armazenar o sinal do

    número inteiro.Para o programador em C, geralmente, nenhuma dessasinformações é importante. O que o programador deseja é utilizar avariável realizando as operações permitidas aos números inteiros(operações aritméticas e comparações), atribuir, recuperar emodificar o valor contido na variável.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    16/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 14

    Assim podemos dizer que uma variável permite ao programadorabstrair-se de detalhes que não interessam e não irão influenciar nocomportamento do programa.

    AtividadesOs itens 1,2 e 3 são abstrações. Para cada um delesdescreva os aspectos que estão sendo escondidos eos aspectos que realmente importam ao programador:1. O comando

    2. Um arquivo3. A função scanf

    1.2.2 Abstração de ProcedimentosPodemos afirmar que a grande maioria dos elementos de linguagem

    utilizados em uma linguagem de programação de alto nível sãoabstrações. Essas abstrações facilitaram o desenvolvimento de programas mais complexos e sofisticados, evitando que programadores precisassem manipular bits e endereços de memória einteragir diretamente com o sistema operacional.Uma outra abstração de programação importante é a Abstração de

    Procedimento .

    Abstração de ProcedimentoA abstração de procedimento permite que o programa-dor crie, ele mesmo, sua “forma de abstrair”, utilizandoos comandos disponíveis na linguagem. A possibilidadede criar procedimentos permite ao programador criarfuncionalidades mais abstratas que “escondem” asequencia de operações necessária para a realização deuma tarefa complexa.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    17/136

    Técnicas de Programação Avançada

    Página 15Centro Federal de Educação Tecnológica do Espírito Santo

    Por exemplo, sabemos que na linguagem C não existe um comandoque seja capaz de ordenar um vetor de inteiros em ordem crescente.Seria muito bom que pudéssemos contar com esse comando, certo?Mas, como não temos esse comando, iremos criar uma função

    (abstração de procedimento) que realize essa tarefa para nós. A funçãoordenana Figura 3 é essa abstração.

    Figura 3: Função ordena: Cria uma abstração do procedimento de ordenação.

    Após a implementação da funçãoordena, quando o programador precisar ordenar um vetor, basta que ele invoque a função, passandoos parâmetros necessários. Ou seja, ao usar o procedimento, o programador irá se preocupar apenas com o que a função faz e nãomais com os detalhes de sua implementação.Uma abstração de procedimento deve realizar uma tarefa (porexemplo, ordenar um vetor de inteiros) que deve ser independente daforma como este vai ser implementado. O programador deve antes detudo ver o procedimento como uma caixa preta, cuja especificaçãodeve conter três elementos básicos (Figura 4):

    Entrada: O conjunto de dados de entrada necessário; Saída: O conjunto de dados produzido pelo procedimento; Função: A descrição do que o procedimento faz.

    Figura 4: Os elementos considerados na definição de um procedimento.

    Na especificação do procedimento, o programador não deve estar preocupado com a implementação, mas sim com o comportamento(função) do mesmo. Qualquer implementação que realize a funçãoespecificada irá servir como solução. Para o caso da ordenação,veremos adiante neste curso que existem diferentes métodos deordenar um vetor. O método utilizado na funçãoordena se chama

    ordenação por inserção . A implementação interna poderia ser

    ENTRADA SAÍDAFUNÇÃO

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    18/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 16

    substituída por qualquer outro método de ordenação. A próprialinguagem C oferece em sua biblioteca padrãostdlib , uma funçãochamada qsort , que pode ser usada para ordenar vetores. Essafunção utiliza um outro método de ordenação muito conhecido etambém muito rápido, chamado deQuick Sort .

    Atividades

    1. Suponha que você tenha disponíveis asseguintes funções em C:

    Int CalculaMedia ( int *not as) ; Void

    DeterminaMaiorEMenorNotas ( int *v, int * mai or , int *menor ) ;

    Void leNotas ( int *not as) ; Void MostraResultados ( int

    medi a, int mai orNot a, int menor Not a) ;

    Utilizando essas funções, desenvolva um programa emC que leia as notas de 5 turmas e para cada uma delas,imprima a média, a maior e a menor nota.

    1.2.3 Tipos Abstratos de DadosA abstração de dados visa aos mesmos objetivos que a abstração de procedimentos, mas com relação às estruturas de dados utilizadas nos programas. A abstração de dados visa criar novos tipos de dadosdefinidos em temos de seu comportamento. Esses novos tipos sãochamados deTipos Abstratos de Dados - TAD .É muito importante que você perceba que um tipo abstrato de dadosnão se resume a uma nova estrutura de dados. Vamos então discutirum pouco sobre essa diferença.Primeiramente, uma estrutura de dados pode ser definidasimplesmente como uma variável capaz de armazenar mais de umvalor simultaneamente. Assim, um vetor, uma matriz ou um registro(struct em C) são exemplos de estruturas de dados. A combinaçãodesses elementos em estruturas mais complexas dá origem a outrasestruturas de dados. A Figura 5 apresenta as declarações destruct

    ponto e struct reta, como exemplos de tipos de estruturasde dado.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    19/136

    Técnicas de Programação Avançada

    Página 17Centro Federal de Educação Tecnológica do Espírito Santo

    Figura 5: Estruturas de Dados ponto e reta.

    Ao definir astruct ponto, passamos a contar com mais umaalternativa para definição de tipos de variáveis e, conseqüentemente, para a composição de novos tipos de estruturas. Assim a structreta foi definida como uma composição de duas variáveis do tipostruct ponto . Essas estruturas podem ser usadas para declarartanto variáveis como argumentos de funções.

    Em C temos ainda a cláusulatypedef, que permite definir onomedo novo tipo. Nesse caso, não precisamos usar a palavra reservadastruct na declaração de variáveis do tipo definido. Na Figura 6temos o uso detypedef . Veja que na definição do tipoReta, onomePonto é usado sem a palavra reservadastruct .

    Figura 6: Definição dos tipos Reta e Ponto.

    Estrutura de Dadosversus Tipo Abstrato de DadosA definição de uma estrutura de dados se preocupa emdemonstrar como o objeto é representado na memóriade um computador (representação). Nessa definição sãoconsiderados aspectos do tipo: quais as informações queserão armazenadas ali e qual a quantidade destasinformações. A definição de um Tipo Abstrato deDados segue uma abordagem diferente. Essa definição éfeita em termos das operações que podem ser realizadassobre o tipo.A definição de um Tipo Abstrato de Dado (TAD) échamada de especificação e consiste, basicamente, emdefinir as operações relacionadas ao tipo. Dizemos queessas operações definem o comportamento do TAD.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    20/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 18

    Vamos aplicar o conceito de TAD considerando os objetos Reta ePonto. Um passo importante na definição do TAD, que já ajuda na programação de uma maneira geral, é que não conseguimos defini-losem conhecermos a sua finalidade e o contexto no qual será usado.

    Em nosso exemplo precisamos saber para quê nós queremos um ponto e uma reta. Geralmente essa informação é conseguida a partirdo enunciado do problema. Assim, vamos supor a seguinte descrição para o nosso problema envolvendo retas e pontos: Problema A. É necessário um programa de computador que realizeoperações geométricas envolvendo pontos e retas localizadas no plano cartesiano. O programa deve permitir: calcular a distância do ponto até a origem do plano cartesiano; calcular a distância entredois pontos; dada a representação da reta por dois pontos, calcular oângulo de inclinação da reta, fornecer os parâmetros a e b

    correspondentes a equação da reta ax + b. Determinar a distância deuma reta a um ponto. Evidentemente, o programa deve permitir aleitura e impressão de pontos e retas conforme a necessidade dasoperações.Com base na descrição acima podemos identificar a necessidade doTAD ponto e do TAD Reta, bem como suas operações. Essasoperações aparecem sublinhadas no texto do problema e sãoapresentadas nas Figuras 7 e 8.

    Figura 7: operações do TAD Ponto para o problema A.

    Figura 8: operações do TAD Reta para o problema A.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    21/136

    Técnicas de Programação Avançada

    Página 19Centro Federal de Educação Tecnológica do Espírito Santo

    Agora, considere que estejamos desenvolvendo um programa para o problema abaixo: Problema B. É necessário um programa de computador paraapresentar graficamente figuras geométricas formadas por pontos eretas, usando o monitor do computador como plano. O programadeve 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 equação dessa reta; dada umareta representada por dois pontos, plotar esta reta no monitor; dadauma reta e um valor d, criar uma reta paralela à reta dada a umadistancia d da reta.As operações necessárias aos TAD Ponto e Reta neste problema sãoapresentadas nas Figuras 9 e 10.

    Figura 9: operações do TAD Ponto para o problema B.

    Figura 10: operações do TAD Reta para o problema B.

    Note que nos dois problemas foram definidos os tiposPonto e Reta. No entanto, a abstração necessária diferede um problema para o outro, interferindo na definiçãodas operações. Embora existam essas diferenças, iremossempre tentar criar abstrações mais genéricas o quantofor possível. Quanto mais genérico um TAD, maior onúmero de problemas em que esse poderá ser aplicado.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    22/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 20

    Embora as operações não informem nada a respeito darepresentação interna de um TAD, elas fornecem ao programador tudo o que ele precisa para manipular oTAD. As operações de um TAD especificam a suainterface com o restante do programa. Isso significa quequalquer ação relacionada ao TAD deve ser feitamediante uma de suas operações.Temos como resultado prático que o programador, aousar o TAD, não vai precisar se preocupar com sua im- plementação interna. Iremos agora analisar esse aspectoconsiderando os TAD Ponto e Reta e o problema A.

    Na implementação, ponto e reta foram definidos e implementados,originando dois módulos independentes: o módulo Ponto e o móduloReta. Cada módulo em C é normalmente implementado por doisarquivos: o arquivo .h e o arquivo .c. No arquivo .c teremos aimplementação das operações do TAD e no arquivo .h teremos aespecificação dainterface do TAD. A Figura 11 e a Figura 12apresentam as interfaces dos módulos Ponto e Reta, respectivamente.

    Figura 11: Interface do TAD Ponto.

    Figura 12: Interface do TAD Reta.

    Com a implementação dos TADs Ponto e Reta concluídas edevidamente testadas, qualquer outro módulo do programa poderáutilizar esses tipos por meio das operações definidas para os mesmos.Quando um módulo A utiliza um módulo B em programação,

    dizemos que o módulo A é cliente do módulo B . Essa relação de“clientela” entre os módulos (ou TADs) de um programa pode serrepresentada graficamente por meio de umdiagrama de estruturamodular - DEM.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    23/136

    Técnicas de Programação Avançada

    Página 21Centro Federal de Educação Tecnológica do Espírito Santo

    Diagrama de Estrutura ModularUm diagrama de estrutura modular é formado porretângulos e linhas direcionadas relacionando os

    retângulos. Cada retângulo representa um módulo. Aslinhas direcionadas significam “cliente de”e indicam oacionamento de operações contidas no módulo apontado pelo módulo cliente. Esses digramas também sãochamados diagramas hierárquicos, pois apresentam ahierarquia dos módulos, iniciando por um módulo queinicia o programa e acionam os demais módulos.

    Como exemplo, suponha que tenhamos também, junto aos módulosPonto e Reta, um módulo chamado principal. Esse módulo é clientedos módulos Ponto e Reta. A Figura 13 a seguir ilustra o DEM deste programa. O módulo que inicia o programa é o módulo principal (edeve conter uma função main()). Ele aciona as operações tanto domódulo ponto quanto do módulo reta. Reta, por sua vez, também écliente do módulo ponto.

    Figura 13: DEM com módulos Ponto, Reta e Principal.

    A Figura 14 ilustra a implementação de um módulo Principal. Noteque a única forma de acesso aos TADsPonto e Reta é por meio dasoperações definidas em suas respectivas interfaces.

    Use diagramas de estrutura modular sempre que foriniciar um novo projeto. Defina os TADs e estabeleça orelacionamento entre eles por meio de DEMs. Junto àslinhas, você pode especificar as operações do TAD quesão acionadas pelo cliente. Isso vai ajudar você naespecificação dos TADs.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    24/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 22

    Atividades

    Implementar as operações do TadPonto e do TadRetaconsiderando o enunciado do problema 1, da Seção 1.2.3do texto, e desenvolver um programa usando a função principal (do quadro a seguir) de forma a testar asoperações.

    Figura 14: Módulo Principal para o Problema A.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    25/136

    Técnicas de Programação Avançada

    Página 23Centro Federal de Educação Tecnológica do Espírito Santo

    Até o momento, em nosso exemplo envolvendo Ponto eReta, não abordamos a questão de como as operaçõesserão implementadaspropositalmente. É que até a parte que apresentamos do desenvolvimento não precisamos saber mesmo. Você por acaso lembra comose calcula a distância entre dois pontos? E a distânciaentre uma reta e um ponto? Pois bem, o importante éque você tenha compreendido a discussão feita e oexemplo dado, mesmo sem saber responder essas duas perguntas. Assim espero!

    1.2.4 Implementação de Tipos Abstratos de Dados

    Um dos principais benefícios da abstração de dadosé separar o comportamento do TAD, especificado por meio da definição de suas operações, da suaimplementação . Em nosso exemplo, o que definimos arespeito dos TAD Ponto e Reta foi o seucomportamento, as suas operações. Nesta seção,discutiremos melhor como separar em um projeto adefinição do comportamento e da implementação de umTAD.

    O projeto completo de um TAD consiste de dois passos:1. Especificação - Consiste na especificação do comportamento

    do TAD;2. Implementação – Implementação das operações e estruturas

    de dados.

    EspecificaçãoA especificação de um TAD descreve o que TAD faz, mas omiteinformações sobre como o mesmo é implementado. Por omitir

    detalhes de implementação, uma única especificação permite muitasimplementações diferentes.A especificação é feita por meio da definição das operações do TAD.Para detalhar melhor cada uma destas operações, devemos estabelecer, para cada operação, dois elementos:

    - Pré-condições: definem as condições necessárias para que aoperação possa ser realizada. Por exemplo, suponha quedesejamos especificar o TAD Conjunto com a operaçãolistarConjunto . Uma pré-condição para essa operação éque o Conjunto não esteja vazio.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    26/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 24

    - Pós-condições: definem o estado do TAD após a execução daoperação. Por exemplo, suponha a operaçãoinserirElemento no TAD conjunto. Uma pós-condição para essa operação seria: elementos no conjunto = elementosno conjunto + novo elemento. A Figura 15 ilustra a definiçãodo TAD conjunto.

    Figura 15: Especificação do TAD Conjunto.

    ImplementaçãoUm TAD é implementado por um módulo de um programa . Umaúnica especificação permite diferentes implementações para ummesmo TAD. Uma implementação está correta se esta provê ocomportamento especificado para o TAD. Implementações corretas podem diferir uma da outra, por exemplo, em termos do algoritmo ouda estrutura de dados que elas usam. Essas diferenças interferem naeficiência (desempenho em tempo de execução, ou ocupação deespaço) apresentado pelo TAD para realização das operações.

    EncapsulamentoPara uma abstração funcionar corretamente, a suaimplementação deve ser encapsulada . Se aimplementação for encapsulada, nenhum outro módulodo programa vai depender de detalhes deimplementação do TAD. Encapsulamento garante quemódulos do programa podem ser implementados e re-implementados independentemente, sem afetar os outrosmódulos do programa.

    O encapsulamento geralmente é conseguido por meio da separação dainterface e da implementação do módulo. Conforme já vimosanteriormente, em C a implementação de um TAD por meio de ummódulo consiste em duas partes: a especificação da interface do

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    27/136

    Técnicas de Programação Avançada

    Página 25Centro Federal de Educação Tecnológica do Espírito Santo

    módulo por meio do arquivoheader(com extensão.h) e da implemen-tação das operações por meio de um arquivo com extensão .c.

    1.2.5 Avaliação de Implementações de Tipos Abstratos deDados

    É fundamental para um programador saber criticar eavaliar a qualidade de uma implementação! Umaimplementação baseada em Abstração de Dados é umindicativo de boa qualidade. Nesta Seção, discutiremoselementos que permitem que você verifique se umaimplementação realmente está de acordo com essatécnica.

    Embora a linguagem C não ofereça um mecanismo que impeçarealmente que o programador tenha acesso à estrutura interna do TAD,esta é uma regra fundamental e deve ser respeitada pelo programador.Esta regra ou característica de TADs é o encapsulamento, discutido naseção anterior . Dizemos que um TAD é encapsulado por suasoperações no sentido de que a estrutura interna do TAD fica preservada e invisível ao restante do programa. Violar essa regrasignifica não usar corretamente a Abstração de Dados.

    Localidade

    O maior benefício do encapsulamento chama-se princípio da Localidade . Esse princípio permite que um programa seja implementado, entendido e modificadoum módulo de cada vez. A localidade aumenta aqualidade do software que está sendo desenvolvido.

    Dentre os benefícios oriundos do princípio da localidade temos:1. O programador de uma abstração sabe o que é necessário pelo

    que está descrito na especificação. Dessa forma, ele não

    precisa interagir com programadores de outros módulos (ou, pelo menos, essa interação vai ser bem limitada).2. De forma análoga, o programador de um módulo que usa a

    abstração sabe o que esperar desta abstração, apenas pelocomportamento descrito em sua especificação.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    28/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 26

    Uma ferramenta que pode contribuir para esseentendimento é a documentação do TAD. Ou seja, aexplicação sobre o seu funcionamento e sobre comoutilizá-lo. Procure sempre fazer uma boa documentaçãodo TAD. Essa documentação pode vir como umdocumento à parte que acompanha o módulo.

    3. É necessário apenas o raciocínio local (por módulo), para sabero que o programa faz e se está fazendo a coisa certa. Paraestudar e compreender o programa podemos dividi-lo emmódulos, e analisar um módulo de cada vez. Em cada caso, preocupamo-nos em saber se o módulo faz o que é suposto quefaça. Ou seja, se ele cumpre o que está na especificação.

    Pode-se assim limitar a atenção para um módulo, ignorandotanto os módulos usados por este quanto os que o utilizam. Osmódulos que utilizam o módulo estudado podem ser ignorados porque dependem apenas de sua especificação e não da suaimplementação. Os módulos utilizados são ignorados,raciocinando-se sobre o que eles fazem utilizando apenas suaespecificação em vez de sua codificação. Com isso, tem-seuma grande economia de esforço, dado que as especificaçõessão muito menores que as implementações. Observando-seapenas as especificações evita-se também um efeito cascata.Por exemplo, se tivermos que olhar o código do módulo queutilizamos, teremos que olhar também o código dos módulosque são utilizados pelos módulos que utilizamos e assim pordiante.

    4. Finalmente, a modificação do programa pode ser feita módulo por módulo. Se uma abstração particular necessita serreimplementada para prover um melhor desempenho, corrigirum erro ou prover uma nova funcionalidade, o móduloimplementado anteriormente pode ser trocado por uma novaimplementação sem afetar os outros módulos.

    PrototipagemLocalidade também provê uma base firme para a

    prototipação ou prototipagem. Um protótipo é umaimplementação inicial, rudimentar e incompleta deum programa a ser desenvolvido. Se mantivermos o princípio da localidade no desenvolvimento do protótipo, essa implementação inicial pode ir sendocompletada ou substituída por implementaçõesmelhores sem grande esforço nem re-trabalho.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    29/136

    Técnicas de Programação Avançada

    Página 27Centro Federal de Educação Tecnológica do Espírito Santo

    Localidade também provê suporte para evolução. Abstrações podem ser utilizadas nesse caso paraencapsular modificações potenciais no programa . Por exemplo, suponha que desejamos um programa para ser executado em diferentes máquinas. Podemos

    tratar esse problema inventando abstrações que escondam asdiferenças entre as máquinas de forma que, para mover o programa para uma máquina diferente, apenas essas abstrações precisem ser reimplementadas. Um bom princípio de projeto é pensar sobre modificações esperadas e organizar odesenvolvimento utilizando abstrações que encapsulem asmudanças.

    Domínio da complexidade

    Os benefícios da localidade são particularmenteimportantes para a abstração de dados. Estruturas dedados são muitas vezes complicadas e a visão maisabstrata mais simples provida pela especificação torna oresto do programa mais simples. Ainda, mudanças nasestruturas de armazenamento são uma das principaisformas de evolução de programas. Portanto, os efeitosdessas mudanças devem ser minimizados encapsulandoessas estruturas de dados em abstrações de dados.

    Se avaliarmos um programa segundo o critério da abstração dedados, devemos observar os seguintes fatores:1. Os TADs estão realmente encapsulados?

    a. O entendimento de cada módulo do programaindepende dos demais módulos?

    b. O efeito cascata é evitado na depuração?c. É possível reimplementar um módulo sem afetar os

    outros?

    2. Potenciais mudanças foram previstas no projeto do TAD?3. Os TADs oferecem abstrações suficientemente simples das

    estruturas de dados que encapsulam?

    Atividades

    Os códigos a seguir especificam as interfaces de doismódulos: Aluno e Turma.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    30/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 28

    /******** aluno.h ***********/typedef struct al uno{

    char nome [ 30] ;i nt mat r i cul a ;int cdgcur so ;

    } Al uno ;void leAluno ( Al uno * ) ;void imprimeAluno ( Al uno ) ;void Al t er aAl uno( Al uno *) ;

    /******** turma.h **********/#include "al uno. h" #define MAXTURMA 100typedef struct t ur ma {

    int nal unos ;Al uno al unos [ MAXTURMA] ;

    } Tur ma ;void insereAluno ( Tur ma *, Al uno) ; / *i nser e o

    al uno passado como par ament r o na t ur ma */ void localizaAluno ( Tur ma *, char * ) ; / *l ocal i za um al uno na t ur ma pel o nome */ void imprimeTurma ( Tur ma ) ;void atualizaAlunoDaTurma ( Tur ma *, char * ) ;

    Agora, suponha que tenhamos o seguinte módulo principal,utilizando esses módulos:

    / ************ Modul o Pr i nci pal**************/ #include " t ur ma. h"

    Tur ma t ur ma1;void principal ( ){int opcao, i ;al uno a;char nome[ 30] ;

    do {scanf ( " %d" , &opcao) ;switch ( opcao) {case 1: / * cadast r ar al uno */

    l eal uno( &a) ;i nser eAl uno( &t ur ma1, a) ;

    break ;case 2:scanf ( " %s" , nome) ;a= l ocal i zaAl uno( &t urma1, nome) ;pr i nt f ( " %s - %d - %d" , a. nome,

    a. mat r i cul a, a. cdgcur so) ; break ;

    case 3: / * i mpr i mi r t ur ma */ for ( i =0; i

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    31/136

    Técnicas de Programação Avançada

    Página 29Centro Federal de Educação Tecnológica do Espírito Santo

    scanf ( " %s" , nome) ;at ual i zaAl unoDaTur ma( &t ur ma1,

    nome) ; break ;

    }

    }

    Tarefas:a) Critique a implementação do módulo acima com

    base nos critérios de avaliação de TADs discutidosacima. b) Faça uma implementação da operaçãoatualizaAlunoDaTurma, respeitando os princípios de programação baseada em tipos abstratos de dados.

    Dijkstra (1930-2002) foi, sem dúvida, um doscientistas que mais contribuíram para odesenvolvimento da Programação de Computadores.Terminamos este capítulo com uma frase dele, queresume o conceito de abstração:“O propósito da abstração não é ser vaga, mas sim,

    criar um novo nível semântico no qual ela possa serabsolutamente precisa”.Edsger. W. Dijkstra, The Humble Programmer (O programador Mediocre), Communications of the ACM, 15(10), 1972.Reflita sobre isso!

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    32/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 30

    2. TIPOS ABSTRATOS DE DADOSFUNDAMENTAIS.

    Olá! Após o estudo e a compreensão dos con-ceitos que definem a técnica de Abstração deDados, utilizaremos esses conceitos em nosso estu-do até o final da disciplina. Portanto, se você nãocompreendeu ou não se sente ainda plenamenteconvencido de que deve utilzar Abstração deDados em seus programas, recomendo que retorneao Capítulo 2. O motivo disso é muito simples.

    Daqui para frente estudaremos problemas e solu-ções mais complexos, que exigem muito do estu-dante em sua capacidade de abstração. NesteCapítulo, em particular, iniciamos nosso estudo deum conjunto de TADs muito comuns eimportantes: Os TAD Pilha e Fila.

    No decorrer da evolução da programação, padrões e práticas comunstêm sido observadas e transformadas em conceitos, modelos e meca-nismos que podem ser utilizados em mais de uma situação diferente.Dentre esses elementos temos uma coleção de tipos abstratos de dadosque são comuns a diversas situações e aplicáveis na solução de umagrande quantidade de problemas. Dois desses TADs são as Pilhas e asFilas, que estudaremos em profundidade neste capítulo.

    2.1 PILHAS No mundo real uma pilha corresponde a um agregado de objetos quesão acomodados um sobre o outro. A Figura 1 ilustra uma pilha emque os objetos são caixas.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    33/136

    Técnicas de Programação Avançada

    Página 31Centro Federal de Educação Tecnológica do Espírito Santo

    Figura 1: Uma Pilha de Caixas

    Os números nas caixas indicam a ordem de empilhamento. Sequisermos agora remover as caixas da pilha (desempilhar), temos queremover a caixa 4 primeiro, depois a 3, a 2 e finalmente a 1. Não podemos remover as caixas abaixo da que está no topo da pilha semantes remover a do topo. Esse comportamento pode ser definido pelaestilo:O último a entrar é o primeiro a sair . No mundo real temos diversas situações em que esse comportamentodeve ser respeitado. Assim, o uso de pilhas pode facilitar a soluçãode vários problemas. Um exemplo típico de uso de pilha é a

    operação desfazer , presente na maior parte dos editores de texto.Quando voce executa a operação desfazer, a última operaçãorealizada é que deverá ser desfeita primeiro. Se você executar odesfazer novamente, a penúltima operação deverá ser desfeita, e assimsucessivamente. Concluindo, precisamos ter sempre a informação dequal foi a última operação realizada. Uma pilha é uma forma eficientede obtermos esa informação. Se tivermos uma pilha em queempilhamos a operação que foi feita, teremos no topo da pilha semprea operação que devemos desfazer.Realmente, editores texto que possuem a operação desfazer mantém

    uma pilha que guarda informações sobre as ações que vão sendorealizadas durante a edição. Por exemplo, no momento em que estetexto era digitado, as informações passadas via teclado e mouse eramtambém empilhadas.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    34/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 32

    A aplicação de pilhas em editores de texto é umexemplo de uma funcionalidade muito comum de uso de pilha. Essa funcionalidade está presente em outroscenários, como em jogos, programas de logistica,robótica e redes de computadores. O que esses cenáriostêm em comum é a necessidade deretroceder por umcaminho de dados ou ações que tenha realizado. Esseretocesso se dá também em algoritmos debacktracking,(algo como voltar na trilha) e é muito comum emalgoritmos de busca e recuperação de informação. Vejaa discussão sobre esses algoritmos emhttp://pt.wikipedia.org/wiki/Backtracking.

    2.1.1 Especificação do TAD PilhaO TAD Pilha pode ser descrito pela seguinte especificaçãoapresentada na Figura 2. Nessa especificação são definidas asoperações Empilha, que insere elementos na Pilha e Desempilha, queremove elementos da Pilha. São definidas também as pré-condições e pós-condições dessas operações.

    Figura 2: especificação do TAD Pilha.

    Além das operações empilha e desempilha, temos também a operaçãoinicializaPilha, que coloca a Pilha em um estado inicial, com a pilhavazia. A Figura 3 ilustra uma possível implementação do TAD Pilhalimitado a 5 (cinco) posições. Cada posição possui um índice. O topomantém o índice do valor que está presente no topo. Nesse exemplo,

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    35/136

    Técnicas de Programação Avançada

    Página 33Centro Federal de Educação Tecnológica do Espírito Santo

    temos o elemento do topo na posição de índice 5, conforme indica afigura. Se convencionarmos que os elementos foram inseridos na pilhana 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 implementação de pilha a atualização dotopo consiste em incrementar de 1 na operação empilha e decrementarde 1 na operação desempilha. As pré-condições também podem serobtidas da implementação. A operação Pilha Vazia pode ser verificada por meio do teste do valor do topo. Por exemplo, se iniciarmos a pilhacom topo valendo 0, podemos usar o teste topo == 0 para verificar se pilha está vazia. Já a pré-condição pilha cheia pode ser verificadaconsiderando o limite da implementação. No nosso exemplo esselimite é 5. Se o topo == 5, a pilha está cheia. Com isso, fica definidatambém a operação inicializaPilha que deve fazer o topo valer 0

    (zero).

    Figura 3: Implementação de uma Pilha.

    É importante neste momento notar que existem muitasimplementações possíveis para a especificação do TAD pilha (conforme discutido no Capitulo 1). Esse exemploapresentado é apenas uma das possíveis soluções.Um outro detalhe é que, além das operações empilhar edesempilhar, as pré-condições de pilha Cheia e pilhaVazia podem também se tornar operações do TAD Pilhana implementação. Na próxima seção discutiremosalgumas implementações de Pilha usando arranjosestáticos.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    36/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 34

    Atividades

    1. Na seqüência a seguir, uma letra significaempilha e um asterisco significa desempilha.Determine a seqüência de valores retornados pela operação desempilha quando essaseqüência de operações é realizada sob uma pilha inicialmente vazia.

    E A S * Y * Q U E * * * S T * * * I O * N * * *

    2. Suponha que uma seqüência misturada deoperaçõesempilha e desempilha é realizada.

    As operaçõesempilha empilham inteiros de 0até 9 ordenadamente. A operaçãodesempilha desempilha e imprime o valor desempilhado.Qual das seqüências abaixo não poderá serimpressa?

    (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 Implementação de Pilhas em ArranjosA Figura 3 ilustra por meio de um diagrama uma implementação dePilha. Usando arranjos estáticos (vetores) e fazendo algumasadaptações, podemos criar essa implementação em C. Aimplementação, conforme discutido na Seção 1.2.4, será formada deduas partes, a interface (arquivo com extensão .h) e aimplementação das operações (arquivo com extensão .c). Érecomendado primeiro a definição do arquivo de interface e depois aimplementação das operações. A seguir discutiremos uma possívelimplementação do TAD Pilha, utilizando arranjos.A Figura 4 mostra o arquivo de interfacetadpilha.h . Foi definidoum novo tipo chamadoPilha , formado por dois elementos principais: Uma variável inteiratopo e o vetoritens, que serviráde contêiner para a pilha. O vetoritens é do tipo Elemento, que éapenas uma redefinição do tipochar . A definição desse tipoElemento facilita posteriores modificações no tipo básico da pilha. Sequisermos, por exemplo, alterar a pilha para que esta empilhe edesempilhe valores inteiros, basta redefinir o tipoElemento como

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    37/136

    Técnicas de Programação Avançada

    Página 35Centro Federal de Educação Tecnológica do Espírito Santo

    int. Foram definidas assinaturas (protótipos) das funçõescorrespondentes às operaçõesinicializaPilha , empilha ,desempilha e aos testes das pré-condições, pilhaCheia e

    pilhaVazia . Observe que estamos seguindo a notação de protótipos padrão de C. Nessa notação, apenas os tipos dosargumentos (parâmetros das funções) são identificados, sendo osnomes mesmos desses argumentos apenas na implementação. Notetambém que a operaçãodesempilha retorna umElemento . Isso é bastante comum, pois normalmente se deseja fazer alguma coisa como elemento desempilhado.

    Figura 4: Interface do TAD Pilha com arranjos estáticos.

    Na Figura 5, temos a implementação das operações feitas no arquivotadPilha.c. A operaçãoinicializaPilha faz o topo da Pilhareceber 0 (zero).PilhaCheia verifica se topo igual a MAX(tamanho máximo que a pilha pode ter) ePilhaVazia verfica se

    topo igual a 0. Na operaçãoempilha temos a seguinte ordem: insereo elemento e depois incrementa o topo. Isso é necessário porque em Ca primeira posição de um arranjo é a 0 (zero) e com a Pilha vazia otopo está em zero. Assim, o topo estará sempre com um índice doelemento no topo + 1. Para compensarmos isso, na operaçãodesempilha devemos decrementar o topo retornando o elementosomente após o topo ser decrementado.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    38/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 36

    Figura 5: Implementação das operações do TAD Pilha.

    Atividades

    1. Empilhamento decrescente. Uma empilhadeiracarrega caixas de 7, 5 e 3 toneladas. Há três pilhasA, B e C. A pilha A é onde se encontram todas ascaixas que chegam no depósito. Com um detalhe:caixas maiores não podem ser empilhadas sobrecaixas menores. Elabore uma funçãochegaNoDeposito (Caixa* nova,Pilha* A) que efetue o controle das caixas, deforma que, caso uma caixa de maior peso do queuma que já está em A deva ser empilhada, então,todas as caixas que estão em A são movidas para as pilhas auxiliares B (contendo somente caixas de 5

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    39/136

    Técnicas de Programação Avançada

    Página 37Centro Federal de Educação Tecnológica do Espírito Santo

    toneladas) e C (contendo somente caixas de 3toneladas) até que se possa empilhar a nova caixa.Depois, todas as caixas são movidas de volta para a pilha A.

    2. Implementar o TADPilhaDupla , usando umarranjo de 100 posições.PilhaDupla deve usarum único arranjo para implementar as duas pilhas.Além disso, a ocupação da Pilha deve maximizar ouso do espaço do arranjo, ou seja, enquanto houver espaço no arranjo qualquer uma das duas pilhas pode utilizá-lo.

    2.2 FILASEm nosso cotidiano nos deparamos constantemente com filas. Oumelhor, estamos constantemente entrando e saindo de filas! Muitas pessoas se aborrecem com as filas. Todavia, podemos dizer que elassão um mal necessário. Por exemplo, imaginem se, para entrarem emum ônibus em uma cidade, as pessoas não fizessem uma fila esimplesmente se amontoassem na porta. Seria um tumulto, as pessoasque estivessem no ponto há mais tempo poderiam não conseguir entrarou ficar sem assento.O mais incrível é que isso acontecia há uns 20anos 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 idéia de que o emprego de filas no dia-a-dia éfundamental para a organização das atividades feitas pelas pessoas,sempre que o número de clientes de um recurso é maior que a

    capacidade de atendimento desse recurso. No caso do ônibus, orecurso é a porta de entrada, que só atende uma pessoa por vez. Commais de uma pessoa no ponto esperando para entrar, é necessário queelas formem uma fila. Um outro exemplo é fila em um banco, cujorecurso necessário é o caixa. Quando entram mais clientes do que onúmero de caixas, os clientes devem formar uma fila.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    40/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 38

    O comportamento de uma fila pode ser descrito pelo estilo:O primeiro que chega é o primeiro a ser atendido . Em uma Filaorganizada e sem prioridades (Figura 6, por exemplo), essa regra ésempre obedecida.

    Na programação aplicamos o conceito de fila para tratar casossemelhantes ao do ônibus e ao do banco. Alguns exemplos deaplicação de filas são:

    Fila de espera de passagens aéreas – Suponha, por exemplo,que você esteja desenvolvendo um sistema de reservas de passagens aéreas. Nesse tipo de sistema, as pessoas fazemreservas até o recurso (número de assentos no vôo) se esgotar.Quando isso acontece, se houver mais pessoas que queremviajar naquele vôo, elas entram em uma fila de espera. Sehouver uma desistência das reservas, a primeira pessoa dessafila será atendida.

    Fila de mensagens – Suponha que você esteja desenvolvendoum programa A que envie constantemente mensagens a um programa B. O programa B precisa receber essas mensagens e processá-las. Se o número de mensagens que o programa Aenvia 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 guardaras mensagens até que elas possam ser processadas. Esse é umcaso muito comum na Internet. Quando fazemos a requisição

    de uma página Web, o navegador (programa A) envia umamensagem ao servidor Web (programa B). Esse servidor podereceber mais requisições (mensagens) do que a sua capacidadede processamento. Nesse caso, ele deve enfileirar asrequisições para que elas não sejam perdidas e para que sejamatendidas na ordem de chegada.

    Teoria das FilasO estudo das Filas, do ponto de vista estatístico e probabilístico, denomina-se Teoria das Filas ecompreende uma disciplina de grande interesse dediversas áreas da engenharia, computação eadministração. Essa disciplina permite, dentre outrascoisas, estimar a capacidade de recursos a seremconstruídos (p.exemplo, aeroportos, pontes,armazéns de estocagem), identificar gargalos(pontos de atraso) em sistemas e estimar o tempo para a realização de uma tarefa.Em nosso estudo,nos concentraremos apenas na implementação eemprego de filas em programação, e não naTeoria das Filas.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    41/136

    Técnicas de Programação Avançada

    Página 39Centro Federal de Educação Tecnológica do Espírito Santo

    2.2.1 Especificação do TAD FILA

    O tipo abstrato de dados fila pode ser descrito pela especificação da

    Figura 7.

    Figura 7: Especificação do TAD Fila.

    As operações fundamentais do TAD Fila sãoinserir e remover .Para garantir o comportamento esperado em uma fila, definimos que ainserção é feita nofinal da fila e a remoção é feita nocomeço da fila.Temos também a operação inicializaFila, que coloca a fila em umestado inicial, no qual a fila deve estar vazia. A partir dessasoperações e de suas pré e pós-condições podemos deduzir que serãonecessárias as operações de teste de fila cheia e teste de fila vazia.Assim como na implementação da pilha precisamos de alguma formade identificar o topo, na fila iremos necessitar de alguma maneira deidentificar o seuinicio e seu o fim .

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    42/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 40

    Figura 8: Inserções e remoções em um TAD Fila.

    O diagrama da Figura 8 ilustra uma fila com capacidade para cincoelementos implementada em uma estrutura semelhante a um vetor. Odigrama também ilustra a inserção de cinco elementos (M1..M5) eduas operações de remoção. Note que os valores de início e fim sãousados para armazenar as posições atuais do início e do fim da fila.Inicialmente o valor de início está em zero. Podemos usar essacondição para detectarmos se a fila está vazia. Quando o elemento M1é inserido, este é colocado na posição 1 e o início e o fim sãoatualizados, ambos para 1. À medida que outros elementos sãoinseridos, o fim é atualizado. Quando o fim chega a 5, temos que a filanão comporta mais nenhuma inserção, isto é , a fila está cheia. Assim, podemos usar essa condição para detectarmos se a fila está cheia ouvazia.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    43/136

    Técnicas de Programação Avançada

    Página 41Centro Federal de Educação Tecnológica do Espírito Santo

    À medida que as remoções ocorrem, o inicio da fila é atualizado, deforma a identificar sempre o elemento a ser removido. Um problemadessa implementação é que uma vez que fim atingiu o valor máximo(5 neste caso), não são possíveis mais inserções, mesmo havendo

    outros espaços. Isso é ruim, pois torna a fila muito limitada. Paracontornarmos esse problema veremos duas implementaçõesdiferentes:Remoção com deslocamento e Fila circular. Na remoçãocom deslocamento, à medida que os elementos são removidos, oselementos remanescentes são deslocados para o início do arranjo.

    Figura 9: Implementação com Deslocamento.

    A Figura 9 mostra a implementação com deslocamento. Note que,nessa implementação, após a remoção de todos os elementos, o valorde início permaneceu com 1 e o valor de fim passou a ser zero. Assim,a condição de fila vazia não pode ser verificada pelo teste de início =0. Um possível teste é fim = 0 ou fim menor que início. A seguirvamos ver uma implementação em C usando arranjos para essa fila.Posteriormente veremos a implementação utilizando fila circular.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    44/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 42

    Atividades

    Ordenar uma fila utilizando 2 pilhas como variáveisauxiliares. Ao final da ordenação o elemento no início dafila deve ser menor que o segundo da fila e assimsucessivamente. A ordenação deve ser feita apenas emtermos das operaçõesinsere , remove , filaVazia ,empilha , desempilha e pilhaVazia . A funçãodeve ter a seguinte organização:voi d or dena_2p ( Fi l a* f ) {

    Pi l ha p1, p2;. . .

    }

    2.2.2 Implementação de Filas em arranjos comdeslocamento

    De forma similar à da implementação de Pilha iremos definir ummódulo em C para implementação da Fila. Na Figura 10 temos adefinição da interface (arquivo filaecd.h) do TAD Fila.

    Figura 10: Interface do TAD Fila.

    A Figura 11 apresenta o arquivo filaecd.c, contendo a implementaçãodas operações da Fila com deslocamento na remoção.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    45/136

    Técnicas de Programação Avançada

    Página 43Centro Federal de Educação Tecnológica do Espírito Santo

    Figura 11: Implementação do TAD Fila Com deslocamento.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    46/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 44

    O código está comentado e pretende ser auto-explicativo. A operaçãoinsereNaFila insere os elementos passados como parâmetro(elem). Para inserir na fila, inicialmente o valor defim éincrementado, visto que este foi inicializado com valor –1. Dessaforma a primeira inserção insere na posição 0 do vetor, a segunda na posição 1 e assim sucessivamente. A operação mais complexa é aremoção. Para remover, inicialmente o elemento no início da fila é passado por referência por meio do parâmetro (elem *).Posteriomente os elementos remanescentes na Fila são deslocados deuma posição. Dessa forma o elemento do início da fila ocupanovamente a posição 0 do vetor.O código da Figura 12 (arquivo principal.c) permite testar a Fila.

    Figura 12: Módulo para teste do TAD Fila.A função testeFilaecd declara uma fila (q) inicializa a fila, insere osinteiros de 0 a 9 e depois remove os elementos e os imprime. Note quetodo o processamento é feito usando as operações do Tad Fila.

    Atividades

    4. Implementar as operações imprimir Fila para o TAD Filaimplementado anteriormente.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    47/136

    Técnicas de Programação Avançada

    Página 45Centro Federal de Educação Tecnológica do Espírito Santo

    2.2.3 Implementação de Filas com Arranjos circulares

    Analisando a implementação do TAD Fila da seçãoanterior podemos notar que, embora a fila estejacorretamente implementada, existe um problema deeficiência na remoção de um elemento. Estou mereferindo aos deslocamentos necessários para que aremoção seja feita e os espaços vagos no vetor possam ser reaproveitados. Veremos agora outramaneira de implementar o TAD Fila, em que essesdeslocamentos não são necessários. Essaimplementação chama-se Fila Circular.

    Função SucessorEm um arranjo simples, cujas posições vão de 0 a t, podemosidentificar facilmente qual o elemento que sucede uma determinada posição i. Por exemplo, se i =0, o sucessor de i = 1, se i=1 sucessor dei = 2. Ou seja, o sucessor de i = i+1, para i variando entre 0 e t-1. Nesse caso, não existe o sucessor de t.Agora, se definimos que o sucessor de t = 0, temos então que todos osíndices do arranjo possuem sucessor. A Figura 13 ilustra essa situação.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, afunção sucessor pode ser obtida elegantemente por meio da função:

    sucessor(i) = (i+1) mod n , onde mod é o operadorresto.Quando utilizamos essa função para avançarmos o índice de umarranjo para a próxima, dizemos que estamos usando um arranjocircular.

    TAD FILA baseado em Arranjo CircularCom um arranjo circular, é possível deslocar o início e o fim da fila por todo o vetor, sem correr o risco da perda de espaço e sem anecessidade de realocar os elementos da fila. Nessa implementação as

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    48/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 46

    operações de inserir e remover, bem como as condições de Fila Cheiae Fila vazia precisam ser baseadas na função sucessor. A Figura 14apresenta a lógica dessas operações, agora definida em termos dafunção sucessor.

    Figura 14: Especificação das operações de um TAD Fila Circular.

    A Figura 15 apresenta a implementação das operações. Note que não énecessário um novo arquivo header, pois este é o mesmo daimplementação do módulo filaecd. Esse fato ilustra um aspectoimportante da implementação de TADs: A implementação pode sermodificada sem necessidade de se alterar a interface. Outro aspecto daimplementação com arranjo circular, é que uma das posições doarranjo é perdida. Isso é necessário para diferenciar as condições deFila 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 sãoimportantes para o paciente: nome, idade, horário de chegada eenfermidade.2. Implemente também a operação imprimeFila para essa nova Fila.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    49/136

    Técnicas de Programação Avançada

    Página 47Centro Federal de Educação Tecnológica do Espírito Santo

    Figura 15: Implementação das operações de Fila em um arranjo Circular.

    2.3 IMPLEMENTAÇÃO DE TADS COM ALOCAÇÃODINÂMICA DE MEMÓRIA

    2.3.1 Revisão de Alocação Dinâmica de MemóriaO objetivo da alocação dinâmica de memória é utilizar espaços damemória de tamanho arbitrário. Em adição, a alocação dinâmica dememória permite criar estruturas de dados encadeadas. A alocação deespaço sob demanda é utilizada quando o espaço de memórianecessário para um conjunto de dados varia durante a execução do programa. Já o encadeamento provê um estilo eficiente de representarconjuntos de dados em C e de implementar as estruturas dearmazenamento de Tipos Abstratos de Dados.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    50/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 48

    A alocação dinâmica de memória necessita de suporte da Linguagemde Programação. Em C, esse suporte é fornecido por um conjunto defunções disponíveis na biblioteca alloc . As principais funções dessa biblioteca são a função malloc , que aloca um espaço na memória e

    retorna um ponteiro para o espaço alocado e a funçãofree , quelibera espaços de memória alocados por meio da função malloc .

    Exemplo de uso de alocação de espaço sob demandaUma das vantagens da alocação dinâmica é permitir a alocação deespaço de acordo com a necessidade. Por exemplo, suponha que um programa necessite de um arranjo para guardar N números inteiros.Usando alocação estática de memória, como não sabemos aquantidade precisa de números, devemos fazer uma estimativa dovalor máximo de número e declarar o vetor com base nessa estimativa.A funçãoalocEstatica da Figura 16 ilustra esta situação.

    Figura 16: Alocação Estática de memória.

    Note que o valor lido para n pode variar de 1 a 100. Quanto menor ovalor de n, maior o desperdício de espaço alocado.Usando alocação dinâmica teremos o valor de n que, lido, pode serusado como parâmetro da chamada da função malloc, para alocar umconjunto de n inteiros, ou seja, um vetor de n inteiros. A funçãoalocDinamica na Figura 17 é idêntica em termos defuncionalidade à funçãoalocEstatica . Contudo, esta utilizaalocação dinâmica.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    51/136

    Técnicas de Programação Avançada

    Página 49Centro Federal de Educação Tecnológica do Espírito Santo

    Figura 17: Vetor com Alocação dinâmica.

    Note que na alocação dinâmica não há limites para n, e este poderáassumir, em teoria, qualquer valor maior que zero(n>0). A função

    malloc possui apenas um parâmetro formal: o número de bytes aserem alocados. Normalmente esse número de bytes é determinadomultiplicando o tamanho em bytes do tipo base a ser alocado pelonúmero de elementos. No exemplo, o tipo base é oint. Foi usada amacro sizeof para determinar o tamanho exato do tipoint , que pode variar entre diferentes máquinas, sistemas operacionais elinguagens. Qualquer tipo pode ser utilizado como parâmetro desizeof , inclusive tipos definidos pelo usuário.

    Listas Simplesmente EncadeadasUma outra finalidade do uso de alocação dinâmica e apontadores é permitir a implementação de estruturas encadeadas utilizandoestruturas auto referenciadas.Uma estrutura auto referenciada possui, dentro seus campos, um campo que pode referenciar estruturasidênticas a ela mesma. Portanto, uma estrutura auto referenciada pode

    apontar para outra estrutura do mesmo tipo que ela.O código na Figura 18 define um tipo Ponto que é auto referenciável.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    52/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 50

    Figura 18: Estrutura auto referenciada.

    O tipo Ponto definido pelotypedef é um tipo ponteiro para astruct ponto . Essa struct por sua vez, possui dentro dela oscampos x,y (coordenadas do ponto),cor (cor do ponto) e

    proximoPonto , que é uma variável do tipo ponteiro parastruct ponto . A variável proximoPonto é que permite que uma variável

    do tipostruct ponto possa se ligar (apontar) a outra estrutura dotipostruct ponto .

    Figura 19: A struct ponto.

    Lista simplesmente EncadeadaA estrutura de dados encadeada mais simples que temosé a lista simplesmente encadeada. Uma listasimplesmente encadeada é um agregado de elementosde um mesmo tipo, em que cada elemento é armazenadoem um espaço alocado dinamicamente. À medida queelementos são inseridos na lista, esses espaços sãocriados e vão sendo encadeados de forma que:- O endereço do primeiro ou do último elemento da listaé mantido em uma variável do tipo ponteiro;- Os demais elementos são acessados a partir do seuinício ou do seu fim. Isto é possível porque cada nododa lista possui um campo que aponta para o próximoelemento da lista.

    A struct ponto pode servir para implementarmos uma lista.Visualmente, uma lista encadeada de pontos pode ser ilustrada pelaFigura 20 a seguir:

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    53/136

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    54/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 52

    Figura 22: Interface do TAD Elemento.

    Figura 23: Interface do TAD Lista.

    A implementação da operaçãoinicializaLista (Figura 24)consiste em atribuir o valor NULL a Lista passada por referência.Segue essa implementação:

    Figura 24: Implementação da operação inicializaLista. A implementação da inserção (Figura 25) segue exatamente o mesmo procedimento usado no exemplo da lista de pontos.

    Figura 25: Implementação da operação insereNaLista.

    A operação de remoção visa remover um elemento da lista tendo sidoinformado o código do elemento. Esse procedimento deve tambémretornar o elemento a ser removido. A remoção deve usar a funçãofree para liberar o espaço alocado pelo nodo removido. Além disso,deve ser também preservado o encadeamento da lista. De acordo comesses objetivos temos que realizar uma pesquisa na lista com oobjetivo de encontrar o nodo a ser eliminado. Como resultado dessa pesquisa existem duas possibilidades:

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    55/136

    Técnicas de Programação Avançada

    Página 53Centro Federal de Educação Tecnológica do Espírito Santo

    * O elemento está na lista. A pesquisa pára quando encontrar oelemento.* O elemento não está na lista. A pesquisa chega até o fim da lista(NULL).Formulamos então o algoritmo recursivo apresentado na Figura 26.

    Figura 26: algoritmo para remoção de um elemento na Lista. A Figura 27 apresenta uma implementação para a operação deremoção baseada no algoritmo da Figura 26.

    Figura 27: Implementação da operação removeDaLista. A operação pesquisaNaLista visa retornar um elemento cujocódigo é passado como parâmetro. Essa pesquisa é feita por meio deum loop, que percorre a lista até encontrar o elemento ou chagar aoseu final. Temos novamente duas situações: busca com sucesso ou busca sem sucesso. Na Figura 28, temos a implementação destaoperação.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    56/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 54

    Figura 28: Implementação da operação pesquisaNaLista. A Figura 30 apresenta a implementação da operaçãoimprimeLista , que utiliza a operaçãoimprimeElemento doTAD elemento (Figura 29). A operaçãoimprimeLista deve percorrer a lista até o final imprimindo o conteúdo de seus elementos.Seguem as implementações das operaçõesimprimeElemento arquivo elemento.c) eimprimeLista (arquivo tadLista.c). Aoperação imprimeLista é recursiva. A cada chamada darecursividade, é passado um apontador para o próximo elemento dalista. A condição de parada da recusividade é chegar ao final da Lista(NULL).

    Figura 29: Implementação da operação imprimeElemento do TAD Elemento.

    Figura 30: Implementação da operação imprimeLista.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    57/136

    Técnicas de Programação Avançada

    Página 55Centro Federal de Educação Tecnológica do Espírito Santo

    Atividades

    1. Implementar uma operação para o TAD Listaque insira os elementos no seu final.

    2. Implementar uma operação para otadLista que transforme a lista em uma lista ordenada.Essa operação deve inserir os elementos demodo que a lista permaneça sempre em ordemcrescente a partir de seu inicio. A chave deordenação a ser utilizada deve ser o código doelemento.

    2.3.2 Implementação do TAD PilhaA implementação do TAD Pilha com alocação dinâmica de memória possui como vantagem principal o fato de podermos considerar a suacapacidade de armazenamento como sendo infinita. Ou seja, usandoalocação dinâmica não precisamos testar se a Pilha está cheia parafazer um empilhamento. Outra vantagem está na simplicidade daimplementação. O quadro abaixo ilustra a definição do tipo Pilhacomo uma estrutura dinâmica encadeada. Podemos afirmar que uma pilha é uma lista onde os elementos são inseridos noinício eremovidos doinício . Para efeitos de implementação da pilha,

    chamamos oinício de topo. A Figura 31 apresenta o arquivo de interface TadPilhaAD.h com adefinição da estrutura de dados Pilha e das operações. Notenovamente que as operações são as mesmas apresentadas no móduloPilha.h visto anteriormente.

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    58/136

    Técnicas de Programação Avançada

    Centro Federal de Educação Tecnológica do Espírito SantoPágina 56

    Figura 31: Interface do TAD Pilha com alocação dinâmica

    Para a definição da Pilha dinâmica, é definido o tipo Nodo que é umtipo ponteiro para struct nodo (em minúsculo). Pilha é uma estruturaque contém apenas uma variável: o topo. Esse topo, por sua vez, é do

    tipo Nodo.Uma variável do tipo Pilha é uma variável estática. Essa variável éuma estrutura contendo como único campo o topo . O topo, por suavez, é que é um apontador.Pilha p;

    p.topo=NULL;

    Figura 32: Representação do da estrutura de dados dinâmica Pilha.

    Topo é uma variável do tipo ponteiro parastruct nodo . Assimtopo pôde ser inicializado com NULL. Essa condição pode serutilizada para detectarmos se a Pilha está vazia. A Figura 33 apresentaas operações inicializaPilha e pilhaVazia seguindo exatamente essasdecisões de implementação.

    p

    NULLtopo

  • 8/17/2019 Cursos de Tecnologia em Analise de Desenvolvimento de Sistemas - Tecnicas de Programação Avançada.pdf

    59/136

    Técnicas de Programação Avançada

    Página 57Centro Federal de Educação Tecnológica do Espírito Santo

    Figura 33: Implementação das operações inicializaPilha e pilhaVazia.

    A operação 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, após inserirmos o primeiro eleme