1 Estrutura de Seleção e de Repetição, Vetor e …profcarloslucas.com.br/pdf/ESTRUTURA DE...

25
1 1 Estrutura de Seleção e de Repetição, Vetor e Matriz O que é Estrutura de Dados? Em diversos contextos, disciplinas associadas à programação recebem a denominação de pro- cessamento de dados''. Esta denominação não é gratuita -- de fato, embora seja possível criar procedimentos que não manipulem nenhum dado, tais procedimentos seriam de pouco valor prático. Uma vez que procedimentos são, efetivamente, processadores de dados, a eficiência de um procedimento está muito associada à forma como seus dados são organizados. Estrutura de dados é o ramo da computação que estuda os diversos mecanismos de organização de dados para atender aos diferentes requisitos de processamento. As estruturas de dados definem a organização, métodos de acesso e opções de processamen- to para a informação manipulada pelo programa. A definição da organização interna de uma estrutura de dados é tarefa do projetista da estrutura, que define também qual a API (Applicati- on Programming Interface) para a estrutura, ou seja, qual o conjunto de procedimentos que podem ser usados para manipular os dados na estrutura. É esta API que determina a visão funcional da estrutura de dados, que é a única informação relevante para um programador que vá utilizar uma estrutura de dados pré-definida. O que é Estrutura de Seleção? Em ciência da computação, uma estrutura de seleção (expressão condicional ou ainda construção condicional) é uma estrutura de desvio do fluxo de controle presente em linguagens de programação que realiza diferentes computações ou ações dependendo se a seleção (ou condição) é verdadeira ou falsa, em que a expressão é processada e transformada em um valor booleano. Seleção simples e composta A condição "se-então(-senão)" é uma estrutura de seleção comum em diversas linguagens de programação. Sua estrutura básica é a seguinte: Se (condição) Então (bloco de código) Senão (bloco de código) Fim Se Quando o interpretador encontra o identificador "Se", ele espera em seguida uma condição booleana sob forma de expressão relacional (como por exemplo, "x > 0"), que pode ser ver verdadeira ou falsa. Se a condição é verdadeira, o bloco de código seguido de "Então" é executado. Caso a condição seja falsa, o bloco de código seguido de "Senão" é executado. Em ambos os casos, após a execução do bloco de código, o fluxo do programa é retornado para o ponto indicado por "Fim Se". Note que a parte do "Senão" é opcional e pode ser omitida. Caso omitida, a estrutura é chamada de seleção simples; caso contrário é chamada seleção composta. A estrutura "Senão Se" é formada pela composição de estruturas de seleção, e um exemplo de sua estrutura é o seguinte: Se (condição) Então (bloco de código) Senão

Transcript of 1 Estrutura de Seleção e de Repetição, Vetor e …profcarloslucas.com.br/pdf/ESTRUTURA DE...

1

1 Estrutura de Seleção e de Repetição, Vetor e Matriz O que é Estrutura de Dados? Em diversos contextos, disciplinas associadas à programação recebem a denominação de pro-cessamento de dados''. Esta denominação não é gratuita -- de fato, embora seja possível criar procedimentos que não manipulem nenhum dado, tais procedimentos seriam de pouco valor prático.

Uma vez que procedimentos são, efetivamente, processadores de dados, a eficiência de um procedimento está muito associada à forma como seus dados são organizados. Estrutura de dados é o ramo da computação que estuda os diversos mecanismos de organização de dados para atender aos diferentes requisitos de processamento.

As estruturas de dados definem a organização, métodos de acesso e opções de processamen-to para a informação manipulada pelo programa. A definição da organização interna de uma estrutura de dados é tarefa do projetista da estrutura, que define também qual a API (Applicati-on Programming Interface) para a estrutura, ou seja, qual o conjunto de procedimentos que podem ser usados para manipular os dados na estrutura. É esta API que determina a visão funcional da estrutura de dados, que é a única informação relevante para um programador que vá utilizar uma estrutura de dados pré-definida.

O que é Estrutura de Seleção? Em ciência da computação, uma estrutura de seleção (expressão condicional ou ainda construção condicional) é uma estrutura de desvio do fluxo de controle presente em linguagens de programação que realiza diferentes computações ou ações dependendo se a seleção (ou condição) é verdadeira ou falsa, em que a expressão é processada e transformada em um valor booleano.

Seleção simples e composta

A condição "se-então(-senão)" é uma estrutura de seleção comum em diversas linguagens de programação. Sua estrutura básica é a seguinte:

Se (condição) Então (bloco de código)

Senão (bloco de código)

Fim Se

Quando o interpretador encontra o identificador "Se", ele espera em seguida uma condição booleana sob forma de expressão relacional (como por exemplo, "x > 0"), que pode ser ver verdadeira ou falsa. Se a condição é verdadeira, o bloco de código seguido de "Então" é executado. Caso a condição seja falsa, o bloco de código seguido de "Senão" é executado. Em ambos os casos, após a execução do bloco de código, o fluxo do programa é retornado para o ponto indicado por "Fim Se". Note que a parte do "Senão" é opcional e pode ser omitida. Caso omitida, a estrutura é chamada de seleção simples; caso contrário é chamada seleção composta.

A estrutura "Senão Se" é formada pela composição de estruturas de seleção, e um exemplo de sua estrutura é o seguinte:

Se (condição) Então (bloco de código)

Senão

2

Se (condição) Então (bloco de código)

Fim Se Fim Se

