Você está na página 1de 83

Técnico em Informática Integrado ao Ensino Médio

Algoritmos e
Linguagem de
Programação II
Professores
Ayslan Trevizan Possebom Daniela Eloise Flôr

Ano Letivo 2021


Ambiente Virtual de Aprendizagem (AVA)
Ambiente virtual de aprendizagem é um software, geralmente disponibilizado na web, que permite aos
professores fornecerem conteúdos (apostilas, slides, videoaulas, avaliações, etc.) aos seus alunos, assim
como acompanhar o progresso destes alunos durante o decorrer da disciplina.

Para acessar o AVA do IFPR, utilize um navegador web (ex: Google Chrome, Firefox, Internet Explorer) e abra
o site https://ava.ifpr.edu.br.

No canto superior direito da tela, clique no texto (Acessar). Digite seus dados de acesso (CPF e senha
cadastrada) e clique no botão Acessar para ter acesso ao sistema.

Escolha o componente curricular 1º Ano – Algoritmos e Linguagem de Programação I e terá acesso a todo
material disponibilizado pelos professores para o estudo desta disciplina. As figuras abaixo demonstram a
sequência destas ações.

Contato com os professores


Para entrar em contato com os professores, utilize os seguintes meios de comunicação:

Email: Professor Ayslan: ayslan.possebom@ifpr.edu.br

Professora Daniela: daniela.flor@ifpr.edu.br

AVA: Na barra superior, clique no ícone de mensagem, pesquise pelo nome do professor (Ayslan Possebom
ou Daniela Flôr) e digite a mensagem. Os professores receberão a mensagem enviada e responderão assim
que possível. As figuras abaixo demonstram as etapas.

Livros na Biblioteca ou Biblioteca Virtual


PUGA, Sandra; RISSETTI, Gerson. Lógica de Programação e Estrutura de Dados: com aplicações em Java.
Editora Pearson, 2008.

ASCENCIO, Ana F. G.; CAMPOS, Edilene A. V. Fundamentos da Programação de Computadores: algoritmos,


Pascal, C/C++ e Java. Editora Pearson, 2007.
Objetivos da Disciplina
Esta disciplina tem como objetivo dar continuidade e aprofundamento dos conhecimentos obtidos na
disciplina de Algoritmos e Linguagem de Programação I, revisando os conteúdos estudados anteriormente e
dando enfoque particular aos mecanismos de armazenamento e organização dos dados em um computador,
de modo que os mesmos possam ser organizados, manipulados e filtrados de maneira eficiente. Tal aspecto
fornece embasamento para áreas correlatas, bem como prepara os acadêmicos para a continuidade dos
estudos e/ou uma atuação profissional exitosa.

Como objetivos específicos, temos:

• Modularizar os algoritmos por meio da construção de subalgoritmos;


• Apresentar diferentes tipos de estrutura de dados abordando seus respectivos propósitos de
aplicação;
• Apoiar o exercício da construção da lógica de programação, principalmente o que tange as
estruturas de dados;
• Correlacionar os conteúdos programáticos com as subáreas da computação que empregam as
técnicas de estrutura de dados;
• Apresentar reconhecidos métodos de organização de estrutura de dados, bastante difundidos
academicamente, que se tornaram implementação de referência;
• Despertar o interesse por estudos mais avançados na área da Ciência da Computação;
• Consolidar o uso do ambiente de virtual de aprendizagem Moodle.

Ementa da Disciplina
Estruturas de dados homogêneas. Pesquisa e ordenação. Estruturas de dados dinâmicas. Estruturas de
dados heterogêneas. Recursividade.

Como devo estudar


Sugere-se o conjunto de atividades a seguir como forma de organização e sequência para o estudo individual
dos alunos:

• Ler o material disponibilizado pelo professor. Leitura de apostilas ou livros didáticos sugeridos sobre
os temas a serem estudados no período;
• Busca na internet sobre textos e outros materiais. Caso o aluno não tenha compreendido parte da
matéria, ele poderá efetuar buscas na internet sobre o assunto estudado;
• Vídeos no Youtube. O Youtube possui muitos vídeos sobre os assuntos “Algoritmos”, “Lógica de
Programação” e “Linguagem Java”. Estes vídeos podem auxiliar na explicação dos conceitos e sanar
possíveis dúvidas. Outros sites de cursos, tal como Udemy, também poderão ser utilizados;
• Resolução dos exercícios propostos. Todos os exercícios propostos pelo professor deverão ser
resolvidos pelos alunos. Os atendimentos acadêmicos podem ser utilizados para o auxílio na
explicação do conteúdo e na resolução destes exercícios;

Resolução dos exercícios de acompanhamento. Estes exercícios deverão ser resolvidos por cada aluno,
individualmente. Para a resolução destes exercícios, o aluno poderá fazer consultas nos materiais de estudo.
É de extrema importância que o estudante não obtenha respostas prontas na Internet ou com outros alunos,
buscando apenas dicas de como solucionar os problemas.
SUMÁRIO

1. Revisando Fundamentos .................................................................................................................................1


Conceitos Gerais ...............................................................................................................................................2
Tipos de Dados .................................................................................................................................................3
Exibindo mensagens .........................................................................................................................................4
Criando variáveis ..............................................................................................................................................5
Operadores Aritméticos ...................................................................................................................................7
Digitando valores no teclado ............................................................................................................................8
Cálculos matemáticos mais avançados ......................................................................................................... 10
Operadores Relacionais ................................................................................................................................. 13
Operadores lógicos ........................................................................................................................................ 14
Tomando decisões nos algoritmos ................................................................................................................ 15
Estruturas de Repetição ................................................................................................................................ 17
2. Subprogramação........................................................................................................................................... 24
Subprogramação (modularização de códigos) .............................................................................................. 25
Procedimentos............................................................................................................................................... 25
Procedimentos com passagem de Parâmetros ............................................................................................. 28
Funções.......................................................................................................................................................... 29
Comparando Procedimentos e funções ........................................................................................................ 30
Recursividade ................................................................................................................................................ 31
3. Estruturas de Dados Homogênea Unidimensional ....................................................................................... 38
Vetores .......................................................................................................................................................... 39
Percorrendo vetores ...................................................................................................................................... 41
Procedimentos e funções com vetores ......................................................................................................... 43
Estrutura de dados homogênea multidimensional ....................................................................................... 45
Estruturas de dados dinâmicas...................................................................................................................... 47
4. Ordenação de Vetores .................................................................................................................................. 52
Conceitos iniciais ........................................................................................................................................... 53
Preliminares ................................................................................................................................................... 53
Algoritmo de Ordenação por Bolha............................................................................................................... 54
Algoritmo de Ordenação por Inserção .......................................................................................................... 57
Algoritmo de Ordenação por Seleção ........................................................................................................... 59
5. Busca de dados em Vetores.......................................................................................................................... 62
Recuperação de informação.......................................................................................................................... 63
Busca Sequencial ........................................................................................................................................... 63
Algoritmo de Busca Binária ........................................................................................................................... 64
6. Estruturas de Dados Heterogêneas .............................................................................................................. 71
Registros ........................................................................................................................................................ 72
Vetores de Registros...................................................................................................................................... 74
Registros em parâmetros de subalgoritmos ................................................................................................. 75
1. Revisando Fundamentos

Objetivos de aprendizagem
Este capítulo tem como objetivo:

• Revisar os conceitos de Algoritmos, abordando questões


sobre: método principal; exibição de dados na tela do
computador; criação de variáveis; uso de operadores de
atribuição, aritméticos, relacionais e lógicos; aplicação
de estruturas de decisão e repetição
• Resolver exercícios de programação sequencial
aplicando lógica de programação e linguagem de
programação
• Utilizar um Ambiente Integrado de Desenvolvimento
• Favorecer a compreensão e a elaboração de soluções de
problemas algorítmicos de forma fluída

1
Conceitos Gerais
Nesta disciplina, utilizamos a linguagem de programação Java para desenvolver nossos algoritmos e utilizar o
raciocínio lógico para a solução de problemas computacionais.

A linguagem Java1 é formada basicamente pelo compilador (que traduz o código-fonte para a linguagem de
máquinas) e pela máquina virtual java JVM – Java Virtual Machine (que é a parte responsável por executar os
programas compilados em linguagem Java).

Ao desenvolver os algoritmos, frequentemente fazemos uso de IDEs (Ambiente Integrado de


Desenvolvimento, ou Integrated Development Environment). Os mais famosos para este fim são: Netbeans2,
Eclipse3 e IntelliJ4. Outras IDEs para a linguagem Java também estão disponíveis e podemos utilizar qualquer
editor de textos para escrevermos nossos códigos-fonte, até mesmo o Bloco de Notas. Entretanto, o uso de
uma IDE facilita no processo de escrita de instruções, compilação de códigos e execução do programa criado.

Utilizando estas IDEs modernas, tais como Netbeans e Eclipse, um algoritmo representa a criação de um
programa de computador. Neste sentido, sempre que desejarmos criar um algoritmo, este algoritmo deve
estar associado a um projeto na IDE. Portanto, devemos sempre criar um novo Projeto que executará
códigos na linguagem Java para que os códigos possam ser criados.

Tendo-se o proejto criado, o ambiente se encontra pronto para receber o código-fonte da aplicação.
Especificamente na linguagem Java, escrevemos o código-fonte dentro de classes. Para isso, precisamos
sempre criar uma classe dentro do projeto.

Como forma de padronização de código e “boas práticas de desenvolvimento”, os nomes das classes devem
começar sempre com letras maiúsculas.

Dentro da classe precisamos fornecer o método principal. Este método representa uma função que sempre
será executada ao “abrirmos o programa”. Como um algoritmo pode ser formado por diversas funções, este
método indica por onde a execução deve começar. Chamamos o método principal na linguagem java de
método main, ou função main. Sua declaração deve ser conforme a sintaxe a seguir:
public class Revisao {
public static void main(String[] args) {
Método principal
}
}

Observando o exemplo acima, pode-se observar que após o nome da classe Revisao temos o início de um
bloco de instruções. Um bloco de instruções representa uma seção de código, ou seja, um conjunto de
instruções que é executado quando àquela estrutura for invocada ou ativada. Os blocos de instruções são
iniciados com o símbolo { e finalizados com o símbolo }. Portanto, tudo o que estiver entre { e } pertence a
este bloco de instrução.

Dentro do bloco de instrução da classe temos a definição do método principal public static void
main(String[] args). Observe que o método também define um bloco de instruções. Logo, sempre que o
método principal da classe Revisao for executado, as instruções dentro deste bloco serão executadas, uma a

1
Para instalar a linguagem Java, precisamos baixar a versão Java SDK disponível em
https://www.oracle.com/java/technologies/javase-jdk8-downloads.html
2
Disponível em https://netbeans.org/
3
Disponível em https://www.eclipse.org/
4
Disponível em https://www.jetbrains.com/pt-br/idea/. A versão Community é gratuita.
2
uma, do início até o fim. Lembre-se que um algoritmo é uma sequência de instruções e, portanto, as
instruções devem ser colocadas na ordem correta para que um problema possa ser resolvido.

Tipos de Dados
Considere um produto qualquer em um supermercado. Imaginemos uma bolacha. Quais são os dados que
podemos pensar sobre esta bolacha?

• A marca da bolacha
• A quantidade de bolachas que o supermercado possui
• O preço que esta bolacha custa
• A data de validade desta bolacha
• Se esta bolacha está vencida ou não
• Etc.

Quando falamos sobre a marca da bolacha, temos como exemplo “Biscoito Passatempo” ou “Bono”. A marca
corresponde a um texto. Outras informações como, por exemplo, o nome de um aluno, o nome da cidade
que uma instituição está instalada, o endereço de uma residência, entre outros, todos são representados
como uma forma textual. Chamamos este tipo de dado de String. Os textos devem estar sempre entre aspas
duplas. Por exemplo: “Maria da Silva”, “Paranavaí”, “Avenida Paraná, 2500”. Dizemos que uma String é vazia
quando ela não possui nenhum caractere dentro dela, por exemplo, “”. Observe ainda que String se escreve
com S maiúsculo.

Ainda se referindo a caracteres (letras, números ou símbolos tais como $, %, @ etc.), em Java ainda temos o
tipo char. Um caractere, ou um char, corresponde a um único caractere alfanumérico. Para ser um char
devemos ter apenas um caractere, sempre um caractere. Representamos um valor do tipo char sempre
utilizando aspas simples e o caractere dentro deste par de aspas. Por exemplo: ‘a’, ‘&’, ‘#’ ou mesmo ‘ ’
(caractere espaço em branco, observe que existe um espaço entre ‘ e ‘).

Ao se referir à quantidade de bolachas que o supermercado possui, temos como exemplo 200 pacotes de
bolacha, ou 150 pacotes de bolacha, ou mesmo 0 pacotes de bolacha. Quando tempos números para serem
representados em nossos algoritmos e estes números são valores sem casas decimais, dizemos que estes
números são inteiros. Números inteiros podem ser negativos (ex: -450, -80), zero (ex: 0) ou números
positivos (ex: 450, 80). Em Java, chamamos números inteiros de int.

O preço da bolacha pode ser representado por R$1,99 ou R$3,59, por exemplo. Observe que não são
números inteiros, visto que os números possuem casas decimais. Em Java, chamamos os números que
possuem casas decimais de double. Outra características dos números com casas decimais é que não
podemos utilizar a vírcula (,) para separar a parte inteira da parte decimal. Sempre utilizamos o ponto (.)
para este fim. Por exemplo: 1.99 ou 3.59 ou 0.0 ou -74.8745.

Por fim, temos o tipo lógico que em Java é chamado de valor booleano, ou boolean. Este tipo de valor
representa situações onde a resposta será sempre sim ou não, ou, true e false. Toda situação que envolva
apenas duas respostas (sim ou não, 0 ou 1, etc.) pode ser representado por valores booleanos true e false.
Por exemplo: perguntando se a bolacha está vencida, a resposta é sim (true) ou não (false). Outros
exemplos: O ar condicionado está ligado? (true ou false). A porta está fechada? (true ou false). Uma pessoa
com 1.60 de altura é alta? (true ou false).

Devemos sempre observar que tipo de informação desejamos que os nossos algoritmos armazene e, com
isso, sabemos qual é o tipo de dado necessário para que esta informação esteja disponível ao nosso
algoritmo.

3
Exibindo mensagens
Em Java, podemos apresentar mensagens na tela do computador utilizando o comando:
System.out.println( MENSAGEM A SER EXIBIDA );

Observe que o comando System se escreve com S maiúsculo. Observe que precisamos de um par de
parênteses com a mensagem a ser exibida configurada dentro destes parênteses. Observe ainda que a
instrução deve ser finalizada com um ponto-e-vírgula ;.

Observe os seguintes comandos.

Exibir uma mensagem com dado do tipo String:


System.out.println(“Bob Esponja Calça Quadrada”);

Exibir uma mensagem com dado do tipo char:


System.out.println(‘x’);

Exibir uma mensagem com dado do tipo boolean:


System.out.println(true);
System.out.println(false);

Exibir uma mensagem com dado do tipo int:


System.out.println(80);

Exibir uma mensagem com dado do tipo double:


System.out.println(1.99);

Podemos criar frases para serem exibidas na tela do computador. Para isso, usamos o operador + para fazer
concatenação de Strings, ou seja, colocar uma informação na frente da outra, unindo-as, obtendo uma
String maior contendo todos os dados informados.
System.out.println(“Meu nome é ” + “He-Man e tenho ” + 15 + “ anos”);
System.out.println(“Idade:” + 15 + “ e peso:” + 60.8 + “kg.”);

A String “Meu nome é ” será concatenada a outra String “He-Man e tenho ” e também ao número inteiro 15
e a outra String “ anos”. Desta forma, obteremos a String “Meu nome é He-Man e tenho 15 anos” que será
então exibida na tela.

A String “Idade:” é concatenada com o número inteiro 15, pela String “e peso:” acompanhada do número
ponto-flutuante 60.8 e da String “kg.”. O resultado desta concatenação será a String “Idade: 15 e peso:
60.8kg.” que será então exibida ao usuário.

Observe que o resultado de uma concatenação sempre precisa ter uma String envolvida e o resultado
sempre será uma String.

Dica: o símbolo + tem duas funções: concatenar Strings e fazer soma de valores. Precisamos estar atentos ao
uso do símbolo +

4
“Hoje é dia ” + 13 + “ de janeiro” ➔ String + int + String. Como tem String envolvida, concatena-se
gerando uma nova String.

5+3 ➔ int + int. Como temos apenas valores numéricos, temos uma
operação matemática de soma e o resultado será 8

Criando variáveis
Uma variável consiste em um nome fictício (um apelido) que damos para uma posição de memória do
computador. Esta variável deve possuir um tipo de dado, ou seja, ela deve representar um valor que seja
inteiro, ponto-flutuante, String, caractere, booleano, ou algum outro tipo de dado disponível na linguagem
de programação. De forma resumida, usamos variáveis na programação para conseguir armazenar
temporariamente alguns dados durante a execução do programa.

A sintaxe (ou seja, o jeito correto de se escrever os comandos) para criar variáveis é:

<TIPO DE DADO> <NOME DA VARIÁVEL>;

Os tipos de dados que iremos utilizar em nossas aulas são:

int para números inteiros

double para números ponto-flutuantes

char para caracteres individuais

String para conjuntos de caracteres (textos, frases)

boolean para valores booleanos

Dica: 2 é diferente de 2.0 que é diferente de “2” ou ‘2’. O primeiro é um número inteiro, o segundo é um
número ponto-flutuante, o terceiro é uma String formada por um único caractere alfanumérico e o quarto é
um único caractere alfanumérico.

O nome da variável geralmente indica o que aquele valor significa na execução do algoritmo. Por exemplo:
String nome;

Indica que foi criada uma variável chamada nome e esta variável contém uma sequência de caracteres (é
uma String). O conteúdo que esta variável irá guardar representa um nome.

Por boas práticas de programação, os programadores estabelecem que os nomes das variáveis devem
sempre começar com letra minúscula e, caso seja uma palavra composta, as primeiras letras de cada palavra
seriam maiúsculas. Por exemplo: precoDoProduto, nomeCompleto, primeiroNome. Outro uso seria o uso
do caractere _ (sublinhado) para separar as palavras: preco_do_produto, nome_completo, etc.

Alguns exemplos para criação de variáveis:


String nome;
int idade;

5
double salario;
double preco;
String cidade;
int distancia;
boolean portaEstaAberta;
char primeiraLetra;
double peso;
char opcao;
int total;

Após a criação da variável, podemos atribuir valores a ela, ou seja, dizer ao algoritmo que a variável possui
um valor. Para atribuir um valor a uma variável, usamos o operador de atribuição = seguido do valor a ser
guardado nesta variável. O valor deve ser compatível com o tipo de dado da variável, ou seja, se a variável é
String, deve guardar valores String, se é inteira, deve guardar valores inteiros.
nome = “Mulher Maravilha”;
idade = 26;
portaEstaAberta = false;
peso = 59.8;
total = 5;

Podemos modificar os valores das variáveis a qualquer momento durante a execução do nosso algoritmo.
Por exemplo:
int quantia;
quantia = 8; //Aqui quantia vale 8
quantia = 10; //Aqui quantia agora vale 10
quantia = 2; //Agora quantia vale 2

Na primeira linha, a variável quantia foi criada e ela armazena valores do tipo int (números inteiros).

Na segunda linha, a variável quantia recebe o número 8. Na terceira linha, a variável quantia é atualizada e
seu novo valor será 10. Por fim, a variável quantia vale 2.

Podemos criar as variáveis já atribuindo valores iniciais a ela. Para isso, basta usar o operador de atribuição
e o valor inicial.
String apresentador = “Luciano Huck”;
int idade = 48;
double sexo = true;

6
Podemos apresentar os valores das variáveis normalmente:
int idade = 48;
System.out.println(idade);
System.out.println(“A idade é:” + idade);

Usando variáveis, também podemos efetuar cálculos. Por exemplo:


int x = 10;
int y = 20;
int z = a + b;
System.out.println(“Resultado: ” + z);

Inicialmente, a variável x foi criada e inicializada com o valor 10. A variável y foi criada e inicializada com 20.
A variável z foi criada e seu valor será 30. Por fim, a mensagem “Resultado: 30” será exibida na tela do
usuário.

O algoritmo completo seria:


public class PrimeiraAula {
public static void main(String[] args) {
int x = 10;
int y = 20;
int z = x + y;
System.out.println("Resultado: " + z);
}
}

Operadores Aritméticos
Utilizamos os operadores aritméticos para realizar cálculos matemáticos e criar expressões matemáticas nos
nossos algoritmos. Em Java, temos os seguintes operadores aritméticos:

+ Soma

- Subtração

* Multiplicação

/ Divisão

% Resto da divisão (parte inteira do resto da divisão)

O resultado do cálculo matemático sempre será do maior tipo de dado utilizado na expressão matemática.
Por exemplo, a soma de um inteiro com um inteiro, resulta em um valor inteiro.
int a = 10;
int b = 20;

int c = a + b; //c = 30 temos que 10 + 20 = 30

O resultado do cálculo envolvendo um inteiro com um ponto-flutuante sempre será ponto-flutuante, visto
que armazenam valores com casas decimais.

7
int a = 10;
double b = 20.0;

double c = a + b; //c = 30.0 temos que 10 + 20.0 = 30.0

A divisão de dois números inteiros sempre será um número inteiro (descartando os valores após a vírgula).
int a = 10;
int b = 20;

int c = a / b; //c = 0 temos que 10 / 20 = 0

