Вы находитесь на странице: 1из 10

Apresentao

A disciplina de Estruturas de Dados (ED) est sendo ministrada em sua nova verso desde o segundo semestre de 1998. Trata-se da segunda disciplina de informtica oferecida no curso de Engenharia da PUC-Rio. Na primeira disciplina, Introduo Cincia da Computao (ICC), so apresentados os conceitos fundamentais de programao. ICC, em sua verso mais nova, utiliza a linguagem Scheme, de fcil aprendizado, o que permite a discusso de diversos conceitos de programao num curso introdutrio. Isso acontece porque Scheme, como a linguagem LISP da qual descende, uma linguagem funcional, baseada em conceitos familiares aos alunos, como a definio de funes e sua aplicao em expresses que devem ser avaliadas. O enfoque do curso de Estruturas de Dados diferente. Discutem-se tcnicas de programao e estruturao de dados para o desenvolvimento de programas eficientes. Adota-se a linguagem de programao C. Apesar de reconhecermos as dificuldades na aprendizagem da linguagem C, optamos por sua utilizao neste curso simplesmente porque C a linguagem bsica da programao do UNIX, da Internet, do Windows, do Linux. Alm de C, usam-se nestes sistemas e em aplicaes desenvolvidas para eles linguagens derivadas de C, como C++ e Java. Um ponto adicional a favor da escolha de C que o estudo de vrias disciplinas posteriores a ED ser facilitado se os alunos j puderem programar com desenvoltura nessa linguagem. Este curso foi idealizado e montado pelo Prof. Jos Lucas Rangel. Neste semestre, estamos reformulando alguns tpicos, criando outros e alterando a ordem de apresentao. Esta apostila foi reescrita tendo como base a apostila do Prof. Rangel, utilizada nos semestres anteriores. O curso est dividido em trs partes. A Parte I apresenta os conceitos fundamentais da linguagem C e discute formas simples de estruturao de dados; a Parte II discute as estruturas de listas e rvores, e suas aplicaes; e a Parte III discute algoritmos e estruturas de dados para ordenao e busca. A apostila apresenta todos os tpicos que sero discutidos em sala de aula, mas recomendamos fortemente que outras fontes (livros, notas de aula, etc.) sejam consultadas. Rio de Janeiro, 19 de fevereiro de 2002 Waldemar Celes

1. Conceitos fundamentais
W. Celes e J. L. Rangel

1.1. Introduo
O curso de Estruturas de Dados discute diversas tcnicas de programao, apresentando as estruturas de dados bsicas utilizadas no desenvolvimento de software. O curso tambm introduz os conceitos bsicos da linguagem de programao C, que utilizada para a implementao das estruturas de dados apresentadas. A linguagem de programao C tem sido amplamente utilizada na elaborao de programas e sistemas nas diversas reas em que a informtica atua, e seu aprendizado tornou-se indispensvel tanto para programadores profissionais como para programadores que atuam na rea de pesquisa. O conhecimento de linguagens de programao por si s no capacita programadores necessrio saber us-las de maneira eficiente. O projeto de um programa engloba a fase de identificao das propriedades dos dados e caractersticas funcionais. Uma representao adequada dos dados, tendo em vista as funcionalidades que devem ser atendidas, constitui uma etapa fundamental para a obteno de programas eficientes e confiveis. A linguagem C, assim como as linguagens Fortran e Pascal, so ditas linguagens convencionais, projetadas a partir dos elementos fundamentais da arquitetura de von Neuman, que serve como base para praticamente todos os computadores em uso. Para programar em uma linguagem convencional, precisamos de alguma maneira especificar as reas de memria em que os dados com que queremos trabalhar esto armazenados e, freqentemente, considerar os endereos de memria em que os dados se situam, o que faz com que o processo de programao envolva detalhes adicionais, que podem ser ignorados quando se programa em uma linguagem como Scheme. Em compensao, temos um maior controle da mquina quando utilizamos uma linguagem convencional, e podemos fazer programas melhores, ou seja, menores e mais rpidos. A linguagem C prov as construes fundamentais de fluxo de controle necessrias para programas bem estruturados: agrupamentos de comandos; tomadas de deciso (if-else); laos com testes de encerramento no incio (while, for) ou no fim (do-while); e seleo de um dentre um conjunto de possveis casos (switch). C oferece ainda acesso a apontadores e a habilidade de fazer aritmtica com endereos. Por outro lado, a linguagem C no prov operaes para manipular diretamente objetos compostos, tais como cadeias de caracteres, nem facilidades de entrada e sada: no h comandos READ e WRITE. Todos esses mecanismos devem ser fornecidos por funes explicitamente chamadas. Embora a falta de algumas dessas facilidades possa parecer uma deficincia grave (deve-se, por exemplo, chamar uma funo para comparar duas cadeias de caracteres), a manuteno da linguagem em termos modestos tem trazido benefcios reais. C uma linguagem relativamente pequena e, no entanto, tornou-se altamente poderosa e eficiente.