No exemplo acima, caso a primeira condição seja falsa, o fluxo do programa é desviado para o bloco de código do "Senão", onde há o processamento de outra estrutura de seleção.

Operador ternário

O operador ternário é uma estrutura de seleção composta presente em linguagens de programação derivadas de C, e sua estrutura básica é a seguinte:

(condição) ? (bloco de código do Então) : (bloco de código do Senão)

Seleção de múltipla escolha

A seleção de múltipla escolha compara um dado valor a constantes, desviando o fluxo de código para o ponto indicado pela primeira constante onde há casamento. Sua estrutura básica é:

Escolha X Caso V1: (bloco de código) Caso V2: (bloco de código) Caso V3, V4: (bloco de código) Caso V5...V10: (bloco de código) Caso contrário: (bloco de código) Fim Escolha

No exemplo acima, X é uma variável e os identificadores Vx são constantes. Essa sintaxe é genérica e muitas vezes não está disponível em algumas linguagens de programação. No primeiro e no segundo caso são feitos um casamento simples. No terceiro caso é feito um casamento com V3 ou V4. No quarto caso, é feito um casamento com valores entre V5 e V10: V5, V6, V7, V8, V9 e V10. No quinto e último caso é feito um casamento por defeito (que é opcional), isto é, um casamento que é usado caso nenhum outro seja feito.

O término de um bloco de código dentro de uma estrutura de múltipla escolha depende da implementação. Tipicamente, uma palavra reservada é usada no final do bloco. Quando encontrada, o fluxo de código é desviado para "Fim Escolha", terminando a estrutura. Caso a palavra não seja encontrada, várias linguagens de programação especificam que o fluxo de execução de código é continuado no próximo caso encontrado.

Casamento de padrões

O casamento de padrões é uma alternativa mais sofisticada para as estruturas tradicionais de seleção, sendo disponibilizada em algumas linguagens funcionais. Um exemplo é dado abaixo:

3

case fruta com | "maçã" -> (bloco de código) | "coco" -> (bloco de código) | "banana" -> (bloco de código)

Asserto

Um asserto é uma estrutura de seleção usada em programação que indica que o desenvolvedor asserta que a condição dada é sempre verdadeira. Sua estrutura básica é a seguinte:

Asserte (condição)

É uma estrutura usada para auxiliar a especificação de programas, e para indicar pré-requisitos de blocos de códigos. Por exemplo, uma pré-condição é um asserto adicionado no início de um bloco de código, e determina o conjunto de estados em que o código é esperado ser executado. Da mesma forma, uma pós-condição é um asserto adicionado no final de um bloco de código, determinando o conjunto de estados em que o código é esperado após ser executado (essa técnica é parte do paradigma de programação por contratos).

No uso prático, diversas linguagens de programação modernas oferecem essa estrutura, que é verificada em tempo de execução. Caso a condição seja falsa, a execução é abortada, facilitando a depuração de um sistema.

É muito comum termos situações em programação — assim como na nossa prática em geral — em que decidimos por um ou outro procedimento, de acordo com certas condições. Por e-xemplo, se eu digo...

SE estiver chovendo

ENTÃO leve um guarda-chuva

...isso significa que uma certa ação (levar o guarda-chuva) deverá ser tomada se a condição (estar chovendo) for verdadeira. Caso contrário, a ação não será feita.

4

Em alguns casos, especificamos também o que deverá ser feito caso a condição não se verifi-que...

SE a piscina estiver livre

ENTÃO faça natação

SENÃO faça uma caminhada.

Essas situações são muito comuns em programação, razão pela qual precisaremos recorrer aos comandos de seleção (ou de decisão). Veja os trechos de programa abaixo:

write(´Forneça a temperatura em celsius: ´); readln(Tc); Tf:= 9* Tc/5 + 32; { conversão para fahrenheit } Writeln(´Temperatura em Fahrenheit: ´, Tf); if Tf > 200 then write (´Atenção – temperatura muito elevada!!´); write(´Forneça dois números: ´); readln(N1,N2); if N1>N2 then writeln(´Maior: ´,N1) else writeln(´Maior: ´,N2);

No primeiro caso, uma temperatura (em celsius) é fornecida e, em seguida, calcula-se o valor correspondente na escala fahrenheit, mostrando-se o resultado obtido. Caso esta temperatura seja superior a 200oF, um sinal de alerta é exibido.

Temos então dois formatos para o comando de seleção:

if <Cond> then <Comando>/<Bloco>; if <Cond> then <Comando1>/<Bloco1> else <Comando1>/<Bloco1>;

Obs: na verdade, o primeiro formato, é um caso particular do segundo.

5

Formação de blocos

Há muitos casos em que, dependendo da condição ser verdadeira (ou falsa), queremos que sejam executados vários comandos. Isso se resolve em pascal de forma muito simples: em vez do comando, coloca-se um bloco, delimitado por begin .. end.

if <Cond> then begin <Comando1> <Comando2> <ComandoN> End Else Begin <ComandoN+1> <ComandoN+2> <ComandoM> end; Atenção:

Um erro comum para iniciantes na programação Pascal é incluir um ponto-e-vírgula (;) antes do else. Em nenhum caso — nem com comandos simples nem com blocos — isso pode ser feito (observe atentamente os formatos acima).

Já dentro dos blocos, os comandos devem ser finalizados por ponto-e-vírgula, normalmente. O ponto-e-vírgula antes de qualquer end de um programa Pascal é opcional.