Entretanto, se algum dos valores for ponto-flutuante, o resultado também será ponto-flutuante.
int a = 10;

double b = 20; //automaticamente 20 é convertido para 20.0

double c = a / b; //c = 0.5 temos que 10 / 20.0 = 0.5

Quanto ao resto da divisão, este valor sempre será inteiro.


int a = 10;
10 4
int b = 4; 8 2
int c = a % b; //c = 2 temos que 10 / 4 = 2 e sobra 2 (resto) 2

Digitando valores no teclado


Para fornecer entrada de dados aos nossos algoritmos, ou seja, para que o usuário consiga digitar valores e
estes valores sejam processados, iremos utilizar um objeto chamado Scanner. Ao usar esse objeto, no início
do nosso código, antes da definição da classe, precisamos importar a classe Scanner. Essa importação é
necessária visto que ela não foi desenvolvida por nós e não está presente no nosso projeto para usarmos.
Com a importação, dizemos ao Java que aquele recurso estará disponível para usarmos. Para isso,
precisamos do comando
import java.util.Scanner;

Por exemplo:
import java.util.Scanner;
public class PrimeiraAula {
public static void main(String[] args) {
}
}

Com a classe Scanner importada, podemos criar um objeto que representa o teclado do nosso computador.
Para isso, usamos a seguinte instrução:
Scanner teclado = new Scanner(System.in);

Com o teclado criado e representado no nosso algoritmo, podemos utilizá-lo para fazer leituras.

Para que o usuário possa digitar um valor do tipo String, usamos

8
teclado.nextLine();

Para que o usuário digite valores int, usamos


teclado.nextInt();

Para que o usuário digite valores double, usamos


teclado.nextDouble();

Para que o usuário digite valores boolean (true ou false), usamos


teclado.nextBoolean();

Para que o usuário digite um char, usamos


teclado.nextLine().charAt(0);

Quando o usuário digita algum valor, ao apertar a tecla ENTER no teclado, este valor digitado deve ser salvo
em algum lugar, caso contrário, perderemos a informação dada pelo usuário. Desta forma, sempre que o
usuário for digitar algum valor para o algoritmo, este valor deve ser salvo em alguma variável.
import java.util.Scanner;
public class PrimeiraAula {
public static void main(String[] args) {
Scanner teclado = new Scanner(System.in);
String nome;
System.out.println("Digite seu nome: ");
nome = teclado.nextLine();
System.out.println("O nome informado foi " + nome);
System.out.println("Digite outro nome: ");
nome = teclado.nextLine();
System.out.println("Novo nome: "+ nome);
}
}

No algoritmo acima, inicialmente o teclado e uma variável chamada nome do tipo String foram criados. A
partir deste ponto, o teclado pode ser utilizado e a variável nome está disponível para receber valores.

Uma mensagem “Digite seu nome: ” será exibida na tela e o cursor ficará aguardando que o usuário digite
alguma coisa (teclado.nextLine()). Ao pressionar ENTER, o valor digitado será atribuído à variável nome, ou
seja, temos que nome = o que o usuário digitar.

O programa exibirá uma mensagem informando ao usuário o que foi digitado.

Novamente, o programa exibirá a mensagem “Digite outro nome: ” e aguardará até que o usuário digite algo
no teclado e pressione ENTER, salvando o valor digitado novamente na variável nome.

Por fim, uma nova mensagem é exibida na tela com o novo nome informado (o novo valor da variável
nome).

Dica: Sempre que o usuário tiver que digitar alguma coisa no teclado do computador, é conveniente exibir
uma informação antes, para que uma mensagem seja exibida na tela e o usuário saiba o que é que ele deve
digitar. Por exemplo:
System.out.println(“Digite sua idade: “);
int idade = teclado.nextInt();

9
Cálculos matemáticos mais avançados
Sempre que criamos uma expressão matemática, precisamos nos atentar à ordem de prioridade dos
operadores aritméticos.

As expressões matemáticas sempre são executadas da esquerda para a direita. Por exemplo:

5+3+2+1

faz com que inicialmente seja calculado 5+3 e obtém-se o resultado 8. Em seguida, temos 8+2 com o
resultado 10. Em seguida, temos 10+1 que gera como resultado final o número 11.

Caso desejamos que esta ordem de execução seja modificada, precisamos utilizar parênteses nas
expressões. O funcionamento é equivalente na matemática: tudo o que estiver entre parênteses será
calculado primeiro. Por exemplo:]

(5 + 3) + (2 + 1)

faz com que 5+3 seja calculado com resultado 8 e depois que 2+1 seja calculado com resultado 3. Por fim,
temos que 8+3 seja calculado com resultado 11.

Precisamos entender a ordem de prioridade dos operadores:

• Multiplicação, Divisão e Resto são avaliados primeiro, da esquerda para a direita


• Soma e subtração são avaliados em seguida, da esquerda para a direita
• Atribuição de valores (=) para variáveis será executado por último, após já obter o resultado do
cálculo.

Considere o exemplo a seguir:

5+2*3/6

Nesta expressão, temos cálculo de soma, multiplicação e divisão e não temos o uso de parênteses para
definir a ordem dos operadores. Como as instruções são calculadas da esquerda para a direita e, ao mesmo
tempo, a multiplicação e divisão possuem prioridades iguais, inicialmente o calculo será feito com 2*3

5+2*3/6

5+ 6 /6

Em seguida, temos a divisão com o resultado de (2*3) por 6

5+ 6 /6

5+ 1

Por fim, temos a soma dos valores:

5+ 1

Desta forma, sempre que estivermos confusos sobre os cálculos, devemos utilizar os parênteses para definir
explicitamente a prioridade de execução. Por exemplo:

5 + ((2 * 3) / 6)
𝑎+𝑏+𝑐
Outro exemplo clássico se refere ao cálculo da média aritmética de 3 números: 3

10
Observe que neste caso, precisamos fazer a soma de a+b+c e o resultado desta soma será dividido por 3.

Caso a instrução fornecida seja

a+b+c/3

Inicialmente teríamos c/3 com maior prioridade e o resultado então seria somado ao restante da soma.
Como este não é o cálculo correto, então devemos primeiro fazer a soma e, só então, dividimos por 3:

(a + b + c) / 3

Para cálculos mais avançados, em especial os cálculos de trigonometria ou outras fórmulas mais avançadas
geralmente aplicadas à estatística ou à engenharias, a linguagem Java oferece uma classe chamada Math.
Como esta classe faz parte da linguagem padrão, ela não precisa ser importada para ser utilizada.

O que podemos fazer com Math?

• Calcular a raiz quadrada do valor informado (valor double)


Math.sqrt(valor)

• Calcular a base elevada ao expoente (valor double). Ex: Math.pow(2, 3) obtém o resultado 23
Math.pow(base, expoente)

• Calcular o seno do valor informado (valor double)


Math.sin(valor)

Por exemplo, um arquivo chamado Aula.java pode conter o seguinte código:


public class Aula {
public static void main(String[] args) {
int num1 = 9;
double v1 = Math.sqrt(num1);
System.out.println("A raiz quadrada de " + num1 + " é " + v1);
double v2 = Math.pow(5, 4);
System.out.println("5 elevado a 4 dá " + v2);
double v3 = Math.sin(90);
System.out.println("O seno de um angulo de 90 graus é " + v3);
}
}

Ao executar o programa acima, teremos como resultado:

A raiz quadrada de 9 é 3.0


5 elevado a 4 dá 625.0
O seno de um angulo de 90 graus é 0.8939966636005579

Dica: Observe que sempre colocamos o nome da classe Math seguida por um ponto . e depois pelo nome da
função que desejamos calcular. Observe também que as funções devem, obrigatoriamente, ter parênteses
após o seu nome. Passamos os valores necessários para este cálculo dentro dos parênteses.

Exemplo: result = Math.sqrt(16);


result = Math.pow(5, 2);

11
Outra classe interessante disponibilizada pela linguagem Java é a classe Random. Ela é utilizada para gerar
números aleatórios. Para usar esta classe e criarmos objetos que sejam capazes de sortear valores
aleatoriamente, esta classe precisa ser importada no início do programa com o comando
import java.util.Random;

e, no início do algoritmo, precisamos criar o objeto que será o responsável por sortear um número com o
comando
Random aleatorio = new Random();

Para sortear um número aleatório, precisamos informar o número máximo (de 0 até o número máximo) que
será sorteado. Desta forma, com a instrução:
int x = aleatorio.nextInt(10);

Fará o sorteio de um número qualquer entre 0 e 9. O valor sorteado será armazenado na variável x.

OBSERVAÇÃO: o número fornecido nos parênteses corresponde ao valor máximo e este valor não está
incluso no sorteio. Portanto, se for sortear de 0 a 10, precisamos informar o número 11.

Dica: temos como padrão que o primeiro número que pode ser sorteado é o número 0.

Desta forma, se tivermos aleatorio.nextInt(10), estamos dizendo ao algoritmo que o número a ser sorteado
pertence aos dez primeiros valores inteiros possíveis. Observe que {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} são dez valores.
Por isso o número 10 não entrará no sorteio, visto que de 0 a 9 temos 10 números.

Exemplo de código para sorteio de número aleatório onde o usuário informa o número máximo e o
algoritmo sorteia um valor, apresentando-o na tela.
import java.util.Random;
import java.util.Scanner;
public class Aula {
public static void main(String[] args) {
Random aleatorio = new Random();
Scanner teclado = new Scanner(System.in);
int maximo;
int sorteio;
System.out.println("Informe o valor máximo: ");
maximo = teclado.nextInt();
sorteio = aleatorio.nextInt(maximo);
System.out.println("Número sorteado: " + sorteio);
}
}

Agora imagine a seguinte situação: desejo que o algoritmo sorteie um número entre 5 e 10 (inclusos).

Temos que a faixa de valores que o algoritmo deseja sortear é {5, 6, 7, 8, 9, 10}, ou seja, temos 6 valores que
poderiam ser sorteados. Desta forma, utilizamos a instrução:
x = aleatorio.nextInt(6);

Entretanto, com a instrução acima, o valor da variável “x” poderá ser qualquer valor entre {0, 1, 2, 3, 4, 5}, ou
seja, sorteou um número aleatório entre os seis primeiros valores inteiros.

12
Como fazemos, então, para que os números sorteados fiquem entre 5 e 10 (inclusos)?

Observe a relação entre os valores:

Número sorteado Número que deveria ter sido sorteado


0 → 5
1 → 6
2 → 7
3 → 8
4 → 9
5 → 10

Ou seja, se sortear 0 (o menor número possível do sorteio), então temos que este valor deve ser equivalente
ao número 5 (o menor número possível do sorteio desejado), e assim sucessivamente. Portanto, basta
somar este “deslocamento” no número sorteado. Desta forma, temos:
x = aleatorio.nextInt(6) + 5;

Caso o valor sorteado seja 0, temos que 0+5 é 5. Logo, o valor sorteado foi o 5.
Caso o valor sorteado seja 1, temos que 1+5 é 6. Logo, o valor sorteado foi o 6.
Caso o valor sorteado seja 2, temos que 2+5 é 7. Logo, o valor sorteado foi o 7.
Caso o valor sorteado seja 3, temos que 3+5 é 8. Logo o valor sorteado foi o 8. E assim sucessivamente.

Operadores Relacionais
Já sabemos que variáveis booleanas armazenam apenas dois possíveis valores: true e false. Sabemos que o
valor true representa o que chamamos de verdadeiro e que o valor false representa o que chamamos de
falso.

Os operadores relacionais são utilizados para fazer comparações entre dois valores Eles são:

Descrição Operador
Maior que >
Menor que <
Maior ou igual a >=
Menor ou igual a <=
Diferente de !=
Igual a ==
O resultado do uso de operadores relacionais (efetuar comparações de valores) sempre será um valor
booleano true ou false. Por exemplo:

int x, y;
x = 10;
y = 20;
System.out.println( x < y ); //true, pois 10 < 20 é verdadeiro
System.out.println( x <= y ); //true
System.out.println( x > y ); //false
System.out.println( x >= y ); //false
System.out.println( x == y ); //false, 10==20 é falso (10 não é igual a 20)
System.out.println( x != y ); //true, 10!=20 é verdadeiro (10 não é 20)

13
Dica: Embora na versão mais atual do Java podermos utilizar o operador de igualdade == com valores
Strings, na linguagem Java com versões mais antigas esta não é a forma correta de se trabalhar.

Usamos os operadores relacionais com valores numéricos, caracteres ou booleanos, mas não para Strings.

A forma correta de se fazer comparações com valores String é utilizar, após o nome da variável, a instrução
.equals(“VALOR A SER COMPARADO”) ou então .equalsIgnoreCase(“VALOR”).

.equals() faz a comparação caractere a caractere. Diferencia letras maiúsculas de minúsculas

.equalsIgnoreCase() faz a comparação caractere e caractere. Não diferencia entre maiúsculas e


minúsculas
String nome = "Zezinho";
System.out.println( nome.equals("Zezinho") ); //true
System.out.println( nome.equalsIgnoreCase("zezinho") ); //true
System.out.println( !nome.equals("Zezinho") ); //false
System.out.println( !nome.equalsIgnoreCase("abcd") ); //true

Operadores lógicos
Os operadores lógicos são usados, em especial, quando temos uma comparação que envolve muitos valores
booleanos. Os operadores relacionais são:

Descrição Operador
E &&
Ou || *geralmente é a tecla ao lado do Z
Não !

Como usamos os operadores lógicos sempre para unir expressões lógicas (booleanas, valores true ou false),
o resultado também será um valor lógico (true ou false). Para saber se o resultado da expressão lógica é
verdadeiro ou falso, utilizamos as tabelas-verdade. Precisamos memorizar os resultados das tabelas-verdade
para os operadores E, OU e NÃO. A seguir, temos as tabelas verdades, onde V representa Verdadeiro (valor
true) e F representa Falso (valor false).

Tabela-verdade para && (e) A B A && B como ler a expressão?


true true true VeV=V
true false false VeF=F
false true false FeV=F
false false false FeF=F

Tabela-verdade para || (ou) A B A || B como ler a expressão?


true true true V ou V = V
true false true V ou F = V
false true true F ou T = V
false false false F ou F = F

Tabela-verdade para ! (não) A !(A) como ler a expressão?


true false não V = F
false true não F = T

14
Desta forma, considere as variáveis a = 10 e b = 20:
int a, b;
a = 10;
b = 20;
System.out.println( a > 0 && b > 30 );

O Código acima exibirá na tela o valor false, visto que:

• para a>0 temos 10 > 0 e o resultado da comparação será true.


• para b>30 temos 20 > 30 e o resultado da comparação será false.
• true && false temos que o resultado de true && false é sempre false.

Os operadores relacionais e os operadores lógicos são extremamente importantes quando desenvolvemos


algoritmos. Portanto, precisamos conhecê-los “de cor”, em especial os resultados das tabelas-verdade.
Usamos estes operadores na tomada de decisões, no controle de repetições, e muitas outras situações ao
criar diferentes estruturas de dados e estruturas de controle nos algoritmos.

Tomando decisões nos algoritmos


Para tomar decisões nos algoritmos, podemos fazer uso das estruturas condicionais (comandos de decisão).
Na linguagem Java, temos os seguintes comandos de decisão:

• Estrutura condicional simples


• Estrutura condicional composta
• Estrutura condicional com múltiplas alternativas

O comando if(condição) { } é utilizado na estrutura condicional simples: tomar decisões se um bloco de


instruções será ou não executado. Sempre que uma condição for verdadeira (true), então o bloco de
instruções (conjunto de comandos entre os sinais { e }) será executado. Desta forma, todas as instruções que
estão dentro do { bloco de instruções } fazem parte deste bloco de instruções. Por exemplo:
int x;
x = 10;
if(x > 0) {
System.out.println("Valor maior que zero");
}
System.out.println("Fim do programa");
No exemplo acima, temos que a variável x possui o valor 10. Na terceira linha temos uma comparação,
verificando se x for maior que zero, então o bloco de instruções do comando if será executado. Como 10 > 0
resulta em um valor true, então o bloco será executado e a mensagem “Valor maior que zero” será exibida
na tela do computador. Por fim, será exibida a mensagem “Fim do programa”.

Se no exemplo, a segunda linha tivesse a instrução x = 0, então o teste feito na segunda linha if(x>0)
utilizaria a comparação 0 > 0, resultando em um valor false. Portanto, o bloco de instruções não será
executado e o algoritmo pula para a primeira instrução fora do bloco, exibindo apenas a mensagem “Fim do
programa”. Portanto, caso a condição seja satisfeita, um conjunto de instruções adicionais será executado,
caso contrário, este conjunto será ignorado e o algoritmo segue seu fluxo normalmente nas instruções
definidas em seguida.

15
O comando if(condição){ } seguido por else{ } representa a estrutura de decisão composta. Observe que
temos dois blocos de instruções: um para o comando if e outro para o comando else. Neste caso, se o valor
da condição for avaliado como true, então é o bloco de instruções do comando if que será o escolhido para
ser executado, ignorando completamente o comando else.

Em contrapartida, caso o valor da condição seja avaliado como false, então é o bloco do comando if que será
ignorado. O algoritmo pula para o comando else e executa aquele bloco de instruções.

Por exemplo:
public class Exemplos {
public static void main(String args[]) {
int idade, dose;
idade = 3;
dose = 0;
if(idade <= 4) {
dose = 4;
}
else {
dose = 8;
}
System.out.println("A dose para criança de " + idade + " anos é de " +
dose + "ml");
System.out.println("Fim do programa");
}
}
Como o valor da variável idade é 3, então a comparação realizada no comando if para 3 <= 4 resulta em um
valor true. Desta forma, a dose receberá o valor 4 (o bloco definido pelo else não será executado, já que
executou o if). No caso do valor da idade ser, por exemplo, 10, então o teste 10<=4 será false e o if não será
executado, fazendo então que o bloco do else seja executado.

Por fim, temos a estrutura de decisão com múltiplas alternativas. Esta estrutura é definida pelos comandos
if(condição) {...} else if(condição) {...} else if(condição){...} else{...}. Observe que entre os comandos if e else
existem vários comandos else if(condição){...}. Utilizamos esta estrutura quando temos mais de uma
comparação.

Por exemplo:
String categoria = "";
int idade = 18;
if(idade < 5) {
categoria = "bebê";
}
else if(idade < 12) {
categoria = "criança";
}
else if(idade < 18) {
categoria = "adolescente";
}
else if(idade < 60) {
categoria = "adulto";

16
}
else{
categoria = "idoso";
}
System.out.println("Uma pessoa com " + idade + " anos de idade");
System.out.println("é considerado " + categoria);

A variável categoria é usada para armazenar um texto que indica qual a categoria de idade que uma pessoa
pertence. A variável idade representa a idade de uma pessoa.

O primeiro comando da tomada de decisão sempre será o comando if(condição){ }. Caso a condição seja
satisfeita, então este bloco será executado.

Se a condição for false, então o próximo comando else if(condição){ } será verificado. Caso o valor da nova
condição seja true, então este será o bloco escolhido para ser executado.

No caso do valor ser false, então o algoritmo segue testando o próximo else if(condição){ }.

Apenas no caso de nenhuma das condições anteriores serem satisfeitas, o bloco do comando else{ } será
executado.

Como no exemplo acima a variável idade tem o valor 18, então o primeiro teste (comando if) será false, o
próximo comando a ser testado (comando else if) também será false, o terceiro teste será feito (comando
else if) e também receberá resultado fase e, por fim, o próximo teste será feito na condição do último
comando else if obtendo como resultado true e, portanto, este bloco será executado, atribuindo à variável
categoria o valor “adulto”.

Estruturas de Repetição
Utilizamos os comandos de repetição quando desejamos que um conjunto de instruções seja executado
repetidamente. Na linguagem Java, dois comandos de repetição são usados com maior frequência:

• for: para laços contados


• while: para laços contados e para laços controlados por sentinela

Um laço de repetição contado diz respeito à repetição de um bloco de instruções por um número pré-
determinado de vezes. Por exemplo, se eu desejo exibir na tela uma mensagem por 10 vezes, eu sei que são
10 vezes e posso indicar ao algoritmo que a instrução deve ser executada repetidamente, por 10 vezes.

A sintaxe do comando for é a seguinte. Observe que são três informações necessárias para que possamos
executar as repetições por um número determinado de vezes e estas informações são separadas por ponto-
e-vírgula:

for ( inicialização ; condição lógica ; incremento ) {

instruções que serão executadas na repetição

Vamos a alguns exemplos:

17
Exemplo 1: exibir na tela a mensagem “Bom dia!” por 10 vezes.
for(int cont = 0; cont < 10; cont++) {
System.out.println("Bom dia!");
}

No trecho do algoritmo acima, inicialmente temos que

int cont = 0 inicialização da variável usada para contar (cont começa com 0)

Em seguida, temos a condição para que a repetição seja executada

cont < 10 condição lógica diz que o bloco será executado caso cont < 10

Como o valor 0 < 10 resulta em true, então o bloco de instruções será executado e a mensagem “Bom dia!”
será exibida na tela.

Ao terminar de executar o bloco de instruções, o algoritmo retorna no comando for. Mas agora ele retorna
na última parte do comando, que tem a instrução

cont++ incremento que modifica o valor da variável usada para contar

Esta instrução cont++ é uma forma abreviada de dizer cont = cont + 1 ou cont += 1, ou seja, cont++ indica
que o valor da variavel cont será aumentado em uma unidade. Como cont valia zero na primeira repetição,
então agora temos que cont vale um.

O teste é refeito, onde 1 < 10 resulta em valor true indicando que o bloco de instruções deverá ser
executado. Então a mensagem “Bom dia!” será exibida na tela.

Ao exibir a mensagem, o algoritmo retorna no comando for e cont++ atualizará o valor de cont para 3. Como
a condição 3 < 10 é true, então novamente a mensagem será exibida. Novamente o algoritmo retorna no
comando for, cont será atualizado e o teste será refeito. Este processo de “incrementar” e “testar” será
executado sempre que o algoritmo retornar ao comando for, até que a condição seja falsa e a repetição
finalizada.

Exemplo 2: Solicitar por 50 números ao usuário e, a cada número informado, mostrar na tela o seu dobro.
Scanner teclado = new Scanner(System.in);
int entrada;
int dobro;
for(int cont = 1; cont <= 50; cont++) {
System.out.println("Informe um número:");
entrada = teclado.nextInt();
dobro = entrada * 2;
System.out.println("O dobro de " + entrada + " é " + dobro);
}
Neste exemplo, a variável cont começa com o valor 1 e a repetição ocorrerá até que a condição seja falsa, ou
seja, até que o valor de cont seja maior que 50. Veja que a repetição ocorre enquanto cont <= 50, então se
cont for 51, 51 <= 50 resulta em false. A cada vez que o bloco de instruções for executado, o valor de cont é
atualizado em mais um com a instrução cont++.

O algoritmo exibe a mensagem “Informe um número:”, o usuário digita um número, é calculado o dobro
deste número e a mensagem “O dobro de ENTRADA é DOBRO” é exibida na tela (ENTRADA e DOBRO se
refem aos valores das variáveis). Desta forma, se o usuário digitou 5, a mensagem “O dobro de 5 é 10” será
exibida na tela.

18
O algoritmo irá executar o bloco de instruções por 50 vezes. Repare que cont começa com 1 e vai crescendo
de um em um (2, 3, 4, 5, 6 …). Observe que a condição cont <= 50 diz que se o valor de cont for 50, então o
bloco de instruções ainda será executado.

Se a condição fosse cont < 50, então como cont começa com 1, seriam executadas apenas 49 repetições.
Para corrigir o problema, a condição deveria ser cont < 51, ou então iniciar a contagem em 0.

Exemplo 3: Exibir na tela os números de 20 a 0.


for(int cont = 20; cont >= 0; cont--) {
System.out.println(cont);
}

Observe que neste exemplo, a contagem está invertida. Ela deve começar com 20, logo

int cont = 20

Como a contagem é invertida, então ela deve ir diminuindo o valor da contagem de um em um. Então aqui
podemos utilizar a instrução cont = cont – 1 para ir decrementando o valor, ou a sua forma resumida:

cont--

Outro ponto a ser observado é na condição para a execução. Aqui, a repetição deve acontecer até que o
valor de cont se torne zero, então a condição

cont >= 0

deve ser usada, garantindo que a repetição seja executada para qualquer valor de cont maior ou igual a zero

Dica: observe que a repetição precisa terminar em algum momento. Como ela é invertida (do maior para o
menor), e como o valor deve seguir diminuindo o valor do contador, a condição deve dizer que em algum
momento o valor da variável se tornará negativo.

Outra forma semelhante de criarmos estruturas com repetição contada é utilizando o comando while. As
três partes do comando for (inicialização, incremento e repetição) também precisam estar presentes, mas
estas instruções não são definidas de uma só vez, como no comando for. A sintaxe é:

Inicialização;
while ( condição lógica ) {
instruções que serão executadas na repetição
incremento;
}

Por exemplo, para contar de 1 até 10, podemos ter o seguinte código:
public class Repeticao {
public static void main(String[] args) {
int cont = 1; //inicialização

while(cont <= 10) { //condição para executar


System.out.println(cont);
cont = cont + 1; //incremento
}
}
}

19
Inicialmente temos que cont = 1. Em seguida, temos uma condição cont <= 10. Ao substituir o valor de cont
pelo seu valor, a comparação 1 <= 10 será true e, então, o bloco de instruções será executado.

A primeira instrução exibirá na tela o valor atual de cont, ou seja, 1. A segunda instrução da repetição faz
com que o valor de cont seja atualizado em uma unidade, logo, cont = 2.

O algoritmo retorna na linha do comando while e a condição é testada novamente. Como 2 <= 10, o
resultado true é obtido e novamente o bloco de instruções será executado.

A primeira instrução exibirá na tela o valor atual de cont, ou seja, 2. A segunda instrução da repetição faz
com que o valor de cont seja atualizado em uma unidade, logo, cont = 3.

O algoritmo retorna na linha do comando while e a condição é testada novamente. Como 3 <= 10, o
resultado true é obtido e novamente o bloco de instruções será executado.

Este processo irá ficar repetindo até que o valor de cont seja 11. Assim, ao retornar na linha do comando
while, ao testar 11 <= 10, o resultado obtido será false e, neste momento, o laço de repetição é finalizado.

Considere um segundo exemplo. O usuário deve digitar cinco números e, ao final, devemos apresentar a
soma dos cinco números informados.

Sabemos que a variável contadora deve inciar em 1, visto que o usuário ainda digitará o primeiro valor. A
condição para que a repetição aconteça é que, enquanto o contador for menor ou igual a 5, deve
permanecer digitando números. Como estamos contando de um em um, a variável contadora deve ser
atualizada em uma unidade a cada repetição.

Precisamos da variável de entrada do número que o usuário irá digitar, e também precisamos de uma outra
variável que irá armazenar a soma de todos os números.
import java.util.Scanner;
public class Repeticao {
public static void main(String[] args) {
Scanner teclado = new Scanner(System.in);
int cont, entrada, soma;
soma = 0;
cont = 1;
while(cont <= 5) {
System.out.println("Informe o número " + cont + ": ");
entrada= teclado.nextInt();
soma = soma + entrada;
cont = cont + 1;
}
System.out.println("A soma de todos os números foi: " + soma);
}
}
No algoritmo acima, criamos as variáveis que representam o teclado do computador, o contador da
repetição, a entrada de dados do usuário e a variável que armazenará a soma de todos os valores. A soma é
inicializada em 0, pois ainda não temos nenhum valor informado.

O contador é inicializado em 1, pois iremos digitar cinco números e este valor indica que o primeiro número
será informado.

A condição diz que: enquanto o valor da variável cont for menor ou igual a 5, então a repetição irá ser
executada.

20
Nesta repetição, uma mensagem será exibida na tela, o usuário digita um valor, este valor será incluído na
variável soma e a variável contadora irá para o próximo número. Após a execução do bloco de instruções, o
algoritmo retorna ao comando while para testar novamente se irá continuar executando ou não o bloco de
instruções. Ao informar os cinco números, o laço de repetição irá ser finalizado e então uma mensagem será
exibida na tela.

O comando while ainda permite definirmos repetições por uma quantia indefinida de vezes, ou seja, a
repetição ficará acontecendo até que uma determinada situação ocorra. Este controle determinando se a
repetição acontecerá ou não é feito por uma variável (variável sentinela). Dependendo do valor desta
variável, então o bloco de instruções será executado ou o laço de repetição será finalizado.

Considere o seguinte exemplo: O usuário deve permanecer informando números inteiros ao algoritmo, até
que ele informe o número 0.
import java.util.Scanner;
public class Repeticao {
public static void main(String[] args) {
Scanner teclado = new Scanner(System.in);
int entrada = 1;
while(entrada != 0) {
System.out.println("Informe o número :");
entrada= teclado.nextInt();
}
System.out.println("Fim do algoritmo");
}
}
No algoritmo acima, inicialmente foram declarados as variáveis que representam o teclado do computador e
a entrada de dados pelo usuário. Observe que a variável de entrada foi inicializada com o valor 1.

Observe ainda que a condição para que o laço de repetição seja executado é o valor da variável entrada seja
diferente de zero. Logo, se o valor da entrada for diferente de zero, a repetição ocorre. Se for igual a zero, a
repetição não será executada. Por este motivo, iniciamos a variável com o valor 1: para garantir que o laço
de repetição seja executado pelo menos uma vez (até que usuário digite um valor). Repare que qualquer
valor que atribuíssemos a esta variável, sendo diferente de zero, resolveria o problema para garantir que o
laço de repetição fosse executado, mas nem sempre isto ocorre. Por isso é importante o PLANEJAMENTO do
algoritmo antes da sua implementação.

Ao entrar no laço de repetição, solicitamos por um número. Imagine que o valor digitado foi 5, logo, entrada
= 5. A repetição retorna na condição e faz o teste 5 != 0 e o resultado é true, logo, a repetição será executada
novamente. Um novo valor será informado. Imagine que o usuário tenha digitado 10, logo, entrada = 10. Ao
retornar na condição, temos que 10 != 0 é true e novamente um novo valor vai ser solicitado ao usuário. Se o
usuário digitar 0, temos que entrada = 0. Ao retornar na condição, o teste 0 != 0 vai gerar false e, desta
forma, a repetição será finalizada.

Perceba que aqui a variável entrada atua como o “sentinela”, estabelecendo se a repetição irá ser executada
ou não. Tudo depende do valor desta variável.

21
Vamos Praticar?
Tente resolver os seguintes algoritmos sozinho, individualmente. Caso não consiga, solicite auxílio aos
colegas e aos professores, mas não obtenha as respostas. Tente conseguir dicas de como resolver.

Após resolver os exercícios, aguarde um dia e tente resolvê-los novamente você mesmo, mas agora sem
utilizar as respostas e dicas como consulta. Se conseguiu resolver todos os exercícios sozinho, então você
está aprendendo o conteúdo!

Exercício 01: Um sistema de vendas (supermercado, lojas de vestuário, etc.) deve controlar os valores pagos
pela compra e os valores a serem dados como troco aos clientes. Implemente um algoritmo que solicite o
valor da compra e o valor que o cliente pagou. O algoritmo deve calcular e apresentar o valor do troco.

Exercício 02: Imagine um sistema de vendas que comercializa produtos vendidos por quilos (ex: carne,
queijo, presunto, etc.). Existe um valor fixo com o preço do quilo e o cliente irá pagar o valor proporcional à
quantia do produto que ele deseja comprar (ex: 300g de queijo, 1,5kg de carne, etc.). Implemente um
programa que solicite ao usuário o nome do produto, o preço do quilo e a quantia de gramas deste produto
que o cliente deseja comprar. Calcule e apresente na tela o valor a ser pago pelo cliente.

Exercício 03: Escreva um algoritmo que solicite ao usuário por 4 números ponto-flutuante. Calcule e
apresente na tela o maior dos números informados.

Exercício 04: Escreva um algoritmo que solicite ao usuário por um número inteiro. Apresente na tela se este
número é par ou ímpar.

Exercício 05: Escreva um algoritmo que solicite ao usuário por um número inteiro. Apresente na tela se este
número é múltiplo de 5.

Exercício 06: Escreva um algoritmo que solicite 3 números ao usuário representando os três lados, ou ângulo
(interno), de um triângulo. O algoritmo deve apresentar na tela uma mensagem dizendo se:

• Forma um triângulo equilátero (os 3 lados são iguais)


• Forma um triângulo isósceles (apenas 2 lados são iguais)
• Forma um triângulo escaleno (os 3 lados são diferentes)
• Não forma um triângulo.

Sabe-se que para 3 medidas representarem um triângulo: (i) nenhum dos lados pode ser igual a 0; (ii) a soma
destes três lados deve ser igual a 180º e, (iii) que a soma de dois lados deve ser maior que o outro lado.

Exercício 07: implemente um algoritmo que solicite ao usuário por um número inteiro. O algoritmo deve
exibir na tela a mensagem “Repetindo” pela quantia de vezes informada pelo usuário.

Exercício 08: Escreva um programa que solicite ao usuário por 10 números (utilize uma estrutura de
repetição para solicitiar um número a cada iteração). Após informar os números, o algoritmo deve
apresentar na tela a soma de todos os números informados.

Exercício 09: Escreva um programa que solicite ao usuário por 8 números (utilize uma estrutura de repetição
para solicitiar um número a cada iteração). Após informar os números, o algoritmo deve apresentar na tela
qual foi o maior número informado pelo usuário.

22
Exercício 10: Escreva um programa que solicite ao usuário por 8 números (utilize uma estrutura de repetição
para solicitiar um número a cada iteração). Após informar os números, o algoritmo deve apresentar na tela
qual foi o maior número e o menor número informados pelo usuário.

Exercício 11: Escreva um programa que solicite ao usuário por uma quantia de valores que ele deseja
fornecer. O algoritmo deve, então, solicitar por estes valores (utilize uma estrutura de repetição para
solicitiar um número a cada iteração). Após informar os números, o algoritmo deve calcular e apresentar na
tela qual foi a média aritmética dos números fornecidos.

Exercício 12: Imagine que b e h sejam arestas representando a base e a altura de um retângulo,
respectivamente. Implemente um algoritmo que solicite ao usuário pelos valores das arestas b e h
representando um retângulo. O algoritmo deve calcular e apresentar na tela a área deste retângulo e seu
perímetro.

Pesquise no Google quais são as fórmulas para o cálculo da área e do perímetro de um retângulo.

Exercício 13 (cont Exercício 12): A diagonal de um retângulo é uma reta que divide o retângulo em dois.
Utilizendo a base b e a altura h do retângulo, implemente um algoritmo que calcule e apresente na tela a
diagonal deste retângulo (Teorema de Pitágoras). Pesquise pela fórmula da diagonal do retângulo no Google.

Exercício 14: Uma instituição deseja fazer uma eleição para decidir quem será o novo diretor. Sabe-se que
são 4 candidatos e cada candidato é representado por um código (1, 2, 3 e 4). A urna é eletrônica e os
funcionários desta instituição devem votar:

• 1, 2, 3 ou 4 = voto para os respectivos candidatos (ex: se votou no código 2 então o segundo


candidato recebe um voto)
• 5 = voto nulo
• Qualquer outro valor = voto em branco

Implemente um software que seja capaz de solicitar ao usuário pelo número total de funcionários que
votarão nesta eleição. Em seguida, o software deve solicitar pelos votos de seus funcionários, um a um
(exiba uma mensagem na tela “Informe o código do candidato:” e o funcionário informará um número). Ao
final da eleição, após todos os funcionários já terem votado, o algoritmo deve apresentar na tela um
relatório com o total de votos em cada candidato, total de votos nulos, total de votos em branco e
apresentar também qual foi o candidato vencedor da eleição.

23
2. Subprogramação

Objetivos de aprendizagem
Este capítulo tem como objetivo:

• Desenvolver algoritmos modulares por meio da criação


de procedimentos e funções
• Utilizar a passagem de parâmetros aos procedimentos e
funções com dados necessários para suas execuções
• Obter retorno de valores das funções

O conteúdo trabalhado neste capítulo aborda:

• Subprogramação: procedimentos e funções


• Passagem de parâmetros
• Retorno de valores
• Variáveis locais e variáveis globais

24
Subprogramação (modularização de códigos)

Subprogramas (também conhecidas como sub-rotinas, sub-algoritmos, módulos ou métodos) são blocos de
instruções que desempenham alguma tarefa específica. Utilizamos os subprogramas para dividir um
problema maior em problemas menores que são mais fáceis de desenvolver.

Existem dois tipos de subprogramas: procedimentos e funções.

OBSERVAÇÃO: Em linguagens orientadas a objetos (ex: Java), os subprogramas não são chamados de
procedimentos ou funções, mas sim de métodos.

Um subprograma pode chamar outros subprogramas, criando um programa completo. A forma correta de se
implementar um subprograma é que ele seja independente de outros subprogramas. Por exemplo: existe a
necessidade no algoritmo de se calcular a média de 4 valores. Desta forma, um subprograma pode ser
construído apenas para se efetuar este cálculo. O processo de aquisição dos 4 valores não é função deste
subprograma. A forma com que os dados serão apresentados ao usuário também não faz parte deste
subprograma. Sua função é, tendo-se os 4 valores, apenas calcular a média.

Considere um subprograma responsável por solicitar por 4 valores ao usuário. Desta forma, a sua
implementação apenas se concentra nesta entrada de dados e mais nada.

Considere um subprograma responsável por calcular a média entre 4 valores. Desta forma, parte-se do
princípio de que os 4 valores já são conhecidos e, portanto, apenas o cálculo será realizado.

Considere um subprograma responsável por apresentar ao usuário o valor da média. Desta forma, a forma
com que os números foram informados, bem como a forma com que a média foi calculada, não importam
para este subprograma. Sua função é, tendo-se o valor da média, apenas exibi-lo ao usuário.

Separando os algoritmos em subprogramas (sub-algoritmos), a implementação dos algoritmos se torna mais


modular, mais simples e mais fácil de identificar erros e corrigi-los. Por exemplo: tendo-se os 4 números,
observou-se que a média apresenta um valor incorreto. Desta forma, sabemos exatamente qual parte do
código está com problema (no cálculo da média) e basta corrigir o subprograma responsável por esta função.

Procedimentos
Os procedimentos consistem em blocos de instruções que são identificados por um nome dentro do
algoritmo. Sempre que o bloco de instruções precisa ser executado, basta chamá-lo informando o seu nome.

Para se criar procedimentos, precisamos declará-los e implementá-los. Para que os procedimentos sejam
executados, precisamos chamá-los (ou invocá-los).

A sintaxe necessária para se declarar um procedimento é:


public static void <NOME_DO_PROCEDIMENTO> ( ) {
//conjunto de instruções do procedimento
}

25
Para se chamar este procedimento e executar suas instruções, a sintaxe é:
<NOME_DO_PROCEDIMENTO> ( );

Por exemplo, considere um procedimento chamado exibirDataAtual cuja função é exibir na tela do
computador a data atual formada pelo dia, mês e ano:
public static void exibirDataAtual() {
Date data = new Date();
int dia = data.getDate();
int mes = data.getMonth() + 1;
int ano = data.getYear() + 1900;
System.out.println("Data: " + dia + "/" + mes + "/" + ano);
}

Ao implementar o procedimento, sua única tarefa é exibir a data atual. Desta forma, obtém-se os dados do
dia, do mês e do ano e, a partir destes dados, é possível apresentá-los.

Para que o procedimento seja executado, em algum local do algoritmo (no método principal ou em outros
métodos), basta chamá-lo:
exibirDataAtual();

O algoritmo completo será:


import java.util.Date;
public class Exercicio {

public static void exibirDataAtual() {


Date data = new Date();
int dia = data.getDate();
int mes = data.getMonth() + 1;
int ano = data.getYear() + 1900;
System.out.println("Data: " + dia + "/" + mes + "/" + ano);
}

public static void main(String[] args) {


exibirDataAtual();
}
}
Observe que no método principal o procedimento exibirDataAtual() foi chamado. Neste ponto, o fluxo de
execução do algoritmo faz um “desvio” e segue a execução do procedimento. Um objeto capaz de obter a
data atual do computador é criado, os dados do dia, mês e ano são obtidos, e a mensagem com a data é
exibida. Ao concluir a execução do procedimento, o algoritmo faz um “desvio” retornando ao seu ponto de
chamada no método principal. O algoritmo então é finalizado.

26
Método Método
main() exibirDataAtual()

Podemos ter inúmeros procedimentos no nosso algoritmo. Um procedimento pode chamar diversos outros
procedimentos. Observe o exemplo abaixo:
import java.util.Date;
public class Exercicio {

public static void exibirDataAtual() {


Date data = new Date();
int dia = data.getDate();
int mes = data.getMonth() + 1;
int ano = data.getYear() + 1900;
System.out.println("Data: " + dia + "/" + mes + "/" + ano);
}

public static void exibirMensagens() {


System.out.println("Estamos criando procedimentos");
System.out.println("Utilizando a linguagem Java");
exibirDataAtual();
}

public static void main(String[] args) {


exibirMensagens();
exibirDataAtual();
}
}

Ao executar o algoritmo, o método principal (método main) é chamado. A primeira instrução (1) é a
chamada ao procedimento exibirMensagens() que exibe duas mensagens na tela do computador e chama (2)
outro procedimento exibirDataAtual(). Ao finalizar sua execução, o algoritmo retorna (3) ao
exibirMensagens() e, como o procedimento terminou sua execução, o fluxo retorna (4) ao método principal.
A próxima instrução do método principal chama (5) o método exibirDataAtual() que novamente exibirá a
data atual do sistema. Ao finalizar sua execução, o fluxo retorna (6) ao método principal e o programa é
então finalizado.

Método Método
main() 1 exibirMensagens()

4 2
Método
3
exibirDataAtual()
5

27
Procedimentos com passagem de Parâmetros
Ao chamarmos um procedimento, podemos fornecer parâmetros. Os parâmetros são informações que são
necessárias para que o procedimento possa executar suas funções. Por exemplo: considere um
procedimento que seja capaz de somar dois números e apresentar na tela o resultado da soma. Para que o
procedimento possa ser executado, os dois números precisam existir, caso contrário, não será possível
executar este procedimento.

Outro exemplo: podemos querer calcular a raiz quadrada de um número. Mas se não soubermos qual será
este número, não será possível efetuar o cálculo.

Outro exemplo: podemos ter um procedimento responsável por cadastrar um cliente no banco de dados.
Entretanto, se não tivermos os dados do cliente (nome, endereço, sexo, telefone, etc.), o procedimento não
poderá ser executado.

Quando estamos declarando e implementando os procedimentos que necessitam de parâmetros (valores)


para serem processados, cada valor a ser fornecido é representado por uma variável declarada dentro dos
parênteses. Por exemplo:
public static void calcularSoma(int n1, int n2) {
int soma = n1 + n2;
System.out.println("A soma foi: " + soma);
}

Observe no exemplo acima que dentro dos parênteses na declaração do procedimento duas variáveis foram
declaradas: n1 e n2 (separadas por vírgula). Como na definição do procedimento foi exigido dois números
inteiros, ao chamar este procedimento, estes dois números devem ser fornecidos. Por exemplo:
calcularSoma(10, 20);

Ao chamar o procedimento calcularSoma() fornecendo o primeiro valor 10 e o segundo valor 20, então a
variável n1=10 e n2=20. Neste momento o procedimento pode ser executado. O código completo do
algoritmo com os dois valores solicitados ao usuário é:
import javax.swing.JOptionPane;
public class Exercicio {

public static void calcularSoma(int n1, int n2) {


int soma = n1 + n2;
System.out.println("A soma foi: " + soma);
}

public static void main(String[] args) {


int a = Integer.parseInt(JOptionPane.showInputDialog("Primeiro valor:"));
int b = Integer.parseInt(JOptionPane.showInputDialog("Segundo valor:"));
calcularSoma(a, b);
}
}

No exemplo acima, inicialmente o método main será executado. Nele, dois números serão fornecidos pelo
usuário e estes dois valores serão passados por parâmetro ao método responsável por calcular a soma.
Desta forma, o parâmetro n1 terá o valor digitado para a variável a; e o parâmetro n2 receberá o valor da
variável b.

28
Dica: Podemos utilizar o JOptionPane.showInputDialog(“Mensagem”) para entrada de dados via teclado. Ao
invés de trabalhar com texto puro, o JOptionPane exibe uma janelinha gráfica para que o usuário informe os
valores. Entretanto, todos os valores informados são Strings e eles precisam ser convertidos para o tipo de
dado apropriado. Portanto, veja como fazer a leitura de valores para cada tipo de dado:
String a = JOptionPane.showInputDialog("Pergunta");
char b = JOptionPane.showInputDialog("Pergunta").charAt(0);

int a = Integer.parseInt(JOptionPane.showInputDialog("Pergunta"));
double b = Double.parseDouble(JOptionPane.showInputDialog("Pergunta"));
boolean c = Boolean.parseBoolean(JOptionPane.showInputDialog("Perg.?"));

Funções
O termo função é bastante utilizado na matemática. Geralmente ele recebe um argumento e produz um valor
como resultado. Por exemplo:
𝑥2
𝑓(𝑥) =
2
Temos que f é o nome da função e x é o argumento (parâmetro). Para avaliar a função, se tivermos f(3), temos
32 9
que 2
= 2 = 4.5.

Uma função pode ter vários argumentos (parâmetros). Por exemplo:


𝑥+𝑦+𝑧
𝑚𝑒𝑑𝑖𝑎(𝑥, 𝑦, 𝑧) =
3
A função media precisa de três argumentos para ser executada: valores para x, y e z. Portanto, se tivermos a
10+8+9.2 27.2
chamada 𝑚𝑒𝑑𝑖𝑎(10, 8, 9.2), vamos obter como resposta 3
= 3
= 9.07.

Observando este mesmo conceito de funções usado na matemática, podemos cria-lo em uma linguagem de
programação. Uma função funciona da mesma forma que um procedimento, ou seja, é um bloco de instruções
que possui um nome e também pode receber parâmetros (argumentos). Entretanto, NÃO PODEMOS mais
utilizar a palavra void. No lugar da palavra void, precisamos colocar um tipo de dado (int, double, String, char,
boolean, ou algum outro objeto da linguagem) que representa o resultado gerado pela função.

Conforme apresentado, considere que uma função deva ser capaz de efetuar a soma de três números inteiros.
O resultado desta soma também será um número inteiro e, portanto, a função fornece como resultado um
número inteiro (a soma dos números). Esta função poderia ser declarada como:

public static int somarNumeros(int a, int b, int c){


//Código de implementação da função
}

Observe que neste ponto, não usamos mais a palavra void. Agora usamos a palavra int que indica que quando
a função somarNumeros for chamada, ela terá como resultado um número inteiro.

29
Quando implementamos uma função na linguagem de programação, utilizamos um comando novo chamado
return. Este comando é o que estabelece o resultado final da função. Toda função precisa retornar um valor,
visto que toda função possui um valor. Observe o exemplo abaixo:

public static int somarNumeros(int a, int b, int c){


int soma = a + b + c;
return soma;
}

Ao chamar a função somarNumeros, um cálculo foi feito e, na última linha, um valor foi retornado. Ou seja, o
valor (o resultado obtido) da chamada da função somarNumeros é estabelecido pelo comando return soma;.
Observe também que na declaração da função (public static int) foi dito que a função representa um número
inteiro e que o valor retornado foi soma e que esta variável também é um número int. Portanto, a função foi
definida corretamente: na declaração dizia que seria produzido como resultado um número inteiro e o
resultado retornado foi um número inteiro.

Outra diferença no uso de funções em linguagem de programação é no momento em que o subalgoritmo é


chamado para ser executado. No caso dos procedimentos, apenas chamamos pelo nome e fornecemos os
parâmetros. Por exemplo:
executarAlgo();

No caso da função, como ela possui um valor (não é void), este valor deve ser armazenado em alguma variável
para que possa ser processado posteriormente. Portanto, no caso da função, temos:
int resultado = somarNumeros(10, 20, 30);

Repare que inicialmente é executado a expressão do lado da direita do sinal de atribuição (=). Portanto,
somarNumeros(10, 20, 30) será chamado e o valor retornado será 60. Portanto, somarNumeros(10,20,30) =
60. Desta forma, temos que int resultado = 60;

Comparando Procedimentos e funções


Definição Chamada
public static void exibirSoma(int a, int b){
int soma = a + b;
Procedimento System.out.println(“Soma: ” + soma);
exibirSoma(10, 20);
}
public static int obterSoma(int a, int b){
int soma = a + b; int result = obterSoma(10, 20);
Função return soma; System.out.println(“Resultado: ” + result);
}

OBSERVAÇÃO: os termos procedimento e função são geralmente utilizadas em algoritmos e em linguagens


de programação mais simples (ex: Pascal, VisualG, etc.). Algumas linguagens utilizam apenas o nome de
função tanto para procedimentos quanto para funções, sendo elas void ou de algum tipo de dado (ex: C,
PHP, etc.). Já as linguagens mais atuais e orientadas a objetos, tal como Java, o nome utilizado é método.
Podemos ter os métodos void (procedimentos) e os métodos que retornam valores int, String, double, etc.
(funções).

30
Recursividade
A recursividade diz respeito a quando um subalgoritmo faz uma chamada a ele mesmo.

Imagine a situação: Temos uma função calcular() que, dentro dela, faz a invocação da função calcular().

public static void calcular() {


//instrução 1
//instruçaõ 2
calcular();
//outras instruções
}
public static void main(String args[]){
calcular();
}

Imagine outra situação: Temos uma função obterValor() que, dentro dela, chama a função
exibirMensagem() que, por sua vez, chama a função obterValor().

public static void exibirMensageM(){


//instrução 1
//instruçaõ 2
obterValor();
//outras instruções
}
public static void obterValor() {
//instrução 1
//instruçaõ 2
exibirMensagem();
//outras instruções
}
public static void main(String args[]){
calcular();
}

Observe que existe um loop que nunca será finalizado em cada uma destas situações. Quando uma função A
chama a si mesma, dizemos que a recursão é direta. Quando uma função A chama outra função B que, por
sua vez, chama a função A, dizemos que a recursão é indireta.

Ao implementar uma função recursiva, precisamos pensar sempre qual será a condição de parada. Esta
condição indica ao nosso algoritmo quando é que a função vai deixar de chamá-la, finalizando este looping
de invocações.

Exemplos 1: Pretendemos fazer a soma de todos os números de 8 até 1, ou seja, desejamos obter
8+7+6+5+4+3+2+1.

Da forma tradicional, utilizando estrutura de repetição, podemos ter o seguinte algoritmo para solucionar o
problema:
31
public class SomandoValores {
public static void main(String[] args) {
int soma = 0;
for(int i = 8; i > 0; i--) {
soma = soma + i;
}
System.out.println("A soma de 8 até 1 é " + soma);

}
}

Para implementar esta função de somar os valores, podemos utilizar a função recursiva. Exemplo:
public class SomaRecursiva {
public static int somar(int x) {
if(x > 0) {
return x + somar(x-1);
}
else {
return 0;
}
}
public static void main(String[] args) {
int soma = somar(8);
System.out.println("A soma de 8 até 1 é " + soma);

}
}

Para a execução da função recursiva, temos uma “pilha de execução”. O algoritmo é executado passo-a-
passo. Observe:

• Na função principal, a variável soma recebe o resultado da função somar(8);


• Ao executar a função somar(int x), o valor da variável do parâmetro x vale 8
o O teste lógico 8>0 possui valor true, logo, o comando if será executado
▪ A função retorna o valor 8 + somar(7). Observe que no retorno temos uma nova
chamada da mesma função. Então na pilha de execução, o retorno será
8 + somar(7)
• Ao executar a função somar(int x), o valor da variável do parâmetro x vale 7
o O teste lógico 7>0 possui valor true, logo, o comando if será executado
▪ A função retorna o valor 7 + somar(6). Observe que no retorno temos uma nova
chamada da mesma função. Então na pilha de execução, o retorno terá
8 + somar(7) (da primeira execução)
8 + 7 + somar(6) (da segunda execução)

• Ao executar a função somar(int x), o valor da variável do parâmetro x vale 6


o O teste lógico 6>0 possui valor true, logo, o comando if será executado
▪ A função retorna o valor 6 + somar(5). Observe que no retorno temos uma nova
chamada da mesma função. Então na pilha de execução, o retorno terá
8 + somar(7) (da primeira execução)
8 + 7 + somar(6) (da segunda execução)
8 + 7 + 6 + somar(5) (da terceira execução execução)

• O processo segue “empilhando” o valor a ser retornado:

32
8 + somar(7) (da primeira execução)
8 + 7 + somar(6) (da segunda execução)
8 + 7 + 6 + somar(5) (da terceira execução)
8 + 7 + 6 + 5 + somar(4) (da quarta execução)
8 + 7 + 6 + 5 + 4 + somar(3) (da quinta execução)
8 + 7 + 6 + 5 + 4 + 3 + somar(2) (da sexta execução)
8 + 7 + 6 + 5 + 4 + 3 + 2 + somar(1) (da sétima execução)
8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + somar(0) (da oitava execução)
• Ao executar a função somar(int x) neste momento, o valor da variável do parâmetro x vale 0
o O teste lógico 0>0 possui valor false, logo, o comando else será executado
▪ A função retorna o valor 0. Observe que neste retorno não temos a chamada da
mesma função. Ela retorna um único valor e só. Então, na pilha de execução temos:
8 + somar(7)
8 + 7 + somar(6)
8 + 7 + 6 + somar(5)
8 + 7 + 6 + 5 + somar(4)
8 + 7 + 6 + 5 + 4 + somar(3)
8 + 7 + 6 + 5 + 4 + 3 + somar(2)
8 + 7 + 6 + 5 + 4 + 3 + 2 + somar(1)
8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + somar(0)
8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0

• O valor retornado (8+7+6+5+4+3+2+1+0 = 36) é então atribuído à variável soma para ser
exibida na próxima linha do algoritmo.

Na fórmula matemática, também podemos observar quando existe uma recursão. Por exemplo:
0 𝑠𝑒 𝑛 = 0
𝑠𝑜𝑚𝑎(𝑛) = {𝑛 + 𝒔𝒐𝒎𝒂(𝒏 − 𝟏) 𝑠𝑒 𝑛 > 0

Exemplo 2: calcular o fatorial de um número.

Sabe-se que que o cálculo do fatorial ocorre da seguinte maneira:

5! = 5 * 4!
= 5 * (4 * 3!)
= 5 * (4 * (3 * 2!))
= 5 * (4 * (3 * (2 * 1!)))
= 5 * (4 * (3 * (2 * (1 * 0!))))
= 5 * (4 * (3 * (2 * (1 * 1)))))
= 120

Utilizando um laço de repetição simples, podemos ter:


public class Fatorial {
public static void main(String[] args) {
int valor = 4;
int fat = 1;
for(int i = valor; i > 0; i--) {
fat = fat * i;
}
System.out.println(valor + "! = " + fat);
}
}
33
Utilizando a versão recursiva, podemos ter:
public class Teste2 {
public static int fatorial(int valor) {
if(valor > 0) {
return valor * fatorial(valor-1);
}
else {
return 1;
}
}
public static void main(String[] args) {
int valor = 4;
int fat = fatorial(valor);
System.out.println(valor + "! = " + fat);
}
}

Executando a função recursiva, teríamos como pilha de execução para o retorno dos valores:

4 * fatorial(3)
4 * 3 * fatorial(2)
4 * 3 * 2 * fatorial(1)
4 * 3 * 2 * 1 * fatorial(0)
4*3*2*1*1 ➔ retorna o número 24

Na fórmula matemática, também podemos observar quando existe uma recursão. Por exemplo:
1 𝑠𝑒 𝑛 = 0
𝑛! = {
𝑛 ∗ (𝒏 − 𝟏)! 𝑠𝑒 𝑛 > 0

Vamos Praticar?
Tente resolver os seguintes algoritmos sozinho, individualmente. Caso não consiga, solicite auxílio aos
colegas e aos professores, mas não obtenha as respostas. Tente conseguir dicas de como resolver.

Após resolver os exercícios, aguarde um dia e tente resolvê-los novamente você mesmo, mas agora sem
utilizar as respostas e dicas como consulta. Se conseguiu resolver todos os exercícios sozinho, então você
está aprendendo o conteúdo!

PROCEDIMENTOS

Exercício 01: Uma imobiliária é especializada em vender terremos em diversos bairros da cidade. Para
atribuir um preço aos terremos, é preciso conhecer a sua área. Crie um algoritmo para auxiliar esta
imobiliária de forma que, no método principal, o algoritmo solicite as dimensões do terreno e, em seguida,
chame um subprograma chamado areaTerreno que recebe as dimensões do terreno nos parâmetros, calcula
a área do terreno e exibe-a ao usuário.

34
Exercício 02: Um algoritmo deve ser implementado para que, ao solicitar um número ao usuário, apresente
uma mensagem indicando se este número é par ou ímpar.

Para a criação deste algoritmo, considere o seguinte:

• Um procedimento chamado parImpar deve ser criado. Este procedimento precisa de um número
inteiro no parâmetro. Deve verificar se este número é par ou ímpar e exibir a mensagem ao
usuário
• Um procedimento chamado lerNumero deve ser criado. Este procedimento precisa solicitar ao
usuário por um número inteiro. Após o usuário digitar o número, ele deve chamar o
procedimento parImpar, fornecendo o número que o usuário digitou como parâmetro
• No método principal, chame o procedimento lerNumero.

Exercício 03: Implemente um algoritmo que:

• Possua um método chamado maiorNumero que receba três valores inteiros nos parâmetros. O
método é responsável por apresentar ao usuário o maior número entre os três valores recebidos
nos parâmetros
• Possua um método chamado lerNumeros que solicite ao usuário por três números inteiros e, em
seguida, chame o método maiorNumero fornecendo os valores informados pelo usuário nos
seus parâmetros
• Possua um método principal que faz a chamada ao método lerNumeros.

Exercício 04: Implemente um algoritmo que:

• Possua um método chamado divisivelPor que receba dois valores inteiros (a e b) nos
parâmetros. O método deve calcular e exibir ao usuário quantos números entre o 0 e o valor de
a são divisíveis pelo valor de b
• No método principal, solicite os dois valores ao usuário e forneça-os ao método divisivelPor para
obtermos a resposta ao questionamento.

Exemplo: O usuário digitou o número 10 e o número 3. Ao chamar o procedimento divisivelPor, o algoritmo


deverá informar que existem 4 números entre 0 e 10 que são divisíveis por 3 (ex: 0, 3, 6, 9).

Exercício 05: Implemente um procedimento chamado verificarNumeros que recebe dois números inteiros
como parâmetro. O procedimento deve apresentar uma mensagem ao usuário indicando se os dois números
são iguais ou se são diferentes.

Teste o seu algoritmo (na função main, solicite dois números e forneça-os ao procedimento criado).

Exercício 06: Implemente um procedimento chamado converterCelsius que recebe como parâmetro um
número ponto-flutuante representando uma temperatura em Farenheit. O procedimento deve converter
esta temperatura para graus Celsius e apresentar na tela a temperatura convertida.

Implemente um procedimento chamado converterFarenheit que recebe como parâmetro um número


ponto-flutuante representando uma temperatura em Celsius. O procedimento deve converter esta
temperatura para graus Farenheit e apresentar na tela a temperatura convertida.

No método principal, solicite uma escala de medidas de temperatura (1 para Celsius e 2 para Farenheit) e
também solicite a temperatura na escala informada. Caso a temperatura informada esteja em Celsius,
chame o procedimento converterFarenheit para exibir a temperatura equivalente. Caso a temperatura
informada esteja em Farenheit, chame o procedimento converterCelsius para exibir a temperatura
equivalente. Se o usuário digitar uma escala diferente de 1 ou 2, emitir uma mensagem na tela dizendo que
a escala é inválida.

35
Pesquise as fórmulas de conversão na Internet

Exercício 07: Um algoritmo especializado em calcular o fatorial de números deve ser desenvolvido. Para isso,
implemente um subprograma chamado exibirFatorial que receba no parâmetro um número inteiro entre 0 e
6. Este subprograma deve ser capaz de exibir ao usuário o fatorial do número informado. Caso o número
esteja for a da faixa de valores, exibir uma mensagem dizendo que não foi possível realizar o cálculo.

No subprograma principal, solicite um número inteiro ao usuário e exiba o fatorial deste número (chamando
o subprograma responsável pelo cálculo do fatorial).

FUNÇÕES

Exercício 08: Imagine que você seja proprietário de uma loja de roupas. Como política de sua loja, você paga
aos vendedores 7,5% de comissão caso o valor da venda seja inferior a R$ 500,00 e 5% caso o valor da venda
seja maior. Para facilitar os cálculos das comissões, você pode desenvolver um sistema que, tendo-se o valor
da venda, calcule e apresente ao usuário o valor da comissão a ser paga ao vendedor. Implemente um
programa que solicite ao usuário pelo valor da venda, calcule e apresente o valor da comissão a ser paga ao
vendedor conforme a política da empresa. Este algoritmo deve conter uma função chamada
calcularComissao que recebe o valor da venda como parâmetro e retorna o valor a ser pago ao vendedor.
Solicite o valor da venda ao usuário e apresente o valor da comissão no método principal.

Exercício 09: Um aluno pode fazer diversas avaliações em um trimestre. Considere que as avaliações
possuem um valor de nota (0 a 10). Implemente uma função chamada getConceito que recebe três notas
(valores double) como parâmetro, calcule e retorne o conceito obtido por um aluno em um determinado
trimestre. Para isso, considere que:

• O aluno fica com conceito D se a média das notas for inferior a 5,0
• O aluno fica com conceito C se a média das notas estiver entre 5,0 e 6,8
• O aluno fica com conceito B se a média das notas estiver entre 6,9 e 8,5
• O aluno fica com conceito A se a média das notas for maior que 8,5

Implemente também um procedimento chamado exibirConceito que receba três valores nos parâmetros: o
nome de um aluno, o nome da disciplina e o conceito obtido pelo aluno. O procedimento deve apresentar
uma mensagem informando que o aluno obteve o conceito naquela disciplina.

No algoritmo principal, solicite todos os dados necessários ao usuário, chame a função para calcular o
conceito e chame o procedimento para exibir a mensagem com o resultado final.

Exercício 10: Implemente uma função chamada obterNumeroAleatorio que receba dois números inteiros
como parâmetros, um indicando o mínimo e o outro indicando o máximo. A função deve ser capaz de obter
um número aleatório entre os valores no intervalo fornecido e retornar este número. No algoritmo principal,
solicite os valores mínimo e máximo ao usuário e apresente 10 números aleatórios chamando a função
criada (utilize laço de repetição).

Exercício 11: Implemente um procedimento chamado exibirMenu. Este procedimento deve exibir o seguinte
menu ao usuário e solicitar pela opção desejada.

MENU DE OPÇÕES:
1. Calcular Potência
2. Calcular Raiz Quadrada
3. Calcular Media
4. Sair
OPÇÃO: ___
36
Caso o usuário informe a opção 1, o sistema deverá solicitar a base e o expoente ao usuário e enviar estes
dados para a função calcularPotencia. Esta função deverá calcular a base elevado ao expoente (utilizando
laço de repetição) e retornar o resultado para ser exibido ao usuário.

Caso o usuário informe a opção 2, o sistema deverá solicitar por um número e enviar este número para a
função obterRaiz. Esta função deverá calcular a raiz quadrada do número informado e retornar este valor
para ser exibido ao usuário.

Se o usuário informar a opção 3, o sistema deverá solicitar por três números inteiros e enviar estes números
para uma função chamada getMedia. Esta função deverá calcular a média aritmética (observe que os valores
são inteiros e o resultado deve ser double, portanto, precisam ser convertidos para double na hora do
cálculo) e retornar este valor para ser exibido ao usuário.

Caso o usuário informe uma opção diferente de 1 a 4, emitir uma mensagem informando que a opção foi
inválida.

Permita que o sistema seja finalizado apenas se a opção 4 seja informada, ou seja, para qualquer opção
diferente de 4, o procedimento deve chamar a si mesmo (exibirMenu).

DICA: quando um subalgoritmo chama a si mesmo, chamamos isso de algoritmos recursivos.

Exercício 12: Implemente uma função chamada fatorial que recebe um número inteiro como parâmetro e
retorne o fatorial deste número. Calcule o fatorial do número apenas se ele estiver entre 0 e 6. Para
números fora desta faixa de valores, o resultado do cálculo do fatorial deve ser 0.

No programa principal, solicite ao usuário por um número e apresente o fatorial deste número (chamando a
função criada).

Exercício 13: Implemente um procedimento chamado lerNotas que leia a nota de 5 alunos (valores entre 0 a
10). Após a leitura das notas, chame a função calcularMedia que recebe todas as notas fornecidas e retorna
a média aritmética destas notas. O procedimento deve então exibir uma mensagem informando se a turma
foi bem (a média da turma for maior ou igual a 7), foi razoável (média da turma foi superior a 5 e inferior a 7)
ou mal (média inferior ou igual a 5). Teste suas funções.

DICA: no método principal haverá apenas a chamada ao procedimento lerNotas() que será o responsável por
conduzir a execução do algoritmo.

Exercício 14: Implemente uma função chamada getCategoria que recebe a idade de um atleta e retorne a
categoria que este atleta pertence. Se o atleta tiver entre 5 e 7 anos, ele pertence a categoria Infantil A. Se a
idade do atleta estiver entre 8 a 10 anos, ele pertence a categoria Infantil B. No caso da idade estar entre 11
e 13 anos, a categoria será Juvenil A. Para idades entre 14 e 17 anos, a categoria é Juvenil B. Maiores que 18
anos (inclusive) são da categoria Adulto.

No programa principal, solicite pela idade do atleta e apresente a sua categoria.

Exercício 15: Crie uma função que recebe por parâmetro um valor inteiro qualquer. Esta função deve
calcular e retornar o número de divisores deste valor (Exemplo: o número 8/2=4, 8/4=2 e 8/8=1, logo, o
número 8 é divisível por três números. Qualquer outra divisão gera números cujo resto da divisão é diferente
de zero).

No programa principal, solicite por um número inteiro e apresente quantos divisores ele possui.

37
3. Estruturas de Dados
Homogênea Unidimensional

Objetivos de aprendizagem
Este capítulo tem como objetivo:

• Desenvolver algoritmos capazes de manipular conjuntos


de dados
• Criar estrutura de dados capaz de armazenar conjuntos
de dados que pertençam a um mesmo tipo de dado
• Processamento de conjunto de dados por meio de
funções e procedimentos

O conteúdo trabalhado neste capítulo aborda:

• Estrutura de dados homogênea unidimensional


(vetores)
• Índice do vetor
• Percorrer vetores

38
Vetores

A Estrutura de Dados Homogênea Unidimensional também é conhecida como Array Unidimensional ou, mais
popularmente, é chamada de Vetores.

Um vetor consiste em um “conjunto de dados”, ou seja, temos uma única variável e dentro desta variável
podemos ter diversos valores armazenados. Observe que uma variável primitiva (String, int, double, etc.)
armazena apenas um único valor em um determinado instante (ex: int x = 10; faz com que a variável x
armazene o valor inteiro 10), já um vetor é uma única variável que pode armazenar mais de um valor.

Os vetores são estruturas de dados homogêneas visto que todos os valores contidos no vetor pertencem a
um mesmo tipo de dado. Por exemplo: se criarmos um vetor de números inteiros, então este vetor conterá
apenas números inteiros. Se o vetor for de Strings, conterá vários valores String. Caso o vetor seja booleano,
então todos os valores neste vetor devem ser booleanos. Os vetores também são unidimensionais, pois
possuem apenas uma única dimensão. Entenderemos melhor o conceito de dimensões quando estudarmos
as estruturas bidimensionais ou n-dimensionais.

Uma característica importante que temos ao utilizar vetores, é que sempre teremos um par de colchetes []
junto ao nome da variável. Este par de colchetes indica que a variável é um vetor. Com isso, temos:

int x; ➔ uma variável primitiva, comum

int x[]; ➔ um vetor de números inteiros

Para criarmos um vetor, precisamos informar quantos valores terão dentro da variável. A sintaxe para criar
um vetor é:
<tipo de dado> <nome do vetor>[] = new <tipo de dado> [<tamanho>];

Por exemplo, imagine que queremos armazenar a idade de 10 alunos em uma única variável. Podemos então
criar um vetor de números inteiros (idade é um número inteiro!) que possui 10 espaços para guardar
valores:
int idades[] = new int[10];

Desta forma, a variável idades possui 10 espaços para guardar valores:

idades
valor valor valor valor valor valor valor valor valor valor

Um conceito muito importante ao trabalharmos com vetores é o de índice do vetor. O índice corresponde a
um endereço que indica qual é a posição dentro do vetor que desejamos acessar. O valor do índice deve vir
dentro dos colchetes. Por exemplo:
idades[3] = 10;

Com a instrução acima, estamos acessando a variável idades na posição de índice 3, e estamos guardando o
número 10 dentro desta posição na variável.

Outro detalhe muito importante a saber sobre os índices: o primeiro índice de um vetor (a posição do
primeiro número dentro da variável) é o número 0. Portanto, a posição do último número dentro do vetor
possui índice <tamanho> - 1. Por exemplo, se criarmos um vetor com tamanho 10, então o primeiro índice
será o 0 e o último índice será o 9. Desta forma, o vetor idades possui a seguinte estrutura:

39
idades
Valores:
Índices: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

Considere o seguinte trecho de algoritmo:


int idades[] = new int[10];
idades[3] = 5;
idades[8] = 1500;
idades[0] = 657;

Inicialmente o vetor idades foi criado e este vetor contém 10 posições para guardar valores. Em seguida, o
número 5 foi atribuído à posição [3] do vetor.

idades
Valores: 5
Índices: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

Em seguida, o número 1500 foi atribuído ao vetor em sua posição de índice [8]:

idades
Valores: 5 1500
Índices: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

Por fim, o vetor idades, em seu índice [0], guardará o valor 657:

idades
Valores: 657 5 1500
Índices: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

Podemos apresentar os valores das variáveis ao usuário normalmente como fazemos com qualquer variável.
Basta fornecer o índice do vetor para acessarmos o valor que desejamos exibir:
System.out.println("Valor: " + idades[8]);

Também podemos fazer cálculos matemáticos com os valores dos vetores igual fazemos com variáveis
primitivas. Por exemplo, o cálculo 5 + 1500 + 2 será feito e o valor 1507 será atribuído à variável soma:
int soma = idades[3] + idades[8] + 2;

Podemos também digitar valores para as posições nos vetores, exatamente igual fazemos com as variáveis
primitivas. Só precisamos lembrar de colocar o índice onde o valor digitado será salvo. No exemplo a seguir,
o usuário pode digitar um valor (em uma janela gráfica) e o valor será convertido para número inteiro e
então será salvo na variável idades na posição de índice [4].
idades[4] = Integer.parseInt(JOptionPane.showInputDialog("Informe um
valor:"));

40
Percorrendo vetores
Tendo-se a seguinte instrução:
String nomes[] = new String[10];

Imagine que precisamos digitar todos os valores do vetor nomes. Desta forma, temos o seguinte conjunto de
instruções:
nomes[0] = JOptionPane.showInputDialog("Informe um nome:");
nomes[1] = JOptionPane.showInputDialog("Informe um nome:");
nomes[2] = JOptionPane.showInputDialog("Informe um nome:");
nomes[3] = JOptionPane.showInputDialog("Informe um nome:");
nomes[4] = JOptionPane.showInputDialog("Informe um nome:");
nomes[5] = JOptionPane.showInputDialog("Informe um nome:");
nomes[6] = JOptionPane.showInputDialog("Informe um nome:");
nomes[7] = JOptionPane.showInputDialog("Informe um nome:");
nomes[8] = JOptionPane.showInputDialog("Informe um nome:");
nomes[9] = JOptionPane.showInputDialog("Informe um nome:");

Agora imagine que desejamos exibir na tela todos os valores do vetor. Teríamos o seguinte conjunto de
instruções:
System.out.println("Valor: " + nomes[0]);
System.out.println("Valor: " + nomes[1]);
System.out.println("Valor: " + nomes[2]);
System.out.println("Valor: " + nomes[3]);
System.out.println("Valor: " + nomes[4]);
System.out.println("Valor: " + nomes[5]);
System.out.println("Valor: " + nomes[6]);
System.out.println("Valor: " + nomes[7]);
System.out.println("Valor: " + nomes[8]);
System.out.println("Valor: " + nomes[9]);

Observe que todas as linhas de entrada de dados, bem como as linhas de saída de dados são parecidas. A
única diferença está no valor dentro dos colchetes, indicando a posição em que os valores estão sendo
acessados dentro do nosso vetor.

Sempre que precisarmos percorrer nosso vetor, tanto para digitar dados para todas as posições, como para
apresentar na tela todos os valores deste vetor, ou mesmo quando precisarmos fazer cálculos envolvendo os
valores deste vetor, podemos melhorar o código utilizando uma estrutura de repetição.

Geralmente utilizamos o comando for para percorrer todos os valores de um vetor. A variável utilizada para
contar as repetições é colocada dentro dos colchetes. Desta forma, conseguimos acessar, sequencialmente,
todos os valores do vetor. Por exemplo:

for(int cont = 0; cont < 10; cont++) {


nomes[cont] = JOptionPane.showInputDialog("Informe um nome:");
}

for(int cont = 0; cont < 10; cont++) {


System.out.println("Valor: " + nomes[cont]);
}

41
Com o uso da estrutura de repetição, o código é reduzido de tamanho, facilitando o acesso a todos os dados
contidos em nosso vetor.

Na linguagem Java, todo vetor é um objeto. Desta forma, temos uma propriedade importante disponível
para usar: acessar o tamanho do vetor após ele ser criado. Para conseguirmos saber qual é o tamanho de um
vetor, podemos colocar .length na frente do nome da variável. Ao fazermos isso, estamos obtendo qual o
tamanho foi fornecido a este vetor no momento de sua criação. Por exemplo: podemos criar um vetor de
números inteiros chamado idades e que possui espaço para guardarmos 15 valores.
int idades[] = new int[15];

Se durante a execução do algoritmo precisamos “relembrar” qual foi o tamanho que demos ao vetor no
momento em que ele foi criado (15), podemos utilizar idades.length. Este atribuído é importante, em
especial, quando usamos laços de repetição para percorrer os valores do vetor. Por exemplo:

for(int cont = 0; cont < nomes.length; cont++) {


System.out.println("Valor: " + nomes[cont]);
}

Ao utilizar o atributo .length dos vetores nos laços de repetição, caso o algoritmo mude e o vetor idades não
tenha mais 15 endereços, mas sim 200, não precisamos modificar o restante do nosso algoritmo, visto que a
repetição continua indo até o tamanho máximo de endereços possíveis:
String nomes[] = new String[10]; Vetor nomes com
10 posições

for(int cont = 0; cont < nomes.length; cont++) {


nomes[cont] = JOptionPane.showInputDialog("Informe um nome:");
Mesmo }
laço de
repetição
para nomes = new String[150]; Novo vetor nomes
diferentes com 150 posições
tamanhos
de vetor for(int cont = 0; cont < nomes.length; cont++) {
nomes[cont] = JOptionPane.showInputDialog("Informe um nome:");
}

Dica: Quando já sabemos quais são os dados que o vetor conterá, podemos criar o vetor já preenchido com
estes dados. Para isso, podemos declarar a variável de vetor e atribuir os valores, na sequência em que os
valores estarão dentro dos índices do vetor.
int v1[] = {10, 50, 4, 8};
Valores: 10 50 4 8
Índices: [0] [1] [2] [3]

String v2[] = {"João", "André", "Carolina", "Beatriz"};


Valores: “João” “André” “Carolina” “Beatriz”
Índices: [0] [1] [2] [3]

42
Procedimentos e funções com vetores
Quando trabalhamos com vetores, provavelmente utilizaremos procedimentos ou funções para calcular as
ações ou processar os dados deste vetor, conforme a necessidade do algoritmo. Por exemplo: imagine que
tenhamos a lista de todos os conceitos obtidos pelos alunos do segundo ano do curso técnico em
informática. Uma função pode ser implementada para computar qual foi o conceito mais obtido pela turma.
Desta forma, a função precisa do vetor preenchido para que possa executar suas instruções e retornar a
informação de que necessitamos.

Podemos passar vetores como parâmetros para procedimentos e funções normalmente, da mesma forma
que passamos parâmetros com tipos de dados primitivos. A diferença é que, ao declarar uma variável dentro
dos parênteses dos módulos (declaração dos parâmetros), precisamos informar que ali contém um vetor e,
portanto, precisamos colocar o par de colchetes na frente do nome da variável. Por exemplo, no
procedimento abaixo chamado exibirVetor(), temos que um vetor de números inteiros deve ser fornecido
para que este procedimento possa executar suas ações:
public static void exibirVetor(int vet[]) {

for(int cont = 0; cont < vet.length; cont++) {


System.out.println("Valor: " + vet[cont]);
}

Agora, para usar este procedimento, precisamos ter um vetor já preenchido. Por exemplo:
//vetor com valores já inicializados
int v1[] = {10, 50, 4, 8};
exibirVetor(v1);

//vetor com valores informados pelo usuário


int valores[] = new int[10];
for(int cont = 0; cont < 10; cont++) {
valores[cont] = Integer.parseInt(JOptionPane.showInputDialog("Informe
valor:"));
}
exibirVetor(valores);

No primeiro caso acima, o vetor v1 é criado. Este vetor contém quatro números inteiros já preenchidos por
padrão no momento da criação do vetor. Em seguida, o procedimento exibirVetor() é chamado, enviando
todos os valores de v1 para este procedimento. Como o procedimento possui um vetor em seu parâmetro
(int vet[]), então, lá dentro do procedimento, o vetor vet possui os valores recebidos de v1.

No segundo caso acima, o vetor valores é criado e todos os dez números são fornecidos pelo usuário via
teclado do computador. Após preencher os dados do vetor, todos os valores deste vetor são enviados para o
procedimento para a variável vet. Em seguida, estes dados podem ser exibidos normalmente.

Repare que o mesmo procedimento pode ser usado para exibir os dados de qualquer vetor de números
inteiros, independentemente do tamanho do vetor. Isso só foi possível, pois no laço de repetição, o índice
começa com 0 (primeiro valor do vetor) e a condição de parada usa vet.length, ou seja, utiliza o tamanho
atual do vetor, e não um valor constante fixado pelo programador. O código completo do exemplo é
apresentado abaixo:

43
import javax.swing.JOptionPane;
public class Exemplos {
public static void main(String args[]) {
//vetor com valores já inicializados
int v1[] = {10, 50, 4, 8};
exibirVetor(v1);

//vetor com valores informados pelo usuário


int valores[] = new int[10];
for(int cont = 0; cont < 10; cont++) {
valores[cont] = Integer.parseInt(JOptionPane.
showInputDialog("Informe valor:"));
}
exibirVetor(valores);
}

public static void exibirVetor(int vet[]) {


for(int cont = 0; cont < vet.length; cont++) {
System.out.println("Valor: " + vet[cont]);
}
}
}

Como exemplo de uso de funções, considere a seguinte situação: Precisamos de uma função que calcule a
soma de todos os números de um vetor. O resultado da função é a soma destes valores. Portanto, podemos
implementar a função como abaixo.
public static int somaVetor(int vet[]) {
int resultado = 0;
for(int cont = 0; cont < vet.length; cont++) {
resultado = resultado + vet[cont];
}
return resultado;
}

Desta forma, a função somaVetor() precisa de um vetor de números inteiros para ser executada. Ao
executar o seu algoritmo, a função percorre o vetor, acumulando a soma valor a valor na variável resultado.
Portanto, o valor da função somaVetor() é o valor da variável resultado. Para chamar esta função, basta fazer
com que uma variável receba o valor da função:
int v1[] = {10, 50, 4, 8};
int a = somaVetor(v1);
System.out.println("A soma do vetor foi: " + a);

O código complete do exemplo é apresentado abaixo. Repare que a soma de qualquer vetor de números
inteiros pode ser feita, já que a função percorre o vetor completo, desde a primeira posição (de índice [0])
até a última posição do vetor (de índice [tamanho-1]), controlado no laço de repetição pelo vet.length.
Desta forma, independentemente do tamanho do vetor, a função poderá ser executada.
import javax.swing.JOptionPane;
public class Exemplos {
public static void main(String args[]) {
//vetor com valores já inicializados
int v1[] = {10, 50, 4, 8};
int a = somaVetor(v1);
System.out.println("A soma do vetor foi: " + a);
44
//vetor com valores informados pelo usuário
int valores[] = new int[10];
for(int cont = 0; cont < 10; cont++) {
alores[cont] = Integer.parseInt(JOptionPane.
showInputDialog("Informe valor:"));
}
int b = somaVetor(v1);
System.out.println("A soma do vetor foi: " + b);
}

public static int somaVetor(int vet[]) {


int resultado = 0;
for(int cont = 0; cont < vet.length; cont++) {
resultado = resultado + vet[cont];
}
return resultado;
}
}

Estrutura de dados homogênea multidimensional


Além das estruturas de dados homogêneas unidimensionais (estruturas homogêneas = todos os valores
possuem o mesmo tipo de dado; estruturas unidimensionais = possui apenas uma única dimensão)
conhecidas como vetores, podemos ter as estruturas de dados homogêneas multidimensionais, ou seja,
estruturas que possuem mais de uma dimensão.

A estrutura de dados homogênea multidimensional mais utilizada é a bidimensional, ou seja, a estrutura de


dados que possui 2 dimensões. Esta estrutura é conhecida como Arrays Bidimensionais ou, mais
popularmente, é conhecida como matrizes.

Uma matriz pode ser visualmente representada por um conjunto de linhas e colunas.

Podemos dizer que uma matriz é um vetor de vetores, ou seja, dentro de uma posição dentro de um vetor,
ao invés de termos apenas um único valor, teremos outro vetor com vários valores. Observe a estrutura da
matriz:

matriz índices [0] [1] [2]


[0]
[1]
[2]
[3]

Observe que existem índices para identificar as linhas e também existem índices para identificar as colunas.

Para acessarmos uma posição específica dentro da matriz, precisamos informar os dois índices. Cada índice
estará dentro de colchetes. Por exemplo:

matriz[2][1] = 8;

faz com que o número 8 seja atribuído para a matriz na terceira linha na segunda coluna:

45
matriz índices [0] [1] [2]
[0]
[1]
[2] 8
[3]

Para comparar matrizes (bidimensional) com vetores (unidimensional), temos:

Vetor Matriz
Representação gráfica: Representação gráfica:

[0] [1] [2] [0] [1] [2]


vetor matriz [0]
[1]
[2]
[3]
[4]

Declaração: Declaração:
int vetor[] = new int[3]; int matriz[][] = new int[5][3];
Atribuição de valores: Atribuição de valores:
vetor[2] = 5; matriz[4][2] = 5;

[0] [1] [2] [0] [1] [2]


vetor 5 matriz [0]
[1]
[2]
[3]
[4] 5

Como os vetores possuem apenas uma dimensão, então geralmente utilizamos um laço de repetição para
percorrer o vetor, valor por valor. O contador da repetição se inicia com 0 pois é o valor do endereço da
primeira posição do vetor e vai até o vetor.length:
for(int i = 0; i < vetor.length; i++) {
System.out.println( vetor[i] );
}

Entretanto, uma matriz possui duas dimensões: uma para a linha e outra para a coluna. Neste sentido,
sempre que precisarmos percorrer valor por valor de uma matriz, precisaremos de dois laços de repetição
(um dentro do outro, aninhados).

O primeiro laço de repetição é utilizado para o posicionamento da linha. O segundo laço de repetição (laço
interno) é utilizado para o posicionamento da coluna. Por exemplo:
for(int i = 0; i < matriz.length; i++) {
for(int j=0; j < matriz[i].length; j++) {
System.out.println( matriz[i][j] );
}
}

Repare que no laço de repetição mais externo, a variável i é usada para posicionar nas linhas. Então,
usamos matriz.length para obtermos a quantia de linhas (primeira dimensão) da matriz. No laço de
46
repetição mais externo, a variável j é usada para o posicionamento das colunas e usamos
matriz[i].length para obtermos o número de colunas que existe dentro daquela linha i.

Estruturas de dados dinâmicas


Nas estruturas de dados homogêneas (unidimensionais ou multidimensionais), sempre que elas são
declaradas, o seu tamanho será fixo. Por exemplo: Se um vetor de números inteiros com 8 posições for
criado, este vetor sempre terá 8 posições. O mesmo acontece com as matrizes: se uma matriz com 5 linhas e
10 colunas for criado, esta matriz sempre terá este mesmo tamanho. Elas não são dinâmicas, ou seja, elas
não permitem aumentar ou diminuir de tamanho.

Quando temos uma lista de valores e não sabemos exatamente quantos serão os valores desta lista, então
podemos fazer uso de estruturas de dados dinâmicas. Em Java, uma das principais estruturas de dados
dinâmicas é oferecida por meio da classe ArrayList. Para utilizar este recurso, precisamos sempre importar a
classe ArrayList no nosso código no início do algoritmo, antes mesmo da definição da classe:
import java.util.ArrayList;
Para criarmos um objeto que representa uma lista de valores, dentro do nosso algoritmo (dentro do método
principal ou de outros procedimentos e funções), podemos utilizar a seguinte sintaxe:

ArrayList<TIPO_DE_DADO> nomeDaLista = new ArrayList<TIPO_DE_DADO>();

O tipo de dado, neste caso, deve ser String (para valores do tipo String), Integer (para valores do tipo int),
Double (para valores do tipo double), Boolean (para valores do tipo boolean) e Character (para valores do
tipo char). Por exemplo:
ArrayList<String> listaString = new ArrayList<String>();
ArrayList<Integer> listaInt = new ArrayList<Integer>();
ArrayList<Double> listaDouble = new ArrayList<Double>();
ArrayList<Boolean> listaBoolean = new ArrayList<Boolean>();
ArrayList<Character> listaChar = new ArrayList<Character>();

Após criado o objeto que armazenará os valores da lista, podemos manipular este objeto adicionando novos
valores, removendo valores ou pesquisando se algum determinado valor está presente ou não nesta lista.

Para adicionar novos elementos na lista, precisamos informar o nome da variável, seguida pelo operador
ponto (.) e da função add(VALOR) fornecendo o valor a ser inserido nesta lista. Por exemplo:
ArrayList<String> alunos = new ArrayList<String>();
alunos.add("Gabriel");
alunos.add("Vitória");
alunos.add("Patrícia");

A lista de alunos, neste momento, será:

alunos “Gabriel” “Vitória” “Patrícia”


[0] [1] [2]
Podemos adicionar novos valores a qualquer momento, onde estes novos valores estarão sendo adicionados
ao final da lista criando novos índices.

Para obtermos um determinado valor da lista, chamamos a função get(POSIÇÃO). A posição indica o índice
que desejamos acessar. Por exemplo:

47
System.out.println( alunos.get(1) );

Na instrução acima temos que uma mensagem será exibida na tela e a mensagem será o conteúdo de
alunos.get(1). Na lista alunos no índice [1] temos o conteúdo “Vitória”. Portanto, “Vitória” será apresentada
na tela do computador.

Para alterar um valor de uma posição dentro da lista, precisamos utilizar a função set(POSIÇÃO, VALOR)
onde a posição indica o índice que desejamos acessar na lista e o valor indica o conteúdo que será colocado
dentro desta posição. Por exemplo:
alunos.set(2, "Amauri");
O comando acima substitui o conteúdo da lista de alunos que está na posição de índice [2], trocando
“Patrícia” por “Amauri”.

alunos “Gabriel” “Vitória” “Amauri”


[0] [1] [2]

Para remover um valor da lista, precisamos utilizar a função remove(POSIÇÃO) onde a posição indica qual é
o índice que desejamos remover da lista. Remover um valor da lista faz com que o seu tamanho seja
modificado e, ao mesmo tempo, os índices sejam atualizados. Por exemplo:
alunos.remove(1);
O comando remove da lista de alunos o valor que está no índice [1]. Removendo este valor, então a lista é
reorganizada e os índices também são atualizados, de forma que a lista ficará como:

alunos “Gabriel” “Amauri”


[0] [1]

Caso desejemos saber quantos valores estão presentes na lista em um determinado momento, precisamos
descobrir o “tamanho” da lista. Para isso, usamos a função .size(). Ela é equivalente ao .length dos vetores
comuns, pois retorna o tamanho da lista de valores. Por exemplo:
ArrayList<String> alunos = new ArrayList<String>();
alunos.add("Gabriel");
alunos.add("Vitória");
alunos.add("Patrícia");

System.out.println("Lista com " + alunos.size() + " valores");

alunos.remove(1);

alunos.add("Amanda");
alunos.add("Milena");

System.out.println("Lista com " + alunos.size() + " valores");

System.out.println(Arrays.asList(alunos));

As mensagens que serão exibidas na tela são:

Lista com 3 valores


Lista com 4 valores
[[Gabriel, Patrícia, Amanda, Milena]]

48
Dica: para exibir todos os valores da lista podemos usar Arrays.asList(LISTA). Para isso, precisamos
importar java.util.Arrays.

Vamos Praticar?
Tente resolver os seguintes algoritmos sozinho, individualmente. Caso não consiga, solicite auxílio aos
colegas e aos professores, mas não obtenha as respostas. Tente conseguir dicas de como resolver.

Após resolver os exercícios, aguarde um dia e tente resolvê-los novamente você mesmo, mas agora sem
utilizar as respostas e dicas como consulta. Se conseguiu resolver todos os exercícios sozinho, então você
está aprendendo o conteúdo!

CRIAÇÃO DE VETORES

Exercício 01: Você precisa desenvolver um aplicativo que seja capaz de guardar as notas de 10 alunos de
uma turma. As notas vão de 0,0 a 10,0. Crie o vetor que seja capaz de representar esta situação.

Exercício 02: Declare um vetor que seja capaz de armazenar o nome de 85 alunos de uma escola.

Exercício 03: Imagine um sistema computacional que precisa controlar o status dos ares condicionados de
uma empresa. A empresa contém 8 salas com ar condicionado. O status é representado por true para
quando o ar condicionado de uma sala esta ligado e false quando está desligado. Crie um vetor em que cada
posição represente uma sala da empresa e que armazene o status de cada ar condicionado.

Exercício 04: Considere o seguinte vetor:

double precos[] = new double[5];

• Qual é a instrução para armazenar o preço R$ 1500,00 na primeira posição do vetor?


• Qual é a instrução para armazenar o preço R$ 8,99 na última posição do vetor?
• Qual é a instrução para exibir na tela o preço que está na terceira posição do vetor?

Exercício 05: Implemente um algoritmo que seja capaz de solicitar por 10 nomes ao usuário. Em seguida, o
algoritmo deve mostrar na tela os 10 nomes informados. Armazene os 10 nomes em uma única variável.

PERCORRENDO VETORES

Exercício 06: Considere o seguinte vetor:

double alturasAlunos[] = new double[40];

Como fazer para exibir na tela o número de valores que a variável alturasAlunos possui?

Exercício 07: Implemente um algoritmo que seja capaz de armazenar o nome e a idade de 10 alunos de uma
turma. Solicite os nomes e as idades de cada aluno ao usuário e, em seguida, apresente na tela um relatório
contendo o nome e a idade informada.

DICA: um vetor para os nomes e um vetor para as idades.


DICA: o nome no índice [0] possui a idade no índice [0].

49
DICA: utilize um laço de repetição para solicitar o nome e a idade e um laço de repetição para apresentar os
dados.
DICA: a saída dos dados deve ser um relatório contendo a mensagem
“O aluno NOME[posição] possui IDADE[posição] anos”

Exercício 08: Implemente um algoritmo que seja capaz de armazenar em uma variável 10 números inteiros.
Estes números deverão ser sorteados pelo computador aleatoriamente, no intervalo entre 0 e 100. Após
obter todos os números, apresente na tela todos os números sorteados.

Exercício 09: Considere o seguinte vetor:

double precos[] = new double[5];

Implemente um algoritmo que tenha este vetor, solicite ao usuário por todos os preços (todos os valores
deste vetor), e, ao final, apresente na tela a soma de todos os valores contidos neste vetor.

Exercício 10: Implemente um algoritmo que contenha um vetor com 10 números inteiros. O algoritmo deve
solicitar ao usuário pelo preenchimento deste vetor. Após o preenchimento, o algoritmo deve encontrar
qual foi o maior número informado pelo usuário e apresentá-lo na tela.

Exercício 11: Seja um vetor declarado e inicializado como segue:

double precos[] = {8, 8.9, 7.89, 9, 1, 0.89, 11};

Implemente um algoritmo que contenha este vetor. Em seguida, o algoritmo deve encontrar qual é o menor
número dentro do vetor e apresentar ao usuário qual é o índice (a posição dentro do vetor) em que este
menor número se encontra.

Exercício 12: Crie um algoritmo que contenha um vetor de números inteiros contendo 50 posições. O
algoritmo deve sortear números aleatórios para preencher este vetor, com valores variando entre 0 e 500.
Após preencher o vetor, o algoritmo deve calcular e apresentar ao usuário quantos números pares foram
sorteados e estão presentes neste vetor.

Exercício 13: Um algoritmo deve conter um vetor de inteiros com 10 posições que é preenchido com valores
aleatórios entre 0 e 10. Em seguida, o algoritmo deve solicitar ao usuário por um número. Por fim, o
algoritmo deve emitir uma mensagem informando se o número digitado está presente ou não neste vetor.

PROCEDIMENTOS E FUNÇÕES COM VETORES

Exercício 14: Implemente um algoritmo que contenha um procedimento que seja capaz de apresentar ao
usuário todos os nomes de alunos que estão armazenados em um vetor cujos dados são recebidos em seu
parâmetro. Teste seu procedimento criando um vetor no método principal, solicitando os dados ao usuário
e, por fim, chamando seu procedimento enviando o vetor criado como parâmetro.

Exercício 15: Um procedimento chamado exibirRelatorio precisa ser criado para exibir um relatório na tela
do computador que contenha os nomes dos alunos juntamente com as médias destes alunos. Para isso, dois
vetores devem ser fornecidos em seus parâmetros: um vetor de Strings com os nomes dos alunos, e um
vetor de inteiros com as notas de cada aluno, de forma que o aluno no índice [0] de um vetor possui a nota
no índice [0] do outro vetor e assim sucessivamente. Implemente o procedimento conforme necessário.

Em seguida, no programa principal, crie os dois vetores (de nomes e de notas), preencha os dados dos dois
vetores solicitando os dados ao usuário, e chame o procedimento para exibir o relatório, fornecendo todos
os dados de que o procedimento necessita para ser executado.
50
Exercício 16: Um programa de computador deve ser capaz de solicitar ao usuário pelo nome de 10 cidades e
também a população de cada uma destas cidades. Implemente um programa que represente esta situação.
Por exemplo:
cidade[0] = “Paranavaí” população[0] = 89500
cidade[1] = “Terra Rica” população[1] = 15256
cidade[2] = “Paranacity” população[2] = 11361
…. ….

O programa deve ter uma função chamada maiorCidade que receba o vetor da população como parâmetro.
A função deve ser capaz de devolver o índice do vetor que possui o maior valor, ou seja, a posição no vetor
que contém a cidade mais populosa. Apresente o nome da cidade mais populosa no programa principal,
utilizando o valor do índice retornado pela função.

Exercício 17: Faça um programa que solicite ao usuário pelo tamanho de um vetor de números inteiros.
Após o usuário informar o tamanho, o programa deve criar o vetor no tamanho informado. Em seguida, o
usuário deverá digitar todos os dados deste vetor.

Implemente um procedimento chamado exibirVetor que receba um vetor de números inteiros no


parâmetro. Este procedimento deve ser capaz de exibir os dados do vetor na tela do computador.

Implemente também um procedimento chamado exibirVetorInvertido que receba um vetor de números


inteiros no parâmetro. Este procedimento deve ser capaz de apresentar na tela do computador todos os
dados do vetor, mas do último valor até o primeiro.

Exercício 18: Um programa de computador deve ser desenvolvido para obter o preço de vinte televisores
que um hipermercado comercializa. Estes valores devem ser armazenados em um vetor com os dados
fornecidos pelo usuário.

Este programa possui uma função chamada mediaPrecos que recebe um vetor contendo preços de
televisores por parâmetro. Sua tarefa é calcular a média dos preços de todos os televisores contidos no
vetor.

Apresente, no método principal, o preço médio dos televisores comercializados pelo supermercado.

Exercício 19: Implemente uma função chamada idadesImpares que receba um vetor de idades nos
parâmetros. Esta função deve calcular quantas idades neste vetor são números ímpares. Teste sua função.

Dica: para testar a função, no método principal, crie o vetor, solicite os dados ao usuário e chame a função
fornecendo o vetor preenchido. Obtenha o valor da função e apresente na tela o valor obtido.

51
4. Ordenação de Vetores

Objetivos de aprendizagem
Este capítulo tem como objetivo:

• Desenvolver o raciocínio lógico necessário para a


ordenação de vetores
• Utilizar diferentes algoritmos para a ordenação de
vetores

O conteúdo trabalhado neste capítulo aborda:

• Ordenação de vetores pelo método Bolha


• Ordenação de vetores pelo método Inserção
• Ordenação de vetores pelo método Seleção

52
Conceitos iniciais

Os computadores lidam o tempo todo com muitos dados. O processamento de dados consiste em ler ou
obter um conjunto de dados, realizar uma série de cálculos sobre estes dados e fornecer algum tipo de
resultado com estes cálculos que seja útil para alguma finalidade.

Iniciaremos o estudo de alguns algoritmos que fazem o “processamento de dados” de uma lista de dados
(vetores). Frequentemente existem situações onde um conjunto de dados precisam estar ordenados
(alfabeticamente, do maior para o menor, etc.). Imagine um sistema computacional que precisa exibir os
nomes dos clientes em ordem alfabética, ou uma lista que exibe os conceitos dos alunos da nota máxima até
a nota mínima, ou mesmo um sistema de vendas online em que os produtos podem ser listados do menor
preço para o maior preço. Para conseguir fazer esta ordenação dos dados, existem diversos algoritmos
diferentes que podem ser usados.

A ordenação dos dados é o assunto a ser estudado neste bloco de atividades. Considere um conjunto de
dados armazenados em um vetor, tal como o representado abaixo:

10 8 6 15 18 20 1

Para o processamento destes dados, imagine que estes dados precisam ser organizados em ordem numérica
crescente, ou seja, do menor número para o maior número. Após esta ordenação, o vetor teria a seguinte
configuração:

1 6 8 10 15 18 20

A função dos algoritmos de ordenação é justamente esta: a partir de um vetor preenchido com dados,
colocar estes dados em ordem seguindo algum critério (do menor para o maior valor, do maior para o
menor, etc.).

Três algoritmos básicos de ordenação de vetor serão apresentados:

• Ordenação de vetor utilizando o método bolha;


• Ordenação de vetor utilizando o método de inserção;
• Ordenação de vetor utilizando o método de seleção.

Preliminares
Vocês se lembram lá da disciplina de Algoritmos e Linguagem de Programação I quando começamos falar
sobre variáveis? Provavelmente você resolveu um algoritmo que dizia o seguinte: Tendo-se duas variáveis A
e B, faça com que a variável A passe a valer o valor de B, e B passe a valer o valor de A.

Esta troca de valores entre as variáveis é o princípio básico para os algoritmos de ordenação. Inicialmente, os
alunos fazem o seguinte:
int a = 10;
int b = 20;
System.out.println("A: " + a + " e B: " + b);

a = b;
b = a;
System.out.println("A: " + a + " e B: " + b);
53
O que ocorre é o seguinte: inicialmente temos que a variável a vale 10 e a variável b vale 20 e a mensagem
“A: 10 e b: 20” será exibida na tela. Em seguida, com a instrução a = b; modificamos o valor da variável a
fazendo com que a = 20. Até aí tudo bem, o valor de a recebeu o valor de b e o algoritmo está correto. Mas
observe a próxima instrução: b = a;. Aqui, como o valor da linha anterior disse que o valor de a é 20, então
temos que b = 20. Logo, não fizemos a troca dos valores. O valor da variável a foi perdido.

Para resolver este problema, precisamos de uma terceira variável, uma variável auxiliar. Por que esta
variável é necessária? Para guardar um valor que será perdido no algoritmo. Se guardarmos este valor em
algum lugar, então podemos recuperá-lo depois quando for necessário. Observe como o algoritmo
funcionaria:
int a = 10;
int b = 20;
System.out.println("A: " + a + " e B: " + b);

int aux = a;
a = b;
b = aux;
System.out.println("A: " + a + " e B: " + b);
O que ocorreu é o seguinte: inicialmente temos que a variável a vale 10 e a variável b vale 20 e a mensagem
“A: 10 e b: 20” será exibida na tela. Em seguida, com a instrução aux = a dizemos que o valor de a será salvo
na variável aux. Ou seja, neste momento temos o valor 10 tanto na variável a quanto na variável aux. Em
seguida, temos que a = b, ou seja, a = 20. Entretanto, para concluir a troca, temos que b = aux, ou seja, desta
vez dissemos que b = 10 e, portanto, foi feita a troca dos valores. Inicialmente a = 10 e b = 20. No fim do
algoritmo, temos que a = 20 e b = 10.

Algoritmo de Ordenação por Bolha


O algoritmo de ordenação por bolha utiliza justamente o método de troca de valores de duas variáveis. O
que este algoritmo faz?

Ele compara dois valores adjacentes (um valor e o próximo valor) da lista. Por exemplo, considere um vetor
chamado vetor criado e inicializado com os seguintes dados:
int vetor[] = {10, 8, 6, 15, 18, 20, 1};
10 8 6 15 18 20 1

O primeiro valor do vetor é 10. Temos que vetor[0] = 10.

O segundo valor do vetor é 8. Portanto, vetor[1] = 8.

Precisamos fazer uma comparação entre estes dois valores. Ou seja, comparamos 10 e 8, ou, mais
precisamente, vetor[0] e vetor[1], visto que são valores adjacentes, vizinhos.

Observe que 10 > 8. Logo, o primeiro valor é maior que o segundo valor. Se o vetor precisa ser ordenado do
menor número para o maior número, então existe um problema aqui. É necessário fazer a troca destes
valores. O resultado do vetor após a troca:
aux = vetor[0];
vetor[0] = vetor[1];
vetor[1] = aux;

54
Após fazer esta troca, o vetor estará configurado da seguinte maneira:

8 10 6 15 18 20 1

Como no primeiro passo fizemos a comparação do primeiro valor com o segundo valor, o próximo passo é
fazer a comparação do segundo valor com o terceiro valor. Observe que temos na segunda posição o valor
10 (vetor[1] = 10) e na terceira posição o valor 6 (vetor[2] = 6). Como 10 > 6, então temos um novo
problema. Os valores não estão do menor para o maior e precisam ser novamente trocados.
aux = vetor[1];
vetor[1] = vetor[2];
vetor[2] = aux;
Após esta nova troca, o vetor ficará da seguinte maneira:

8 6 10 15 18 20 1

O processo continua fazendo a comparação agora do terceiro valor com o quarto valor. Temos que
vetor[2]=10 e que vetor[3] = 15. Se compararmos 10 > 15, temos uma resposta false. Neste sentido, estes
dois números não precisam ser trocados, visto que os números 10 e 15 já se encontram ordenados.
Portanto, o vetor permanece da mesma forma:

8 6 10 15 18 20 1

Agora precisamos comparar o número 15 com o 18. Fazemos a pergunta: 15 > 18 ? Como a resposta foi false
novamente, então os números 15 e 18 já estão ordenados. O vetor resultante é o mesmo:

8 6 10 15 18 20 1

Novamente precisamos fazer o teste do valor 18 com o valor 20. Comparando 18 > 20, obtemos false
novamente como resposta. Portanto, o vetor, neste ponto, também não precisa ser modificado, visto que 18
e 20 ja estão ordenados.

8 6 10 15 18 20 1

Por fim, temos que comparar vetor[5]=20 com vetor[6]=1. Ao verificar se 20 > 1, então o resultado foi true
e, neste ponto, temos um problema, visto que os dois números não estão ordenados. Devemos fazer esta
troca novamente:
aux = vetor[5];
vetor[5] = vetor[6];
vetor[6] = aux;
Como resultado, o vetor terá a seguinte configuração:

8 6 10 15 18 1 20

Observe que o processo sempre faz a comparação de dois números consecutivos:

Primeiro com segundo. Se precisar trocar valores, troque.

Segundo com terceiro. Se precisar trocar valores, troque.

Terceiro com quarto. Se precisar trocar valores, troque. E assim por diante.

55
Observe também que, ao comparar todos os valores, o vetor não está em ordem! Este processo de
comparação deve ser executado novamente, desde o início.

Comparar 8 > 6, precisamos trocar de lugar.

6 8 10 15 18 1 20

Comparar 8 > 10, não trocamos os valores neste momento.

6 8 10 15 18 1 20

Comparamos 10 > 15, não precisamos trocar os valores neste momento.

6 8 10 15 18 1 20

Comparamos 15 > 18, não precisamos trocar os valores neste momento.

6 8 10 15 18 1 20

Comparamos 18 > 1. Aqui temos um problema e, portanto, precisamos fazer a troca dos valores:

6 8 10 15 1 18 20

Para concluir, comparamos 18 > 20. Aqui não precisamos trocar os valores. O vetor resultante é:

6 8 10 15 1 18 20

Observe neste momento que o vetor ainda não se encontra ordenado.

Neste caso, precisamos realizar todo o processo de comparação novamente.

6>8 não troca 6 8 10 15 1 18 20


8>10 não troca 6 8 10 15 1 18 20
10>15 não troca 6 8 10 15 1 18 20
15>1 troca 6 8 10 15 1 18 20

6 8 10 1 15 18 20
15>18 não troca 6 8 10 1 15 18 20
18>20 não troca 6 8 10 1 15 18 20

Observando novamente o vetor, temos que ele ainda não se encontra ordenado. O processo é reiniciado
novamente.

6>8 não troca 6 8 10 1 15 18 20


8>10 não troca 6 8 10 1 15 18 20
10>1 troca 6 8 10 1 15 18 20

6 8 1 10 15 18 20
10>15 não troca 6 8 1 10 15 18 20

56
15>18 não troca 6 8 1 10 15 18 20
18>20 não troca 6 8 1 10 15 18 20

Observando novamente o vetor, temos que ele ainda não se encontra ordenado. O processo é reiniciado
novamente.

6>8 não troca 6 8 1 10 15 18 20


8>1 troca 6 8 1 10 15 18 20

6 1 8 10 15 18 20
8>10 não troca 6 1 8 10 15 18 20
10>15 não troca 6 1 8 10 15 18 20
15>18 não troca 6 1 8 10 15 18 20
18>20 não troca 6 1 8 10 15 18 20

Observando novamente o vetor, temos que ele ainda não se encontra ordenado. O processo é reiniciado
novamente.

6>1 troca 6 1 8 10 15 18 20

1 6 8 10 15 18 20
6>8 não troca 1 6 8 10 15 18 20
8>10 não troca 1 6 8 10 15 18 20
10>15 não troca 1 6 8 10 15 18 20
15>18 não troca 1 6 8 10 15 18 20
18>20 não troca 1 6 8 10 15 18 20

Observando novamente o vetor, temos que neste momento, sim. Agora o vetor já se encontra ordenado.

Observe o funcionamento do método de ordenação por bolha:

• Compara-se um valor com o próximo. Se precisar fazer a troca de posição, troque;


• Repita o processo anterior até que todos os valores tenham sido comparados;
• Reinicie o processo. Os dois itens anteriores deverão ser executados n-1 vezes, sendo n o
tamanho do vetor. Ou seja, se o vetor tem tamanho 7, o processo de comparação deve ser
executado 6 vezes.

Algoritmo de Ordenação por Inserção


O algoritmo de ordenação por inserção (Insertion Sort) funciona de forma análoga ao que fazemos quando
estamos ordenado as cartas de um baralho. Neste algoritmo, cada valor é considerado um a um, e são
inseridos em sua respectiva posição entre os valores já ordenados.

Usando a ordenação de cartas de baralho como exemplo, o processo de ordenação seria o seguinte:

57
• Lê uma carta
o Se for a primeira carta lida, então ela ja se encontra em seu devido lugar
o Lê outra carta
• Encontra a posição desta nova carta (ou será antes da primeira carta ou depois)
• Lê a próxima carta e encontra a posição desta nova carta (será a primeira carta, a segunda carta
ou a terceira carta?)
• Lê a próxima carta e encontra a sua posição
• Lê a próxima carta e encontra a sua posição …. …. …. … …
• O processo segue até que a última carta é lida e colocada em sua devida posição.

O algoritmo funciona da seguinte maneira:

Percorrer o vetor:

1. Da esquerda para a direita


2. Encontrou elemento for a de ordem
a. Posiciona o elemento em seu local
b. Leva os “demais” valores uma casa pra frente

Considere o seguinte vetor:


int vetor[] = {10, 8, 6, 15, 18, 20, 1};
10 8 6 15 18 20 1

O primeiro valor, automaticamente, ja se encontra em seu devido lugar:

10 8 6 15 18 20 1

A partir do segundo valor, o algoritmo deve encontrar a sua posição ideal. Para isso, seguem-se os seguintes
passos:

• Passo 1: encontrar o lugar do número 8. Ele deve vir antes do 10.

8 → 10 6 15 18 20 1
Coloca o número 8 no seu devido lugar e o número 10 é enviado uma casa para frente.

8 10 6 15 18 20 1

• Passo 2: encontra o lugar do número 6. Ele deve vir antes do número 8.

6 → 8 10 15 18 20 1
Coloca o número 6 no seu devido lugar e os números 8 e 10 são enviados uma casa para frente.

6 8 10 15 18 20 1

• Passo 3: encontra o lugar do número 15. Ele já está em seu devido lugar.

6 8 10 15 18 20 1

• Passo 4: encontra o lugar do número 18. Ele já está em seu devido lugar.

6 8 10 15 18 20 1

58
• Passo 5: encontra o lugar do número 20. Ele já está em seu devido lugar.

6 8 10 15 18 20 1

• Passo 6: encontra o lugar do número 1. Ele deve vir antes do número 6.

1 → 6 8 10 15 18 20
Coloca o número 1 no seu devido lugar e os números 6, 8, 10, 15, 18 e 20 são enviados uma casa para frente.

1 6 8 10 15 18 20

Algoritmo de Ordenação por Seleção


O algoritmo de ordenação por seleção (Selection Sort) é considerado um dos algoritmos de seleção mais
simples.

Este algoritmo funciona da seguinte maneira:

• O vetor é lido da Esquerda para a Direita


• Encontrar o menor valor do vetor
• Trocar de posição este menor valor do vetor com o primeiro valor do vetor
• Encontrar o segundo menor valor do vetor
• Trocar de posição este segundo menor valor do vetor com o segundo valor do vetor
• Encontrar o terceiro menor valor do vetor
• Trocar este terceiro menor valor com o valor que esta na terceira posição do vetor
• … (continuar encontrando o quarto menor, quinto menor, etc.) … até que todos os valores
estejam em ordem.

Considere o seguinte vetor:


int vetor[] = {10, 8, 6, 15, 18, 20, 1};
10 8 6 15 18 20 1

• Passo 1: Encontrar o menor valor do vetor {10, 8, 6, 15, 18, 20, 1}. Este valor é o 1. Colocar ele na
primeira posição do vetor, trocando os valores:

1 8 6 15 18 20 10

• Passo 2: Encontrar o segundo menor valor do vetor (o menor valor entre a segunda e a última
posições, ou seja, {8, 6, 15, 18, 20, 10}). Este valor é o 6. Colocar ele na segunda posição do
vetor, trocando os valores:

1 6 8 15 18 20 10

• Passo 3: Encontrar o terceiro menor valor do vetor (encontrar o menor valor entre a terceira e a
última posições, ou seja, o menor entre {8, 15, 18, 20, 10}). Este valor é o 8. Como ele já se
encontra em sua devida posição, não é necessário realizar a troca dele com ele mesmo!

59
• Passo 4: Encontrar o quarto menor valor do vetor (ou seja, encontrar o menor valor da posição
atual até o fim do vetor {15, 18, 20, 10}). O menor valor é o 10. Logo, precisamos trocar o valor
10 com o valor (15) da quarta posição.

1 6 8 10 18 20 15

• Passo 5: Encontrar o quinto menor valor do vetor (encontrar o menor valor entre a quinta
posição e a última posição do vetor, ou seja, o menor de {18, 20, 15}). O menor valor é o 15 e,
portanto, devemos trocar ele de posição com o número 18 que esta ocupando a casa do quinto
número.

1 6 8 10 15 20 18

• Passo 6: Encontrar o sexto menor valor do vetor (encontrar o menor valor entre a sexta posição
e a última posição do vetor, ou seja, o menor de {20, 18}). O menor valor é o 18 e, portanto,
devemos colocar ele em sua devida posição, trocando os valores.

1 6 8 10 15 18 20
Como só restou o sétimo valor, último valor do vetor, então ele não precisa ser verificado ou trocado com
ninguém, pois já ocupa sua posição.

Vamos Praticar?
Tente resolver os seguintes algoritmos sozinho, individualmente. Caso não consiga, solicite auxílio aos
colegas e aos professores, mas não obtenha as respostas. Tente conseguir dicas de como resolver.

Após resolver os exercícios, aguarde um dia e tente resolvê-los novamente você mesmo, mas agora sem
utilizar as respostas e dicas como consulta. Se conseguiu resolver todos os exercícios sozinho, então você
está aprendendo o conteúdo!

BOLHA

Exercício 01: Utilizando o algoritmo de ordenação por Bolha (Bubble Sort) onde um ciclo de trocas
corresponde a fazer a comparação de todos os valores do vetor com os seus adjacentes. Considere o
seguinte vetor:

int valores[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};

Considere ainda que o vetor valores precise ser ordenado de forma crescente. Considerando o “pior caso”
(onde o vetor está completamente desordenado, na ordem inversa a que se deseja), quantos ciclos de troca
serão necessários para ordenar o vetor valores?

Exercício 02: Utilizando o seguinte vetor:

double precos[] = {1.99, 10.99, 10.50, 8.50, 7.49, 1599.45, 1400.00}

Apresente o “passo a passo” para a ordenação deste vetor utilizando o algoritmo Bubble Sort.

Exercício 03: Implemente um algoritmo que solicite ao usuário pelo tamanho de um vetor de números
inteiros. O algoritmo deve ser capaz de criar este vetor. O algoritmo deve solicitar ao usuário por todos os
60
dados deste vetor. Apresente os dados informados pelo usuário em ordem crescente. Utilize o algoritmo de
ordenação por Bolha.

INSERÇÃO

Exercício 04: Utilizando o algoritmo de ordenação por Inserção (Insertion Sort) onde um passo (ou ciclo) de
trocas corresponde a encontrar o local exato de um valor e deslocar todos os próximos valores uma casa
para frente. Considere o seguinte vetor:

int valores[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};

Considere ainda que o primeiro valor do vetor já se encontra em sua devida posição e o primeiro passo se
inicia com a busca pela posição correta do segundo valor do vetor. Considerando o “pior caso” (onde o vetor
está completamente desordenado, na ordem inversa a que se deseja), quantos passos serão necessários
para ordenar o vetor valores?

Exercício 05: Utilizando o seguinte vetor:

double precos[] = {1.99, 10.99, 10.50, 8.50, 7.49, 1599.45, 1400.00}

Apresente o “passo a passo” para a ordenação deste vetor utilizando o algoritmo Insertion Sort.

Exercício 06: Implemente um algoritmo que solicite ao usuário pelo tamanho de um vetor de números
ponto-flutuantes. O algoritmo deve ser capaz de criar este vetor e solicitar por todos os números ao usuário
para o preenchimento deste vetor. Aplique o algoritmo de Ordenação por Inserção para ordenar os dados
deste vetor. Por fim, apresente o vetor ordenado ao usuário.

SELEÇÃO

Exercício 07: Utilizando o algoritmo de ordenação por Seleção (Selection Sort) onde um passo de trocas
corresponde a encontrar o menor valor e colocar em sua posição atual representada pelo passo, trocando os
valores. Considere o seguinte vetor:

int valores[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};

Considerando o “pior caso” (onde o vetor está completamente desordenado, na ordem inversa a que se
deseja), quantos passos serão necessários para ordenar o vetor valores?

Exercício 08: Utilizando o seguinte vetor:

double precos[] = {1.99, 10.99, 10.50, 8.50, 7.49, 1599.45, 1400.00}

Apresente o “passo a passo” para a ordenação deste vetor utilizando o algoritmo Selection Sort.

Exercício 09: Implemente um procedimento chamado ordenarSelecao que receba um vetor de números
inteiros nos parâmetros. Este procedimento deve ser capaz de ordenar o vetor utilizando o algoritmo de
ordenação por seleção.

Implemente um procedimento chamado exibirVetor que receba um vetor de números inteiros nos
parâmetros. Este procedimento deve ser capaz de exibir os dados do vetor na tela do computador.

No método principal, crie um vetor contendo 10 valores (pode criar com valores já atribuídos ou pode
solicitar os dados ao usuário para preencher este vetor). Chave o método para exibir os dados do vetor.
Chame o método para ordenar o vetor e, por fim, chame o método para exibir os dados do vetor novamente
após ordenado.

61
5. Busca de dados em Vetores

Objetivos de aprendizagem
Este capítulo tem como objetivo:

• Desenvolver o raciocínio lógico necessário para a busca


de valores armazenados nos vetores
• Utilizar diferentes algoritmos para a busca em vetores

O conteúdo trabalhado neste capítulo aborda:

• Busca Sequencial ou Linear


• Busca Binária

62
Recuperação de informação

A busca pelos dados (recuperação de informações) é uma das principais tarefas dos sistemas
computadorizados. Por exemplo: busca de um determinado valor em uma agenda de contatos, busca de
uma palavra e seu significado em um dicionário, busca por um determinado produto em algum site de
venda, busca pelo RA de determinado aluno pelo nome deste aluno, etc.

Imagine a seguinte situação. Temos a seguinte lista de valores em um vetor:

superHerois = {“Mulher Maravilha”, “Homem de Ferro”, “Homem Aranha”, “Super-Man”, “Batman”}

E precisamos saber se o “Capitão América” está presente na lista de nomes de super-heróis. Precisamos
realizar uma busca no vetor superHerois e verificar se ele se encontra na lista ou não.

Diversos algoritmos de busca de dados em vetores foram propostos, cada um deve ser aplicado em
determinados casos conforme os dados estejam organizados em seus respectivos vetores. A operação de
busca em um vetor por um valor x (qualquer valor a ser localizado) consiste em procurar por x em todo o
vetor e descobrir se ele está presente ou não neste vetor. Se ele estiver presente, ainda conseguimos obter
qual é a sua posição (índice) dentro do vetor.

Dois algoritmos de busca são bastante simples populares:

• Algoritmo de Busca Sequencial (também conhecido como Algoritmo de Busca Linear);


• Algoritmo de Busca Binária

Busca Sequencial
A forma mais simples de se buscar por um determinado valor em um vetor é percorrendo este vetor, valor
por valor, do primeiro ao último valor no vetor. Caso encontrarmos este valor no vetor, então basta
identificar qual seria a sua posição dentro do vetor. Por exemplo: considere o seguinte vetor de dados:
int vetor[] = {10, 8, 6, 15, 18, 20, 1};
10 8 6 15 18 20 1
[0] [1] [2] [3] [4] [5] [6]

Exemplo 1: Imagine que precisamos procurar pelo número 25.


Percorremos o vetor, da primeira posição até a última para comparar o valor atual com o 25 que desejamos
encontrar.
vetor[0] == 25 ➔ 10 == 25 ➔ falso
vetor[1] == 25 ➔ 8 == 25 ➔ falso
vetor[2] == 25 ➔ 6 == 25 ➔ falso
vetor[3] == 25 ➔ 15 == 25 ➔ falso
vetor[4] == 25 ➔ 18 == 25 ➔ falso
vetor[5] == 25 ➔ 20 == 25 ➔ falso
vetor[6] == 25 ➔ 1 == 25 ➔ falso fim do vetor. Valor 25 não foi encontrado.

63
Exemplo 2: Imagine que precisamos procurar pelo número 15.
Percorremos o vetor, da primeira posição até a última para comparar o valor atual com o 15 que desejamos
encontrar.
vetor[0] == 15 ➔ 10 == 15 ➔ falso
vetor[1] == 15 ➔ 8 == 15 ➔ falso
vetor[2] == 15 ➔ 6 == 15 ➔ falso
vetor[3] == 15 ➔ 15 == 15 ➔ verdadeiro encontramos valor 15. Não precisa terminar a busca.

O algoritmo de busca sequencial possui uma complexidade computacional excessiva, ou seja, demanda-se
um “longo tempo de processamento”. Se o valor a ser procurado estiver logo na primeira posição (melhor
caso), então temos que a complexidade do algoritmo de busca sequencial para um vetor de n posições C(n)
= O(1). O valor a ser buscado pode também estar na segunda posição, na terceira ou até a última posição.
𝑛+1
Desta forma, o caso médio (número médio de comparações) é de 2
. Se o valor a ser buscado não estiver
presente no vetor, ou seja, o pior caso da busca, precisamos de n comparações. Desta forma, dizemos que a
complexidade computacional para este algoritmo, no pior caso é de C(n) = O(n).

Algoritmo de Busca Binária


O algoritmo de Busca Binária só funciona caso o vetor estiver ordenado. Se o vetor não estiver em ordem,
então este algoritmo não poderá ser aplicado.

O processo de busca ocorre da seguinte maneira:

1. Obtemos o índice de início do vetor (inicio) e do fim do vetor (fim)


2. Encontramos o valor (índice do vetor) que está no meio do vetor
𝑖𝑛𝑖𝑐𝑖𝑜+𝑓𝑖𝑚
3. Comparamos se o valor a ser buscado é igual ao valor do meio ( 2
). Se for, então
encontramos este valor. Se não for:
a. Se o valor for maior que o valor presente no meio do vetor, então podemos “descartar”
todos os valores que estão do início até o meio. Logo, o espaço de busca diminuiu. O novo
espaço de busca faz com que o inicio seja a posição do meio+1 (o primeiro valor após o
meio).
b. Se o valor for menor que o valor presente no meio do vetor, então podemos “descartar”
todos os valores que estão do meio até o fim. Logo, o espaço de busca diminuiu. O novo
espaço de busca faz com que o fim seja a posição do meio-1 (o último valor antes o meio).

O algoritmo retorna em (2) e segue o processo de comparar com o valor do meio. Se encontrou o valor,
obteve sucesso; se não encontrou, redefinir o novo inicio ou o novo fim e reiniciar o processo para esta nova
“faixa de valores”.

Exemplo inicial: considere o seguinte vetor de dados:


int vetor[] = {10, 8, 6, 15, 18, 20, 1};
10 8 6 15 18 20 1
[0] [1] [2] [3] [4] [5] [6]

64
Para utilizar a busca binária, este vetor precisa estar ordenado. Logo, após a aplicação de algum algoritmo de
ordenação (Bolha, Inserção, Seleção ou chamar alguma função específica de ordenação da linguagem de
programação), o vetor estará da seguinte maneira:

vetor[] = {1, 6, 8, 10, 15, 18, 20};


1 6 8 10 15 18 20
[0] [1] [2] [3] [4] [5] [6]

Exemplo 1: Imagine que o número a ser procurado neste vetor seja o número 18.

INICIO DO PROCESSO:

inicio = 0 (primeiro índice do vetor)


fim = 6 (último índice do vetor)
meio = (0 + 6) / 2 = 3 (índice do meio do vetor)

1 6 8 10 15 18 20
[0] [1] [2] [3] [4] [5] [6]
inicio meio fim

Comparar se vetor[3] == 18 10 == 18 ➔ falso.

10 < 18 ➔ verdadeiro, logo, o 18 deve estar do lado da direita do vetor.

Precisamos atualizar o valor do ínicio e o do meio.

inicio = meio + 1 = 3 + 1 = 4 (primeiro índice do vetor. Descarta toda a primeira metade do vetor)
fim = 6 (último índice do vetor. O último valor não mudou de lugar)
meio = (4 + 6) / 2 = 5 (novo índice do meio do vetor)

1 6 8 10 15 18 20
[0] [1] [2] [3] [4] [5] [6]
inicio meio fim

Comparar se vetor[5] == 18 18 == 18 ➔ verdadeiro. Logo, encontramos o valor no vetor.

Observe que para localizar o valor 18 no vetor, apenas duas comparações foram realizadas:

10 == 18

18 == 18

Desta forma, a busca em vetores ordenados utilizando o método de busca binária se torna mais eficiente
que a busca sequencial, onde (no caso do vetor ordenado) seriam necessárias 6 comparações (1==18, 6==18,
8==18, 10==18, 15==18 e 18==18).

65
Exemplo 2: Imagine que o número a ser procurado neste vetor seja o número 35.

INICIO DO PROCESSO:

inicio = 0 (primeiro índice do vetor)


fim = 6 (último índice do vetor)
meio = (0 + 6) / 2 = 3 (índice do meio do vetor)

1 6 8 10 15 18 20
[0] [1] [2] [3] [4] [5] [6]
inicio meio fim

Comparar se vetor[3] == 35 10 == 35 ➔ falso.

10 < 35 ➔ verdadeiro, logo, o 35 deve estar do lado da direita do vetor.

Precisamos atualizar o valor do ínicio e o do meio.

inicio = meio + 1 = 3 + 1 = 4 (primeiro índice do vetor. Descarta toda a primeira metade do vetor)
fim = 6 (último índice do vetor. O último valor não mudou de lugar)
meio = (4 + 6) / 2 = 5 (novo índice do meio do vetor)

1 6 8 10 15 18 20
[0] [1] [2] [3] [4] [5] [6]
inicio meio fim

Comparar se vetor[5] == 35 18 == 35 ➔ falso.

18 < 35 ➔ verdadeiro, logo, o 35 deve estar do lado da direita do vetor.

Precisamos atualizar o valor do ínicio e o do meio.

inicio = meio + 1 = 5 + 1 = 6 (primeiro índice do vetor. Descarta toda a primeira metade do vetor)
fim = 6 (último índice do vetor. O último valor não mudou de lugar)
meio = (6 + 6) / 2 = 6 (novo índice do meio do vetor)

1 6 8 10 15 18 20
[0] [1] [2] [3] [4] [5] [6]
inicio
meio
fim

Comparar se vetor[6] == 35 20 == 35 ➔ falso.

20 < 35 ➔ verdadeiro, logo, o 35 deve estar do lado da direita do vetor.

Precisamos atualizar o valor do ínicio e o do meio.

inicio = meio + 1 = 6 + 1 = 7 (primeiro índice do vetor. Descarta toda a primeira metade do vetor)

Como não existe nenhum índice vetor[7], já que o vetor vai até vetor[6], então o valor 35 não está presente
neste conjunto de dados.

Observe que neste caso, para localizar o valor 35 no vetor, apenas três comparações foram realizadas:
66
10 == 35
18 == 35
20 == 35

Desta forma, a busca em vetores ordenados utilizando o método de busca binária se torna mais eficiente
que a busca sequencial, onde (no caso do vetor ordenado) seriam necessárias 7 comparações (1==35, 6==35,
8==35, 10==35, 15==35, 18==35 e 20 == 35).

Exemplo 3: Imagine que o número a ser procurado neste vetor seja o número 8.

INICIO DO PROCESSO:

inicio = 0 (primeiro índice do vetor)


fim = 6 (último índice do vetor)
meio = (0 + 6) / 2 = 3 (índice do meio do vetor)

1 6 8 10 15 18 20
[0] [1] [2] [3] [4] [5] [6]
inicio meio fim

Comparar se vetor[3] == 8 10 == 8 ➔ falso.

10 < 8 ➔ falso, logo, o 8 deve estar do lado da esquerda do vetor.

Precisamos atualizar o valor do fim e o do meio.

inicio = 0 (primeiro índice do vetor não precisou ser modificado)


fim = meio - 1 = 3 – 1 = 2 (último índice do vetor. A metade da direita do vetor é descartada)
meio = (0 + 2) / 2 = 1 (novo índice do meio do vetor)

1 6 8 10 15 18 20
[0] [1] [2] [3] [4] [5] [6]
inicio meio fim

Comparar se vetor[1] == 8 6 == 8 ➔ falso.

6 < 8 ➔ verdadeiro, logo, o 8 deve estar do lado da direita do vetor.

Precisamos atualizar o valor do ínicio e o do meio.

inicio = meio + 1 = 1 + 1 = 2 (primeiro índice do vetor. Descarta a primeira metade do vetor)


fim = 2 (último índice do vetor. O último valor não mudou de lugar)
meio = (2 + 2) / 2 = 2 (novo índice do meio do vetor)

1 6 8 10 15 18 20
[0] [1] [2] [3] [4] [5] [6]
inicio
meio
fim

Comparar se vetor[2] == 8 8 == 8 ➔ verdadeiro. Logo, encontramos o valor no vetor.

67
Observe que para localizar o valor 8 no vetor, apenas três comparações foram realizadas:

10 == 8
6 == 8
8 == 8 e encontrou o valor em vetor[2]

LEMBRE-SE: a comparação do valor a ser buscado no vetor é SEMPRE feita no valor do meio.

Se o valor estiver para a direita: inicio = meio + 1

Se o valor estiver para a esquerda: fim = meio – 1


𝑖𝑛𝑖𝑐𝑖𝑜+𝑓𝑖𝑚
O cálculo do meio sempre será 2
. Como os índices são números inteiros, sempre a parte inteira da
divisão será considerada como o meio. Por exemplo:

Se inicio = 0 e fim = 5, o meio seria (0+5)/2 que pe 5 / 2 = 2.5. Desta forma o meio é 2.

No algoritmo de busca binária, como cada comparação faz a redução do “espaço de busca” por um fator de
2 (o número de possíveis candidatos é reduzido à metade), este algoritmo possui uma complexidade
computacional para um vetor de n valores de C(n) = O(log2(n))

(valor do log2 arredondado para cima). Exemplo. Para um vetor de n=10, temos que log2(10) = 3.3, logo,
seriam 4 comparações no máximo a serem executadas.

Se um vetor tiver n=25 números, então log2(25) = 4.6, logo, teríamos no máximo 5 comparações na busca.

Vamos Praticar?
Tente resolver os seguintes algoritmos sozinho, individualmente. Caso não consiga, solicite auxílio aos
colegas e aos professores, mas não obtenha as respostas. Tente conseguir dicas de como resolver.

Após resolver os exercícios, aguarde um dia e tente resolvê-los novamente você mesmo, mas agora sem
utilizar as respostas e dicas como consulta. Se conseguiu resolver todos os exercícios sozinho, então você
está aprendendo o conteúdo!

SEQUENCIAL

Exercício 01: Elabore um algoritmo que solicite ao usuário pela quantia de números inteiros que ele deseja
informar a um vetor. Crie este vetor e faça a leitura dos dados para preencher este vetor. Em seguida, solicite
ao usuário por um valor a ser buscado neste vetor.
Faça a busca no vetor utilizando o algoritmo de busca sequencial. Apresente na tela uma mensagem
informando se o valor está presente ou não neste vetor.
Exercício 02: Considere o seguinte vetor:
v = {5, 4, 1, 6, 10, 3}

68
• Considere que devemos verificar se o número 3 está presente ou não neste vetor. Neste caso, o
algoritmo de busca sequencial terá um melhor desempenho se o vetor v estiver ordenado ou se ele
estiver não-ordenado? Por que?
• Considere que devemos verificar se o número 10 está presente ou não neste vetor. Neste caso, o
algoritmo de busca sequencial terá um melhor desempenho se o vetor v estiver ordenado ou se ele
estiver não-ordenado? Por que?
• Considere que devemos verificar se o número 55 está presente ou não neste vetor. Neste caso, o
algoritmo de busca sequencial terá um melhor desempenho se o vetor v estiver ordenado ou se ele
estiver não-ordenado? Por que?
Exercício 03: Implemente um algoritmo que tenha um método chamado ordenaSelecao. Este método deve
receber um vetor de números inteiros no parâmetro. Na sua execução, este método deve ordenar o vetor
recebido no parâmetro utilizando o algoritmo de ordenação por seleção.

Este algoritmo também deve ter um método chamado buscaSequencial. Este método deve receber nos
parâmetros um vetor de números inteiros e também um outro número inteiro que será pesquisado no
vetor. O método deverá retornar a posição em que este número se encontra no vetor (índice), ou então,
deverá retornar -1 caso o valor não esteja presente no vetor.

No método principal, criar um vetor contendo 10 posições preenchidos com números aleatórios entre 0 e
100. Em seguida, ordene este vetor chamando o método de ordenação por seleção. Solicite ao usuário por
um número. Chame o método de busca sequencial fornecendo o vetor e o número. Apresente na tela uma
mensagem indicando se o número está presente ou não no vetor (utilizando o índice retornado).

BINÁRIA
Exercício 04: Elabore um algoritmo que solicite ao usuário pela quantia de números inteiros que ele deseja
informar a um vetor. Crie este vetor e faça a leitura dos dados para preencher este vetor. Em seguida, solicite
ao usuário por um valor a ser buscado neste vetor.
Chame o método ordenaBolha passando o vetor como parâmetro. Este método deve ser capaz de ordenar o
vetor recebido no parâmetro utilizando o algoritmo de ordenação por Bolha.
Por fim, apresente uma mensagem dizendo se o valor a ser buscado está presente ou não no vetor. A busca
deve ocorrer por meio do método de busca binária.
Exercício 05: Considere o seguinte vetor:
v = {5, 4, 1, 6, 10, 3}
Considere que devemos verificar se o número 3 está presente ou não neste vetor. Para este vetor, o algoritmo
de busca binária pode ser aplicado? Explique sua resposta.
Exercício 06: Considere o seguinte vetor:
v = {5, 4, 1, 6, 10, 3}
Considere que devemos verificar se o número 3 está presente ou não neste vetor. Para isso, este vetor deve
ser ordenado. Utilizando o método de busca binária neste vetor ordenado, quais valores seriam comparados
na busca pelo número 3 neste vetor?
Exercício 07: Considere o seguinte vetor de números inteiros:

vetor = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}

Como o vetor está ordenado, precisamos utilizar o algoritmo de busca binária para localizar o número 15.
Quais seriam os números a serem comparados nesta busca?

Exercício 08: Implemente um algoritmo que tenha um método chamado buscaBinaria que receba dois
parâmetros, sendo um vetor de números inteiros e um outro número inteiro. Este método deve ser capaz de
realizar a busca binária no vetor, verificando se o número inteiro informado está presente ou não no vetor.
Este método não deve retornar nada, apenas apresentar a mensagem.

69
Implemente também um método chamado ordenar. Este método deve receber um vetor de números
inteiros nos parâmetros e deve ordenar este vetor utilizando qualquer algoritmo de ordenação escolhido por
você.

No algoritmo principal, crie um vetor contendo 40 números inteiros. Preencha este vetor com números
aleatórios entre 0 e 500. Chame o método para a ordenação do vetor. Solicite um número ao usuário para
ser buscado neste vetor. Chame o método de busca binária fornecendo nos parâmetros o vetor preenchido
e o número a ser buscado.

70
6. Estruturas de Dados
Heterogêneas

Objetivos de aprendizagem
Este capítulo tem como objetivo:

• Apresentar as estruturas de dados heterogêneas


• Desenvolver algoritmos que utilizem estruturas de
dados heterogêneas

O conteúdo trabalhado neste capítulo aborda:

• Criação de estruturas de dados heterogêneas


• Acesso aos atributos/campos destas estruturas

71
Registros

Uma estrutura de dados homogênea (unidimensional *vetor* ou multidimensional *matriz*), também


conhecida como Array, permite o armazenamento de uma lista de valores, onde todos os valores pertencem
ao mesmo tipo de dado, utilizando-se um único nome de variável. Para se acessar cada valor desta lista,
precisamos informar o índice deste array. Por exemplo, podemos ter um vetor de números inteiros, ou um
vetor de valores ponto-flutuante, ou mesmo um vetor de Strings.

Quando falamos em estrutura de dados heterogênea, nos referimos a uma estrutura que pode conter
diversos valores, e cada valor pode ter um tipo de dado diferente. Como exemplo, uma estrutura pode
armazenar um valor do tipo String, outro valor do tipo inteiro, outro valor do tipo ponto-flutuante, etc. É
comum chamarmos as estruturas de dados heterogêneas de Registro (em especial em linguagens como
Pascal) ou mesmo de estrutura (struct em linguagem C/C++).

Um registro representa um “novo tipo de dado” que é criado pelo programador. Ao criarmos variáveis deste
tipo de dado, podemos acessar cada informação deste registro individualmente.

Exemplo: considere um registro (novo tipo de dado) chamado de Data. Uma data possui as seguintes
informações: dia, mês e ano.
registro Data {
dia : integer
mes : integer
ano : integer
}

As variáveis dia, mes e ano são conhecidas como “campos” do registro. Desta forma, o registro Data possui
três campos.

Após definir um tipo de estrutura (registro), podemos declarar variáveis deste tipo:
dataNascimento : Data

Desta forma, uma variável chamada dataNascimento foi criada e ela é do tipo Data, ou seja, dentro da
variável dataNascimento, temos 3 campos disponíveis para armazenar valores. Para acessar individualmente
cada campo, utilizamos o operador ponto (.):
dataNascimento.dia = 05
dataNascimento.mes = 11
dataNascimento.ano = 2019
As linguagens de programação atuais são conhecidas como Linguagens Orientadas a Objetos (exemplo: Java,
C++, Dart, Python, Object Pascal, etc.). Nestas linguagens, geralmente podemos definir os registros por meio
de uma estrutura conhecida como Classe.

OBSERVAÇÃO:
os conceitos de Classes e Objetos utilizados na Programação Orientada a Objetos
não serão tratados aqui. Usaremos classes/objetos para trabalhar como registros e
desenvolvimento do raciocínio lógico em Algoritmos.

72
Uma classe pode ser vista como um novo tipo de dado que possui um conjunto de dados (ou seja, uma
espécie de registro) e um conjunto de operações em uma só estrutura (trabalharemos apenas com dados e
não com operações neste momento). Chamamos de “atributo” todos os campos que pertencem a uma
classe.

Relembrando:

• Registro (em algoritmos) ➔ Classe (em Java)


• Campo do registro (em algoritmos) ➔ Atributo da classe (em Java)

Um objeto pode ser visto como uma variável que é do tipo de uma classe (chamamos de instância de uma
classe).

Relembrando:

• Objeto ➔ Variável que é do tipo de uma Classe.

A implementação de sistemas utilizando registros/classes permite organizar o código e definir funções


específicas para tratamento dos dados das classes.

Em Java, podemos criar uma classe em um novo arquivo que possui a extensão .java conforme o exemplo a
seguir.

Arquivo: Arquivo.java
public class Arquivo {
<tipo> atributo1;
<tipo> atributo2;
<tipo> atributoN;
}

Considere que precisamos implementar um sistema e, nesta implementação, uma Data precise ser definida,
já que podemos ter a Data de Nascimento de uma pessoa, a Data de Matrícula de um aluno, a Data de uma
Avaliação na faculdade, a Data do Início das Aulas, a Data do início das férias escolares, entre outras datas.
Desta forma, podemos definir Data como uma classe e criarmos diversas variáveis do tipo Data, uma para
cada informação desejada. Para todas as datas, temos o dia, o mês e o ano.

Arquivo: Data.java
public class Data {
int dia;
int mes;
int ano;
}

Em uma outra classe dentro do mesmo projeto, dentro do método principal, podemos criar nossas variáveis
com base no novo tipo de dado que implementamos (classe Data). Por exemplo:
Data d = new Data();
Para acessarmos cada um dos atributos, basta utilizar o nome da variável, seguida pelo operador ponto . e
do nome do atributo que desejamos acessar:
d.dia = 14;
73
Por exemplo, considere o arquivo UsandoDatas.java com o seguinte código que contém o método principal e
se encontra no mesmo projeto que o arquivo Data.java:

Arquivo: UsadoDatas.java
public class UsandoDatas {

public static void main(String[] args) {


Data d1 = new Data();
d1.dia = 14;
d1.mes = 2;
d1.ano = 2021;

System.out.println("Data: " + d1.dia + "/" + d1.mes + "/" + d1.ano);

Data d2 = new Data();


d2.dia = 15;
d2.mes = 10;
d2.ano = 2022;

System.out.println("Data: " + d2.dia + "/" + d2.mes + "/" + d2.ano);

if(d1.ano == d2.ano) {
System.out.println("As duas datas são do mesmo ano!");
}
}

Vetores de Registros
Podemos ter ainda um vetor (ou matriz) de registros (classes).

Exemplo: precisamos representar um conjunto de alunos de uma faculdade.

Os alunos devem possuir em seu registro o nome e a idade.

Arquivo: Aluno.java
public class Aluno {
String nome;
int idade;
}

Na classe que contém o método principal, podemos ter:

Arquivo: UsandoVetores.java
import java.util.Arrays;
public class UsandoVetores {
public static void main(String[] args) {
//cria o vetor que receberá a lista de alunos e
//preenche o vetor com os alunos
Aluno[] alunos = new Aluno[5];

74
Arrays.fill(alunos, new Aluno());

alunos[0].nome = "Ana Maria";


alunos[0].idade = 15;

alunos[1].nome = "Carlos Alexandre";


alunos[1].idade = 16;

System.out.println("Primeiro aluno: " + alunos[0].nome);


}
}

A partir do momento que conseguimos acessar o aluno fornecendo o índice do vetor e já exibir objetos em
cada índice, podemos utilizar o operador ponto (.) para acessar os atributos:
alunos[0].nome
alunos [0].idade
alunos [1].nome
alunos [1].idade

Registros em parâmetros de subalgoritmos


Podemos passar objetos como parâmetro para funções e procedimentos e também retornar objetos nas
funções:

Arquivo: ObjetosParametro.java
import java.util.Arrays;
import java.util.Scanner;
public class UsandoVetores {

public static void exibirAluno(Aluno alu) {


System.out.println("Nome: " + alu.nome);
System.out.println("Idade: " + alu.idade + "\n");
}

public static Aluno obterAluno() {


Aluno a = new Aluno();
Scanner teclado = new Scanner(System.in);
System.out.println("Informe o nome do aluno: ");
a.nome = teclado.nextLine();
System.out.println("Informe a idade do aluno: ");
a.idade = teclado.nextInt();
teclado.nextLine(); //limpar o buffer do teclado
return a;
}

public static void main(String[] args) {


Aluno a1 = obterAluno();
Aluno a2 = obterAluno();
System.out.println("RELATÓRIO:");
exibirAluno(a1);
exibirAluno(a2);
}
}

75
Vamos Praticar?
Tente resolver os seguintes algoritmos sozinho, individualmente. Caso não consiga, solicite auxílio aos
colegas e aos professores, mas não obtenha as respostas. Tente conseguir dicas de como resolver.

Após resolver os exercícios, aguarde um dia e tente resolvê-los novamente você mesmo, mas agora sem
utilizar as respostas e dicas como consulta. Se conseguiu resolver todos os exercícios sozinho, então você
está aprendendo o conteúdo!

Exercício 01: Um telefone celular precisa ser representado em um programa de computador. Sabe-se que
este telefone possui uma marca, um modelo, um ano de fabricação e um preço. Implemente uma estrutura
para representar os telefones celulares. Crie três celulares, solicite os dados ao usuário para cada um e
apresente-os na tela.

Exercício 02: Um programa de computador deve ser capaz de armazenar dados sobre as partes de uma
casa. Como a casa possui vários cômodos e cada cômodo possui uma porta, precisa-se de uma estrutura
capaz de representar as portas da casa. Sabe-se que toda porta deve ter registrado a sua largura, sua altura,
seu peso e o seu material (ex: madeira, alumínio, etc.). Crie três objetos que representem portas (ex: porta
da sala, porta do quarto e porta da cozinha). Preencha os dados da porta solicitando-os ao usuário. Em
seguida, apresente os dados das portas.

Exercício 03: Escreva um modelo para representar uma lâmpada que está à venda em um supermercado.
Que atributos devem ser representados por este modelo?

Exercício 04: Considere que uma lâmpada possua os seguintes estados: apagada e acesa. Implemente uma
estrutura capaz de representar o estado da lâmpada.

Implemente um método (função ou procedimento) chamado ascenderLuz que receba a lâmpada por
parâmetro e faça com que a lâmpada fique acesa. Implemente o método pagarLuz que receba a lâmpada por
parâmetro e faça com que a lâmpada fique apagada. Implemente o método exibirLuz que receba a lâmpada
como parâmetro e apresente uma mensagem informando se a lâmpada está acesa ou apagada.

DICA: Em Java, objetos são passados “por referência” nos parâmetros dos métodos. Ou seja, se um objeto
for recebido no parâmetro de um método, todas as alterações feitas neste objeto dentro do método serão
automaticamente modificadas no objeto original fornecido ao chamar o método.

Exercício 05: Imagine uma lâmpada que possa ter três estados: apagada, acesa e meia-luz. Estes estados são
representados por um valor de 0 a 100, onde 0 representa o estado apagado, de 80 a 100 representa o
estado aceso e de 1 a 79 representa o estado meia-luz.

Implemente um programa capaz de representar uma lâmpada conforme o enunciado.

Implemente uma função chamada criarLampada que crie uma lâmpada e solicite a intensidade da lâmpada,
retornando o objeto criado.

Implemente um procedimento chamado exibirLampada que recebe uma lâmpada como parâmetro e
apresente na tela se a lâmpada está apagada, acesa ou em meia-luz.

Exercício 06: Uma agência bancária deve ser capaz de representar contas bancárias. Sabe-se que para as
contas bancárias precisa-se conhecer a data de abertura (formada pelo dia, mês e ano), o cliente (formado
pelo nome e pela data de nascimento) e pelo saldo.

76
Implemente um programa que seja capaz de representar uma conta bancária. Faça uma análise de quais
classes (registros) serão necessários e a relação entre estes registros.

Implemente um método chamado lerData que crie um objeto de uma Data e faça a leitura do dia, mês e ano,
retornando o objeto criado.

Implemente um método chamado lerCliente que crie um objeto de um Cliente e faça a leitura do nome e da
data de nascimento, retornando o objeto criado.

Implemente um método chamado lerConta que crie uma conta bancária e faça a leitura de todos os valores
da conta, retornando o objeto criado.Implemente um método chamado exibirContaBancaria que receba
uma conta bancária como parâmetro e exiba na tela todos os dados da conta bancária.

No algoritmo principal, chame os métodos necessários para que uma conta bancária possa ser obtida e
exibida na tela.

Exercício 07: Uma pessoa possui um nome, uma data de nascimento (dia, mês e ano) e uma hora de
nascimento (hora e minuto). Implemente um programa que seja capaz de representar uma pessoa
(utilizando registros).

Exercício 08: Uma televisão deve ser capaz de armazenar seu status (ligada ou desligada) e o número do
canal a ser exibido.

Implemente um registro capaz de representar esta situação.

Implemente um método chamado aumentarCanal que receba uma televisão como parâmetro e aumente o
canal em uma unidade (ir para o próximo canal), caso a TV esteja ligada.

Implemente um método chamado diminuirCanal que receba uma televisão como parâmetro e diminua o
canal em uma unidade (ir para o canal anterior), caso a TV esteja ligada.

Implemente um método capaz de exibir o estado atual da TV (se ela está ligada e o canal atual, ou se ela está
desligada). Considere que a TV possa ter canais representados de 0 a 99 (canais fora desta faixa não podem
ser exibidos pela TV).

Exercício 09: (continuação ex. 8) Adicione na classe Televisão os atributos que representam a marca da TV e
o número de polegadas que a TV possui.

Implemente um método chamado criarTV que crie um objeto da televisão e retorne o objeto criado.

Implemente um método chamado lerDadosTV que receba como parâmetro uma TV e faça a leitura dos
dados iniciais da TV solicitando-os ao usuário.

Implemente um método chamado exibirTV que exiba todos os dados da TV.

Exercício 10: Implemente uma classe chamada Matematica. Esta classe deve possuir dois atributos
representando dois valores numéricos e um atributo representando uma operação matemática.

Implemente um método chamado getCalculo que receba um objeto do tipo Matematica como parâmetro,
efetue a operação operação matemática (atributo que representa a operação) com os dois valores
numéricos do objeto e retorne o resultado.

Teste seus códigos.

Exercício 11: Considere as seguintes classes:

77
O diagrama representa uma pessoa que possui um nome e uma data de nascimento formada pelo dia, mês e
ano.

Implemente as classes conforme o diagrama.

Implemente um método chamado calcularIdade que receba uma pessoa por parâmetro, calcule e retorne a
idade da pessoa.

Implemente um método chamado lerDados que receba uma pessoa por parâmetro e faça a leitura dos
dados desta pessoa.

Implemente um método chamado exibirDados que receba uma pessoa por parâmetro e exiba os dados
desta pessoa, incluindo a sua idade atual.

No algoritmo principal, crie três objetos do tipo Pessoa e faça a leitura dos dados dos objetos:

• Albert Einstein (nascido em 14/3/1879)


• Isaac Newton (nascido em 4/1/1643)
• Você (seus dados pessoais)

Por fim, exiba os dados das três pessoas.

78

Você também pode gostar