1.2. Modelo de um computador


Existem diversos tipos de computadores. Embora no seja nosso objetivo estudar hardware, identificamos, nesta seo, os elementos essenciais de um computador. O
Estruturas de Dados PUC-Rio 1-1

conhecimento da existncia destes elementos nos ajudar a compreender como um programa de computador funciona.
Canal de comunicao (BUS)

CPU
Central de processamento Armazenamento secundrio Dispositivos de entrada/sada

Memria

Figura 1.1: Elementos bsicos de um computador tpico.

A Figura 1.1 identifica os elementos bsicos de um computador tpico. O canal de comunicao (conhecido como BUS) representa o meio para a transferncia de dados entre os diversos componentes. Na memria principal so armazenados os programas e os dados no computador. Ela tem acesso randmico, o que significa que podemos enderear (isto , acessar) diretamente qualquer posio da memria. Esta memria no permanente e, para um programa, os dados so armazenados enquanto o programa est sendo executado. Em geral, aps o trmino do programa, a rea ocupada na memria fica disponvel para ser usada por outras aplicaes. A rea de armazenamento secundrio , em geral, representada por um disco (disco rgido, disquete, etc.). Esta memria secundria tem a vantagem de ser permanente. Os dados armazenados em disco permanecem vlidos aps o trmino dos programas. Esta memria tem um custo mais baixo do que a memria principal, porm o acesso aos dados bem mais lento. Por fim, encontram-se os dispositivos de entrada e sada. Os dispositivos de entrada (por exemplo, teclado, mouse) permitem passarmos dados para um programa, enquanto os dispositivos de sada permitem que um programa exporte seus resultados, por exemplo em forma textual ou grfica usando monitores ou impressoras. Armazenamento de dados e programas na memria A memria do computador dividida em unidades de armazenamento chamadas bytes. Cada byte composto por 8 bits, que podem armazenar os valores zero ou um. Nada alm de zeros e uns pode ser armazenado na memria do computador. Por esta razo, todas as informaes (programas, textos, imagens, etc.) so armazenadas usando uma codificao numrica na forma binria. Na representao binria, os nmeros so representados por uma seqncia de zeros e uns (no nosso dia a dia, usamos a representao decimal, uma vez que trabalhamos com 10 algarismos). Por exemplo, o nmero decimal 5 representado por 101, pois 1*22 + 0*21 + 1*20 igual a 5 (da mesma forma que, na base decimal, 456=4*102 + 5*101 + 6*100). Cada posio da memria (byte) tem um endereo nico. No possvel enderear diretamente um bit. Se s podemos armazenar nmeros na memria do computador, como fazemos para armazenar um texto (um documento ou uma mensagem)? Para ser possvel armazenar uma seqncia de caracteres, que representa o texto, atribui-se a cada caractere um cdigo
Estruturas de Dados PUC-Rio 1-2

numrico (por exemplo, pode-se associar ao caractere 'A' o cdigo 65, ao caractere 'B' o cdigo 66, e assim por diante). Se todos os caracteres tiverem cdigos associados (inclusive os caracteres de pontuao e de formatao), podemos armazenar um texto na memria do computador como uma seqncia de cdigos numricos. Um computador s pode executar programas em linguagens de mquina. Cada programa executvel uma seqncia de instrues que o processador central interpreta, executando as operaes correspondentes. Esta seqncia de instrues tambm representada como uma seqncia de cdigos numricos. Os programas ficam armazenados em disco e, para serem executados pelo computador, devem ser carregados (transferidos) para a memria principal. Uma vez na memria, o computador executa a seqncia de operaes correspondente.