Seleções aninhadas

Chamamos seleções aninhadas (ou concatenadas) as que ocorrem dentro de outra se-leção, seja no ramo do then, seja no ramo else. Como o comando de seleção é um comando como outro qualquer, ele pode ser inserido em outro, este outro em um terceiro, e assim su-cessivamente. Veja o exemplo abaixo :

write(´Forneça 2 números´); readln(A,B); if A>B then write(´Os números são iguais´) else if A > B then writeln(´Maior: ´,A) else writeln(´Maior: ´,B);

6

O que é Estrutura de Repetição?

Identificar a necessidade de utilizar uma estrutura de repetição para a resolução de um deter-minado problema. Diferenciar as diferentes estruturas de repetição existentes a aplicabilidade de cada estrutura para os diversos tipos de problemas Saber utilizar a estrutura de repetição PARA FAÇA cujo controle é realizado por um contador auto-incrementável Saber utilizar as estruturas de repetição ENQUANTO FAÇA e REPITA ATÉ cujo controle é realizado pelo usuá-rio. Identificar a necessidade de utilizar e saber resolver problemas que necessitem de estrutu-ras de repetição dentro de outras estruturas de repetição.

Uma das principais características que consolidaram o sucesso na utilização dos computado-res para a resolução de problemas foi a sua capacidade de repetir o processamento de um conjunto de operações para grandes quantidades de dados. Exemplos de conjuntos de tarefas que repetimos diversas vezes dentro de uma situação específica podem ser observados lar-gamente no nosso dia a dia.

As estruturas de repetição provém uma maneira de repetir um conjunto de procedimentos até que determinado objetivo seja atingido, quando a repetição se encerra. Todas as estruturas de repetição têm em comum o fato de haver uma condição de controle, expressa através de uma expressão lógica, que é testada em cada ciclo para determinar se a repetição prossegue ou não.

Por exemplo, consideremos que uma determinada loja de calçados efetue uma venda no cre-diário para um cliente que ainda não está registrado em seu sistema. Para realizar essa venda, é necessário cadastrar o cliente, solicitando informações básicas como: nome, endereço, CPF, RG, etc. Essas etapas para realizar o cadastro seguirão sempre a mesma ordem para cada novo cliente que aparecer na loja. Caso precisássemos desenvolver um sistema para efetuar os cadastros de clientes de uma loja, não haveria lógica que programássemos novamente es-sas etapas para cada cliente novo, bastaria que desenvolvêssemos uma única vez a seqüência de etapas e que a cada novo cliente usássemos a seqüência previamente definida.

As estruturas de repetição são basicamente três: enquanto-faça, faça-enquanto e para-faça. A diferença básica é que enquanto-faça primeiro testa a condição para depois realizar o bloco de comando, ao contrário de faça-enquanto que primeiro executa o bloco para depois realizar o

7

teste. A estrutura para-faça tem embutida um mecanismo de controle para determinar quando o laço deverá ser terminado.

As estruturas de repetição são representadas por três tipos de comandos: Repetição com teste no início, repetição com teste no final e repetição com variável de controle. Esses comandos podem realizar a repetição de ações (conjunto de comandos). Essas ações são executadas repetidamente enquanto uma determinada condição for satisfeita (verdadeira).

Repetição com Teste no Início

Neste tipo de repetição há uma condição logo no início, e, enquanto esta condição for satisfeita (verdadeira) o conjunto de ações limitadas pelo bloco da repetição é executa-do. Quando a condição for falsa o comando é abandonado prosseguindo para o próximo comando na sequência.

Diagrama Sintático:

1. Português estruturado

enquanto ( <expressão lógica> ) início C1; C2; . . . Cn; fim

A semântica deste comando é a seguinte:

• Quando a expressão lógica é encontrada, é testada. Se for falsa o comando seguinte ao bloco limitado por início e fim será executado. Se for verdadeira, os comandos C1, C1, ... , Cn serão executados. E o processo se repete até que o resultado da expressão lógica continue verdadeiro.

• Um ponto importante é que esse bloco de comandos pode não ser executado. Para que isso ocorra é necessário somente que a <expressão lógica> seja falsa logo na primeira avaliação.

8

2. Diagrama de Chapin

3. Tradicional (Fluxograma)

VETOR Podemos definir um Vetor como uma variável dividida em vários "pedaços", em várias "casi-nhas", onde cada pedaço desses é identificado através de um número, referente à posição de uma determinada informação no vetor em questão. O número de cada posição do vetor é cha-mado de índice. Conceito: Vetor é um conjunto de variáveis, onde cada uma pode armazenar uma informação diferente, mas todas compartilham o mesmo nome. São associados índices a esse nome, que representam as posições do vetor, permitindo assim, individualizar os elementos do conjunto. Podemos imaginar que na memória do computador o vetor seja mais ou menos da seguinte forma:

9

Exemplos de Manipulação de Vetores: 1) Escrever Nomes [3] Esta instrução escreve na tela, o conteúdo da Posição 3 do Vetor chamado Nomes, ou seja, escreve a palavra ‘Maria’. ATENÇÃO: Sempre que estivermos nos referindo a um Vetor, devemos colocar o Nome do Vetor e a Posição (o Índice) correspondente entre colchetes. 2) Nomes [5] ← 'André' Esta instrução armazena (atribui) a palavra 'André' na posição 5 do Vetor chamado Nomes. 3) Escrever Nomes [X] Esta instrução escreve o conteúdo da posição X do Vetor Nomes, ou seja, é possível utilizar-mos variáveis para indicar a posição (o índice) do Vetor. Neste exemplo 3, o que será escrito depende do valor da variável X. Por exemplo, se antes da instrução Escrever, tivéssemos a instrução: X 4. Então seria escrito o conteúdo da posição 4 do Vetor Nomes, neste caso, seria escrita a pala-vra ‘Ana’. 4) Escrever Nomes [X-2] Esta instrução é para mostrar que também pode-se utilizar cálculos (expressões) para indicar a posição (o índice). Digamos que o X tenha recebido o valor 4, como no exemplo 3 acima, en-tão, neste caso, seria escrita a palavra ‘Alex’. 5) Como LER um Vetor (Preencher) Para Ler um vetor, ou seja, para preencher um vetor com informações (dados) é necessária uma estrutura de repetição, pois um vetor possui várias posições e temos que preencher uma a uma. A estrutura de repetição normalmente utilizada para vetores é o Para-Até-Faça. Veja no exemplo a seguir como preencher (ler) um vetor de 10 posições: var cont : inteiro v[10] : real inicio para cont ← 1 até 10 faça leia (v [cont]) fim-para fim

10

Acima está demonstrado como preencher um vetor chamado v de 10 posições, ou seja, serão lidas 10 informações (valores reais) e cada uma armazenada em uma posição do vetor v. Sen-do que utiliza-se a própria variável da repetição para variar a posição (índice) do vetor. EXEMPLO Escreva um algoritmo para ler a nota de 30 alunos, calcular a média geral da turma e escrever quantos alunos tiveram a nota acima da média calculada. var cont, i : inteiro nota[10] : real soma, media : real inicio cont ← 0 soma ← 0 para i ← 1 até 30 faça leia (nota[i]) soma ← soma + nota [i] fim-para media ← soma / 30 para i ← 1 até 30 faça se nota[i] > media então cont ← cont + 1 fim-se fim-para escreva (“Número de alunos acima da média é: ”, cont) fim

11

MATRIZ O que é uma matriz? Definição “computacional”: Uma matriz de duas dimensões é uma matriz cujos elementos são vetores (Índices). Cada elemento de uma matriz é identificado univocamente por dois índices. Como declarar uma matriz? Para declarar uma matriz de duas dimensões você precisa indicar: Os tipos de dados que serão armazenados Int (inteiro) float double char (caractere) O nome da matriz (seguindo as regras de nomenclatura) O número de elementos de cada componente da matriz Indicados por números inteiros Informados entre colchetes

12

Exemplo: int nota [ 2 ] [ 50 ]; float temp [ 12 ] [ 12 ]; É só uma questão de dimensões... Vetores: Um vetor nada mais é que uma matriz unidimensional Matrizes bidimensionais: Interpretação “geométrica”: linhas x colunas

13

2 Registro, Modularização, Arquivo e Recursividade O que é Estrutura de Dados? Em diversos contextos, disciplinas associadas à programação recebem a denominação de pro-cessamento de dados''. Esta denominação não é gratuita -- de fato, embora seja possível criar procedimentos que não manipulem nenhum dado, tais procedimentos seriam de pouco valor prático.

Uma vez que procedimentos são, efetivamente, processadores de dados, a eficiência de um procedimento está muito associada à forma como seus dados são organizados. Estrutura de dados é o ramo da computação que estuda os diversos mecanismos de organização de dados para atender aos diferentes requisitos de processamento.

As estruturas de dados definem a organização, métodos de acesso e opções de processamen-to para a informação manipulada pelo programa. A definição da organização interna de uma estrutura de dados é tarefa do projetista da estrutura, que define também qual a API (Applicati-on Programming Interface) para a estrutura, ou seja, qual o conjunto de procedimentos que podem ser usados para manipular os dados na estrutura. É esta API que determina a visão funcional da estrutura de dados, que é a única informação relevante para um programador que vá utilizar uma estrutura de dados pré-definida.

Registro Estrutura de dados composta por um conjunto de variáveis de tipos diferentes, primitivos e/ou estruturados (homogêneos ou heterogêneos), que estão relacionadas logicamente e podem ser referenciadas por um mesmo nome (um identificador de registro) ou individualmente. A sintaxe de declaração de um registro utilizada é: Declaração de tipos id_tipo_reg : Registro inicio campo_1 : tipo_campo_1; campo_2 : tipo_campo_2; ........ campo_N: tipo_campo_N; fim_registro onde: id_tipo_reg é o identificador do novo tipo registro. campo_i corresponde ao identificador dos componentes do registro. Se vários campos (ou componentes) apresentam o mesmo tipo, sua declaração pode ser efe-tuada na mesma linha de declaração. A declaração de uma variável do tipo id_tipo_reg é feita na seção de declaração de variáveis: registro1 : id_tipo_reg Exemplo: Declaração de tipos Data : Registro inicio

14