1.3. Interpretao versus Compilao


Uma diferena importante entre as linguagens C e Scheme que, via de regra, elas so implementadas de forma bastante diferente. Normalmente, Scheme interpretada e C compilada. Para entender a diferena entre essas duas formas de implementao, necessrio lembrar que os computadores s executam realmente programas em sua linguagem de mquina, que especfica para cada modelo (ou famlia de modelos) de computador. Ou seja, em qualquer computador, programas em C ou em Scheme no podem ser executados em sua forma original; apenas programas na linguagem de mquina ( qual vamos nos referir como M) podem ser efetivamente executados. No caso da interpretao de Scheme, um programa interpretador (IM), escrito em M, l o programa PS escrito em Scheme e simula cada uma de suas instrues, modificando os dados do programa da forma apropriada. No caso da compilao da linguagem C, um programa compilador (CM), escrito em M, l o programa PC, escrito em C, e traduz cada uma de suas instrues para M, escrevendo um programa PM cujo efeito o desejado. Como conseqncia deste processo, PM, por ser um programa escrito em M, pode ser executado em qualquer mquina com a mesma linguagem de mquina M, mesmo que esta mquina no possua um compilador. Na prtica, o programa fonte e o programa objeto so armazenados em arquivos em disco, aos quais nos referimos como arquivo fonte e arquivo objeto. As duas figuras a seguir esquematizam as duas formas bsicas de implementao de linguagens de programao.
Execuo PS Programa Fonte

IM Interpretador

Sada

Dados de Entrada

Figura 1.2: Execuo de programas com linguagem interpretada.

Estruturas de Dados PUC-Rio

1-3

Compilao PC Programa Fonte PM Programa Objeto

CM Compilador

Execuo Dados de Entrada PM Programa Objeto

Sada

Figura 1.3: Execuo de programas com linguagem compilada.

Devemos notar que, na Figura 1.2, o programa fonte um dado de entrada a mais para o interpretador. No caso da compilao, Figura 1.3, identificamos duas fases: na primeira, o programa objeto a sada do programa compilador e, na segunda, o programa objeto executado, recebendo os dados de entrada e gerando a sada correspondente. Observamos que, embora seja comum termos linguagens funcionais implementadas por interpretao e linguagens convencionais por compilao, h excees, no existindo nenhum impedimento conceitual para implementar qualquer linguagem por qualquer dos dois mtodos, ou at por uma combinao de ambos. O termo mquina usado acima intencionalmente vago. Por exemplo, computadores idnticos com sistemas operacionais diferentes devem ser considerados mquinas, ou plataformas, diferentes. Assim, um programa em C, que foi compilado em um PC com Windows, no dever ser executado em um PC com Linux, e vice-versa.

1.4. Exemplo de cdigo em C


Para exemplificar cdigos escritos em C, consideremos um programa que tem a finalidade de converter valores de temperatura dados em Celsius para Fahrenheit. Este programa define uma funo principal que captura um valor de temperatura em Celsius, fornecido via teclado pelo usurio, e exibe como sada a temperatura correspondente em Fahrenheit. Para fazer a converso, utilizada uma funo auxiliar. O cdigo C deste programa exemplo mostrado abaixo.
/* Programa para converso de temperatura */ #include <stdio.h> float converte (float c) { float f; f = 1.8*c + 32; return f; }

Estruturas de Dados PUC-Rio

1-4

int main (void) { float t1; float t2; /* mostra mensagem para usuario */ printf("Digite a temperatura em Celsius: "); /* captura valor entrado via teclado */ scanf("%f",&t1); /* faz a conversao */ t2 = converte(t1); /* exibe resultado */ printf("A temperatura em Fahrenheit : %f\n", t2); return 0; }