dia, mes, ano: inteiro; fim_registro Declaração de variáveis i, j : inteiro inicio_aulas : Data Modularização Existem várias técnicas para o desenvolvimento de algoritmos. Dentre elas, destaca-se a pro-gramação estrutura. A Programação Estruturada é um conjunto de metodologias para o desen-volvimento organizado de software, buscando obter produtos confiáveis, legíveis, portáveis e flexíveis, de forma a garantir fácil manutenção. A programação estruturada não elimina a ne-cessidade de reflexão e entendimento do problema. As idéias básicas associadas ao desenvolvimento estruturado podem ser resumidas como se-gue: 1. utilização de um número limitado de estruturas de controle (seqüencial, condicional e de re-petição); 2. desenvolvimento de algoritmos utilizando a técnica de refinamentos sucessivos; 3. transformação de alguns refinamentos em módulos. O primeiro item corresponde ao uso das estruturas de controle já discutidas anteriormente. Po-de ser provado que qualquer problema pode ser resolvido com a aplicação das estruturas se-qüencial, condicional e de repetição. Os demais itens são discutidos nas duas subseções a seguir. TÉCNICA DE REFINAMENTOS SUCESSIVOS (REFINAMENTO “TOP-DOWN”) O segundo item está relacionado ao processo criativo de desenvolvimento da solução de um problema a partir da decomposição de um problema em problemas menores e mais simples de serem resolvidos do que o inicial. A decomposição dos subproblemas deve ser feita até que as soluções estejam expressas por um conjunto de ações (instruções, operações e funções) ele-mentares, como as citadas anteriormente. Os refinamentos sucessivos possibilitam ao desenvolvedor a preocupação com detalhes con-forme o nível do processo de refinamento. Com este procedimento, o volume de noções a se-rem manipuladas e entendidas a cada instante é mantido sob controle, o que facilita o enten-dimento necessário para se formular, completa e corretamente, a solução do problema a ser resolvido. O processo de refinamento sucessivo leva à modularização da solução. MODULARIZAÇÃO O último item está associado à construção de módulos isolados com funções bem definidas. Um módulo é um grupo de instruções (comandos) que se constitui em uma função bem defini-da e o mais independente possível em relação ao restante do algoritmo. Este método permite que a solução do problema possa ser desenvolvida por vários programadores de uma equipe, já que um módulo é “independente” dos demais. Este procedimento também concorre para o desenvolvimento de um conjunto de módulos que podem ser reutilizados, já que sua função é independente do problema original mas contribui para a solução. A geração de módulos tem por objetivos:

15

1. evitar a duplicação de código, ou seja, que uma determinada seqüência de comandos ne-cessária em vários locais do algoritmo seja repetida em cada um desses locais; 2. dividir e estruturar um algoritmo em partes fechadas e logicamente coerentes; 3. aumentar a legibilidade do código; 4. facilitar a documentação do algoritmo. Em geral, os módulos devem ter um tamanho limitado. Além disso, uma das características interessantes de módulos é a possibilidade de se definir estruturas de dados próprias do módu-lo, necessárias e suficientes para que estes executem suas tarefas. O uso de dados locais (de-finidos no escopo do módulo) que não têm nenhum significado fora do módulo é fator importan-te para a reutilização de um módulo criado para resolver um determinado problema na solução de outros problemas, além de simplificar a manutenção de softwares. Sem o uso de dados globais é necessário um mecanismo para o compartilhamento de informa-ções entre módulos. A descrição estrutural da modularização pode ser feita por meio de diagramas hierárquicos. Na Figura 2 são representados seis módulos. O módulo A aciona os módulos B e C. O módulo B aciona os módulos D, E e F e o módulo C também aciona o módulo F.

FERRAMENTAS PARA MODULARIZAÇÃO Praticamente todas as linguagens modernas de programação dispõem de ferramentas básicas de modularização, ou seja, permitem criar e manipular módulos. Dentre as principais ferramentas pode-se citar as sub-rotinas e as funções. VINCULAÇÃO ENTRE MÓDULOS (PASSAGEM DE PARÂMETROS) Visto que os módulos correpondem a um conjunto de comandos com um significado lógico e o mais independente possível dos detalhes do problema que se deseja resolver é necessário in-formar a ele com base em que dados a computação deve ser realizada. Isso pode ser feito transferindo os dados necessários por meio de passagem de parâmetros, os quais acabam por vincular os módulos que concorrem para resolver o problema. Os principais modos de transferência de dados são: Passagem de parâmetros por valor (parâmetros de entrada): As alterações efetuadas nos parâmetros formais (veja seção 2.2.3) no módulo chamado não são propagados para os parâ-metros atuais no módulo que faz a chamada.

16

Passagem de parâmetros por resultado (parâmetros de saida): Permite retornar um valor calculado num módulo para o módulo que fez a chamada. Passagem de parâmetros por referência (parâmetros de entrada e saída): Toda alteração dos parâmetros formais passados por referência para o módulo chamado se reflete nos parâ-metros atuais do módulo que fez a chamada. SINTAXE A SER UTILIZADA NA DESCRIÇÃO DE MÓDULOS A sintaxe de definição de módulos utilizada nesta disciplina é apresentada a seguir: Identificador_módulo(lista de parâmetros formais) : tipo_retorno inicio bloco de instruções do módulo fim_módulo onde: Identificador_módulo: nome (identificação) do módulo tipo_retorno: indica o tipo do parâmetro de resultado. Se nenhum tipo de retorno é indicado significa que o módulo não apresenta parâmetro de resultado. Lista de parâmetros formais: parâmetros que permitem a vinculação de módulos. Algoritmo 1: Módulo para o cálculo da média dos elementos de um vetor Media (A:vetor de real, N: inteiro) : real Declaração de variáveis (locais) soma,med : real; inicio soma ¬ 0 Para i ¬ 1 até N faça soma ¬ soma + A[i] med ¬ soma/N retorna med fim_módulo Neste exemplo, A e N são parâmetros (N é passado por valor e o vetor é passado por referên-cia). O módulo calcula e retorna um valor por meio da instrução retorna. Arquivo

O que é um arquivo?

Um arquivo é uma sequência de informações binárias, ou seja, uma sequência de 0 e 1. Este arquivo pode ser armazenado para guardar um vestígio destas informações. Um arquivo texto é um arquivo composto de caracteres armazenados sob a forma de bytes.

Este arquivo é registado no disco rígido sob a forma “nom_du_fichier.ext”.

“.ext” representa a extensão e é um meio para reconhecer o tipo de programa com o qual este arquivo pode ser aberto (atenção, isto não garante o tipo de arquivo: quando se altera a extensão, não se altera o tipo de arquivo!).

O comprimento do nome e a extensão podem variar de acordo com o sistema operacional :

17

• 8 caracteres para o nome e 3 para a extensão sob DOS e Windows 3.1 • 256 caracteres para o nome e a extensão sob Windows 95,98 e NT • 256 sob os sistemas Unix

Assim, sob DOS ou Windows 3.1, um arquivo que provém do Windows 9x terá um nome truncado que comporta os 6 primeiros caracteres do nome seguido de ~x em que x representa um número que é incrementado cada vez que um arquivo leva o mesmo nome. Ou seja, se se um arquivo nomeado “fichie~1” já existir o seguinte chamar-se-á “fichie~2”.

Além disso, um arquivo contém uma rubrica que permite armazenar informações suplementares, como o tipo de arquivo e sobretudo a dimensão do ficheiro. Contém também um carácter de fim de arquivo que assinala que as informações situadas para além deste caracter já não fazem parte do mesmo arquivo .

Poderá pensar: "que estupidez pôr na rubrica do arquivo a dimensão do arquivo dado, se já sabemos qual é!"

Eis dois exemplos que lhe mostrarão a sua utilidade

Os arquivos corrompidos

De certeza já lhe aconteceu fazer um download de um arquivo na Internet/contents/internet/internet.php3 e o navegador bloquear ou o servidor que aloja este arquivo cortar a comunicação.

Se este arquivo for um arquivo texto, faltar-lhe-á apenas o fim do texto, em contrapartida, se for um arquivo binário (um programa realizável, por exemplo), a sua execução poderia muito bem ser perigosa porque faltam informações. O sistema de exploração compara por conseguinte a sua dimensão real com a dimensão indicada na rubrica para verificar a validade do arquivo. Chama-se a isso integridade. Na realidade, este controlo realiza-se com a ajuda de um algoritmo mais eficiente chamado CRC (controlo de redundância cíclico).

Recursividade É uma das principais técnicas de projeto de algoritmos. Um procedimento é recursivo se chama a si mesmo, direta ou indiretamente. Em geral, o uso da recursividade permite uma descrição mais clara e concisa de algoritmos, principalmente quando o problema a ser resolvido é recursivo por natureza ou permite a utiliza-ção de estruturas recursivas, tais como árvores. Todo processo recursivo deve implementar uma condição de TERMINAÇÃO. A chamada re-cursiva a um procedimento P deve estar sujeita a uma condição B, a qual se torna não satisfei-ta em algum momento da computação. Conforme definido por Wirth (1976): P º se B então C[Si , P] onde C é uma composição de comandos Si (outras instruções) e P(chamada ao procedimento recursivo). Técnica Básica: Definir f(x) tal que: f(x) <= 0 corresponde à condição de terminação; f(x) é decrementada a cada iteração, onde x é um conjunto de variáveis do programa.

18

Simplificação: Associar um parâmetro n para P (por valor) e chamar P recursivamente com (n-1). Nestas condições a B é substituída por N > 0 : P º se n > 0 então C[Si , P(n -1)]

19

3 Estrutura de Dados = Lista, Fila e Pilha O que é Estrutura de Dados? Em diversos contextos, disciplinas associadas à programação recebem a denominação de pro-cessamento de dados''. Esta denominação não é gratuita -- de fato, embora seja possível criar procedimentos que não manipulem nenhum dado, tais procedimentos seriam de pouco valor prático.

Uma vez que procedimentos são, efetivamente, processadores de dados, a eficiência de um procedimento está muito associada à forma como seus dados são organizados. Estrutura de dados é o ramo da computação que estuda os diversos mecanismos de organização de dados para atender aos diferentes requisitos de processamento.

As estruturas de dados definem a organização, métodos de acesso e opções de processamen-to para a informação manipulada pelo programa. A definição da organização interna de uma estrutura de dados é tarefa do projetista da estrutura, que define também qual a API (Applicati-on Programming Interface) para a estrutura, ou seja, qual o conjunto de procedimentos que podem ser usados para manipular os dados na estrutura. É esta API que determina a visão funcional da estrutura de dados, que é a única informação relevante para um programador que vá utilizar uma estrutura de dados pré-definida.

LISTA Uma Estrutura de Dados Lista é um conjunto de dados dispostos e/ou acessáveis em uma seqüência determinada.

• Este conjunto de dados pode possuir uma ordem intrínseca (Lista Ordenada) ou não. • Este conjunto de dados pode ocupar espaços de memória fisicamente consecutivos, es-

pelhando a sua ordem, ou não. • Se os dados estiverem dispersos fisicamente, para que este conjunto seja uma lista, ele

deve possuir operações e informações adicionais que permitam que seja tratado como tal (Lista Encadeada).