Um programa em C, em geral, constitudo de diversas pequenas funes, que so independentes entre si no podemos, por exemplo, definir uma funo dentro de outra. Dois tipos de ambientes so caracterizados em um cdigo C. O ambiente global, externo s funes, e os ambientes locais, definidos pelas diversas funes (lembrando que os ambientes locais so independentes entre si). Podem-se inserir comentrios no cdigo fonte, iniciados com /* e finalizados com */, conforme ilustrado acima. Devemos notar tambm que comandos e declaraes em C so terminados pelo caractere ponto-e-vrgula (;). Um programa em C tem que, obrigatoriamente, conter a funo principal (main). A execuo de um programa comea pela funo principal (a funo main automaticamente chamada quando o programa carregado para a memria). As funes auxiliares so chamadas, direta ou indiretamente, a partir da funo principal. Em C, como nas demais linguagens convencionais, devemos reservar rea de memria para armazenar cada dado. Isto feito atravs da declarao de variveis, na qual informamos o tipo do dado que iremos armazenar naquela posio de memria. Assim, a declarao float t1;, do cdigo mostrado, reserva um espao de memria para armazenarmos um valor real (ponto flutuante float). Este espao de memria referenciado atravs do smbolo t1. Uma caracterstica fundamental da linguagem C diz respeito ao tempo de vida e visibilidade das variveis. Uma varivel (local) declarada dentro de uma funo "vive" enquanto esta funo est sendo executada, e nenhuma outra funo tem acesso direto a esta varivel. Outra caracterstica das variveis locais que devem sempre ser explicitamente inicializadas antes de seu uso, caso contrrio contero lixo, isto , valores indefinidos. Como alternativa, possvel definir variveis que sejam externas s funes, isto , variveis globais, que podem ser acessadas pelo nome por qualquer funo subseqente
Estruturas de Dados PUC-Rio 1-5

(so visveis em todas as funes que se seguem sua definio). Alm do mais, devido s variveis externas (ou globais) existirem permanentemente (pelo menos enquanto o programa estiver sendo executado), elas retm seus valores mesmo quando as funes que as acessam deixam de existir. Embora seja possvel definir variveis globais em qualquer parte do ambiente global (entre quaisquer funes), prtica comum defini-las no incio do arquivo-fonte. Como regra geral, por razes de clareza e estruturao adequada do cdigo, devemos evitar o uso indisciplinado de variveis globais e resolver os problemas fazendo uso de variveis locais sempre que possvel. No prximo captulo, discutiremos variveis com mais detalhe.

1.5. Compilao de programas em C


Para desenvolvermos programas em uma linguagem como C, precisamos de, no mnimo, um editor e um compilador. Estes programas tm finalidades bem definidas: com o editor de textos, escrevemos os programas fontes, que so salvos em arquivos1; com o compilador, transformamos os programas fontes em programas objetos, em linguagem de mquina, para poderem ser executados. Os programas fontes so, em geral, armazenados em arquivos cujo nome tem a extenso .c. Os programas executveis possuem extenses que variam com o sistema operacional: no Windows, tm extenso .exe; no Unix (Linux), em geral, no tm extenso. Para exemplificar o ciclo de desenvolvimento de um programa simples, consideremos que o cdigo apresentado na seo anterior tenha sido salvo num arquivo com o nome prog.c. Devemos ento compilar o programa para gerarmos um executvel. Para ilustrar este processo, usaremos o compilador gcc. Na linha de comando do sistema operacional, fazemos:
> gcc o prog prog.c

Se no houver erro de compilao no nosso cdigo, este comando gera o executvel com o nome prog (prog.exe, no Windows). Podemos ento executar o programa:
> prog Digite a temperatura em Celsius: 10 A temperatura em Fahrenheit vale: 50.000000 >

Em itlico, representamos as mensagens do programa e, em negrito, exemplificamos um dado fornecido pelo usurio via teclado. Programas com vrios arquivos fontes Os programas reais so, naturalmente, maiores. Nestes casos, subdividimos o fonte do programa em vrios arquivos. Para exemplificar a criao de um programa com dois arquivos, vamos considerar que o programa para converso de unidades de temperatura
1

Podemos utilizar qualquer editor de texto para escrever os programas fontes, exceto editores que incluem caracteres de formatao (como o Word do Windows, por exemplo).

Estruturas de Dados PUC-Rio

1-6