Vimos 2 Aspectos Em um projeto de software, 2 aspectos devem ser considerados:

• De que forma estão organizados os dados, qual a sua estrutura. • Quais procedimentos atuam sobre estes dados, que operações podem ser realizadas

sobre eles. • Vamos ver agora estes aspectos para as listas.

2.2.1 Listas usando Vetores: Modelagem de Listas utilizando Programação Estruturada

• Modelaremos a Estrutura de Dados Lista utilizando a técnica da Programação Estrutu-rada e como forma de armazenamento um Vetor (Array).

o Veremos somente algoritmos. o Veremos algoritmos tanto para uma lista cronológica como para uma lista orde-

nada. • Procedimento Didático:

o Modelagem da Lista e de seus algoritmos usando a técnica estruturada. o Exercícios

20

Modelagem da Lista

• Aspecto Estrutural: o Necessitamos de um vetor para armazenar as informações. o Necessitamos de um indicador da posição atual do ultimo elemento da lista. o Necessitamos de uma constante que nos diga quando a lista está cheia e duas

outras para codificar erros.

• Aspecto Funcional:

1. Colocar e retirar dados da lista. 2. Testar se a lista está vazia ou cheia e outros testes. 3. Inicializa-la e garantir a ordem dos elementos.

• Operações: Colocar e retirar dados da lista:

Adiciona(dado) AdicionaNoInício(dado) AdicionaNaPosição(dado,posição) AdicionaEmOrdem(dado) Retira() RetiraDoInício() RetiraDaPosição(posição) RetiraEspecífico(dado)

• Operações: Testar a lista e outros testes:

ListaCheia ListaVazia Posicao(dado) Contem(dado) Igual(dado1,dado2) Maior(dado1,dado2) Menor(dado1,dado2)

• Operações: Inicializar ou limpar:

InicializaLista DestroiLista

Algoritmo InicializaLista FUNÇÃO inicializaLista() início aLista.ultimo <- -1; fim; Observação: Este e os próximos algoritmos pressupõem que foi definida uma variável global tipo Lista denominada aLista.

21

Algoritmo DestroiLista FUNÇÃO destroiLista() Início aLista.ultimo <- -1; fim; Observação: Este algoritmo parece redundante. Colocar a sua semântica em separado da ini-cialização porém, é importante. FILA É uma lista linear em que a inserção é feita numa extremidade e a eliminação na outra. Conhecida como estrutura FIFO (First In, First Out). ( a1, a2 , ... , an ) eliminações inserções no início no final Exemplos: • Escalonamento de "Jobs": fila de processos aguardando os recursos do sistema operacional. • Fila de pacotes a serem transmitidos numa rede de comutação de pacotes. • Simulação: fila de caixa em banco. Operações associadas: 1. Criar - cria uma fila vazia 2. Vazia - testa se um fila está vazia 3. Primeiro - obtém o elemento do início de uma fila 4. Inserir - insere um elemento no fim de uma fila 5. Remover - remove o elemento do início de uma fila, retornando o elemento removido. Implementação de Filas Como lista Seqüencial ou Encadeada ? Pelas suas características, as filas têm as eliminações feitas no seu início e as inserções feitas no seu final. A implementação encadeada dinâmica torna mais simples as operações (usando uma lista de duas cabeças). Já a implementação seqüencial é um pouco mais complexa (teremos que usar o conceito de fila circular), mas pode ser usada quando há previsão do tamanho máximo da fila. IMPLEMENTAÇÃO SEQÜENCIAL DE FILA Definição da Estrutura de Dados: Devido a sua estrutura, será necessária a utilização de dois campos que armazenarão os índi-ces do início e do final da fila e um vetor de elementos (onde serão armazenados os dados) com tamanho pré-estabelecido. REGISTRO tfila INICIO

22

v : VETOR [1..5] DE INTEIRO //contém uma fila de 05 elementos inicio : INTEIRO final : INTEIRO FIMREGISTRO PILHA São listas onde a inserção de um novo item ou a remoção de um item já existente se dá em uma única extremidade, no topo.

Definição: • Dada uma pilha P = ( a(1), a(2), ..., a(n) ), dizemos que a(1) é o elemento da base da pilha; • a(n) é o elemento topo da pilha; e a(i+1) está acima de a(i). • Pilhas são também conhecidas como listas LIFO (last in first out). Operações Associadas: 1. Criar uma pilha P vazia; 2. Testar se P está vazia; 3. Obter o elemento do topo da pilha (sem eliminar); 4. Inserir um novo elemento no topo de P (empilhar); 5. Remover o elemento do topo de P (desempilhar); Implementação de Pilhas Como lista Seqüencial ou Encadeada?

23

No caso geral de listas ordenadas, a maior vantagem da alocação encadeada sobre a seqüen-cial - se a memória não for problema - é a eliminação de deslocamentos na inserção ou elimi-nação dos elementos. No caso das pilhas, essas operações de deslocamento não ocorrem. Portanto, podemos dizer que a alocação seqüencial é mais vantajosa na maioria das vezes. Exemplo do Uso de Pilhas Chamadas de procedimentos Suponha a seguinte situação:

Quando o procedimento A1 é executado, ele efetua uma chamada a A2, que deve carregar consigo o endereço de retorno e1. Ao término de A2, o processamento deve retornar ao A1, no devido endereço. Situação idêntica ocorre em A2 e A3. Assim, quando um procedimento termina, é o seu endereço de retorno que deve ser consulta-do. Portanto, há uma lista implícita de endereços (e0, e1, e2, e3) que deve ser manipulada como uma pilha pelo sistema, onde e0 é o endereço de retorno de A1. No caso de processamento recursivo - por exemplo uma chamada a A2 dentro de A4 - o ge-renciamento da lista como uma pilha resolve automaticamente a obtenção dos endereços de retorno na ordem apropriada (e0, e1, e2, e3, e4). ALOCAÇÃO SEQÜENCIAL DE PILHAS Definição da Estrutura de Dados: REGISTRO tpilha INICIO v : VETOR [1..5] DE INTEIRO //contém uma pilha de 05 elementos topo : INTEIRO FIMREGISTRO

24

4 Busca e Ordenação (Aaron = 486-661 + 408-482) + (Waldemar = 239-263) BUSCA As tarefas relacionadas à busca e ordenação são muito utilizadas pelo ser humano; Sempre que procuramos um número telefone na agenda do celular ou uma palavra no dicionário estamos realizando a tarefa de busca; Muitas vezes a ordenação dos elementos facilita o processo de busca e a organização geral dos elementos e por isso este também é muito importante; Só possuir os dados não ajuda em nada se não soubermos onde eles se encontram. Suponha, por exemplo, uma lista de presença de alunos. Se não conseguirmos localizar um aluno ela não nos servirá de nada. Os algoritmos de busca são alguns dos mais utilizados no mundo da informática: usados em bancos de dados, Internet, jogos, entre outros; A escolha do método a ser utilizado depende muito da quantidade de dados envolvidos, do volume de operações de inclusão e exclusão a serem realizadas, entre outros. Todos os algoritmos de busca têm o objetivo de encontrar ou localizar um elemento que corresponde a uma determinada chave de pesquisa; Apesar do objetivo ser sempre o mesmo existem diversas maneiras de se chegar até ele; Estaremos discutindo aqui neste primeiro momento somente algoritmos de busca relacionados à memória primária; Os dois algoritmos de busca a elementos em uma lista linear mais conhecidos são: Busca seqüencial; Busca binária; Busca seqüencial: O algoritmo de busca seqüencial ou linear consiste em visitar um a um os elementos de uma lista comparando-os com o elemento alvo da busca; Caso encontre o elemento, o algoritmo deve retornar o valor verdadeiro ou a posição em que foi encontrado. Caso contrário, deve retornar o valor falso, uma mensagem ou outro valor que se convencionar; Exemplo 1: Considere a seguinte lista de elementos: [22, 51, 18, 34, 02, 16, 45, 73, 29]. A busca ao elemento 34 deve proceder da seguinte forma: Compare o 34 com o primeiro da lista, no caso o 22. Como não é ele compare o 34 com o próximo que é o 51. Segue-se assim até encontrar o 34 na quarta posição da lista, retornando verdadeiro ou a posição do elemento 34 de acordo com o objetivo do algoritmo; Exemplo 2: Considere a seguinte lista de elementos: [22, 51, 18, 34, 02, 16, 45, 73, 29] Agora vejamos o que acontece na busca ao elemento 63: Compare o 63 com o primeiro da lista, no caso o 22. Como não é ele compare o 63 com o próximo que é o 51 e assim por diante até chegar ao final da lista. Como não é nenhum deles concluímos pelo insucesso da busca; O método de busca linear é o mais adequado quando não se tem nenhuma informação a respeito da estrutura em que a busca será realizada; Se o elemento procurado estiver entre os últimos ou não estiver no conjunto, esse método poderá ser demasiadamente lento; Busca binária: Quando temos uma seqüência ordenada de elementos, existem outros métodos de busca muito mais eficientes; Ao procurar um elemento, em vez de compará-lo com o primeiro elemento da seqüência, pode-se compará-lo com o elemento do meio. Divide-se então a seqüência em blocos sucessivamente, até que o elemento seja encontrado; Esta busca é

25

conhecida como binária ou logarítmica pois o esforço para completar o algoritmo é logarítmico: O(log n) ao contrário da busca binária que é O(n); Comparações sucessivas são feitas entre o elemento que se procura e o elemento no meio da seqüência pesquisada. Cada não-sucesso da busca reduz a seqüência pela metade, até que o elemento seja encontrado ou a seqüência não possa mais ser dividida. Exemplo 1: Considere a seguinte lista de elementos: [02, 16, 18, 22, 29, 34, 45, 51, 73], a busca ao elemento 34 deve proceder da seguinte forma: Encontre o elemento do meio do vetor, no caso o 29. Compare o 34 com ele. Como não é ele e 34 é maior que 29 considere para a busca o trecho do vetor do próximo de 29 em diante. O elemento do meio agora é o 45. Ao fazer o mesmo passamos a considerar somente a posição 6 do vetor retornando verdadeiro ou a posição 6 de acordo com o objetivo do algoritmo; Considere a seguinte lista de elementos: [02, 16, 18, 22, 29, 34, 45, 51, 73] Agora vejamos o que acontece na busca ao elemento 63: Encontre o elemento do meio do vetor, no caso o 29. Compare o 63 com ele. Como não é ele e 63 é maior que 29 considere para a busca o trecho do vetor do próximo de 29 em diante. O elemento do meio agora é o 45. Fazemos o mesmo com o elemento 51. Ao fazer o mesmo e também não é este. Neste instante o início cruza com o final e retornamos falso;