apresentado anteriormente seja dividido em dois fontes: o arquivo converte.c e o arquivo principal.c. Teramos que criar dois arquivos, como ilustrado abaixo: Arquivo converte.c:
/* Implementao do mdulo de converso */ float converte (float c) { float f; f = 1.8*c + 32; return f; }

Arquivo principal.c:
/* Programa para converso de temperatura */ #include <stdio.h> float converte (float c); int main (void) { float t1; float t2; /* mostra mensagem para usuario */ printf("Entre com temperatura em Celsius: "); /* captura valor entrado via teclado */ scanf("%f",&t1); /* faz a conversao */ t2 = converte(t1); /* exibe resultado */ printf("A temperatura em Fahrenheit vale: %f\n", t2); return 0; }

Embora o entendimento completo desta organizao de cdigo no fique claro agora, interessa-nos apenas mostrar como geramos um executvel de um programa com vrios arquivos fontes. Uma alternativa compilar tudo junto e gerar o executvel como anteriormente:
> gcc o prog converte.c principal.c

No entanto, esta no a melhor estratgia, pois se alterarmos a implementao de um determinado mdulo no precisaramos re-compilar os outros. Uma forma mais eficiente compilarmos os mdulos separadamente e depois ligar os diversos mdulos objetos gerados para criar um executvel.
> gcc c converte.c > gcc c principal.c > gcc o prog converte.o principal.o

Estruturas de Dados PUC-Rio

1-7

A opo c do compilador gcc indica que no queremos criar um executvel, apenas gerar o arquivo objeto (com extenso .o ou .obj). Depois, invocamos gcc para fazer a ligao dos objetos, gerando o executvel.

1.6. Ciclo de desenvolvimento


Programas como editores, compiladores e ligadores so s vezes chamados de ferramentas, usadas na Engenharia de Software. Exceto no caso de programas muito pequenos (como o caso de nosso exemplo), raro que um programa seja composto de um nico arquivo fonte. Normalmente, para facilitar o projeto, os programas so divididos em vrios arquivos. Como vimos, cada um desses arquivos pode ser compilado em separado, mas para sua execuo necessrio reunir os cdigos de todos eles, sem esquecer das bibliotecas necessrias, e esta a funo do ligador. A tarefa das bibliotecas permitir que funes de interesse geral estejam disponveis com facilidade. Nosso exemplo usa a biblioteca de entrada/sada padro do C, stdio, que oferece funes que permitem a captura de dados a partir do teclado e a sada de dados para a tela. Alm de bibliotecas preparadas pelo fornecedor do compilador, ou por outros fornecedores de software, podemos ter bibliotecas preparadas por um usurio qualquer, que pode empacotar funes com utilidades relacionadas em uma biblioteca e, dessa maneira, facilitar seu uso em outros programas. Em alguns casos, a funo do ligador executada pelo prprio compilador. Por exemplo, quando compilamos o primeiro programa prog.c, o ligador foi chamado automaticamente para reunir o cdigo do programa aos cdigos de scanf, printf e de outras funes necessrias execuo independente do programa. Verificao e Validao Outro ponto que deve ser observado que os programas podem conter (e, em geral, contm) erros, que precisam ser identificados e corrigidos. Quase sempre a verificao realizada por meio de testes, executando o programa a ser testado com diferentes valores de entrada. Identificado um ou mais erros, o cdigo fonte corrigido e deve ser novamente verificado. O processo de compilao, ligao e teste se repete at que os resultados dos testes sejam satisfatrios e o programa seja considerado validado. Podemos descrever o ciclo atravs da Figura 1.4.

Editar

Compilar

Ligar

Testar

Figura 1.4: Ciclo de desenvolvimento.

Estruturas de Dados PUC-Rio

1-8

Este ciclo pode ser realizado usando programas (editor, compilador, ligador) separados ou empregando um ambiente integrado de desenvolvimento (integrated development environment, ou IDE). IDE um programa que oferece janelas para a edio de programas e facilidades para abrir, fechar e salvar arquivos e para compilar, ligar e executar programas. Se um IDE estiver disponvel, possvel criar e testar um programa, tudo em um mesmo ambiente, e todo o ciclo mencionado acima acontece de maneira mais confortvel dentro de um mesmo ambiente, de preferncia com uma interface amigvel.

Estruturas de Dados PUC-Rio

1-9