Você está na página 1de 186

ALGORITMOS E LÓGICA DE

PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

ESTRUTURA DE DADOS I

PROF. CARLOS DANILO LUZ

FACULDADE CATÓLICA PAULISTA | 1


Diretor Geral | Valdir Carrenho Junior


A Faculdade Católica Paulista tem por missão exercer uma
ação integrada de suas atividades educacionais, visando à
geração, sistematização e disseminação do conhecimento,
para formar profissionais empreendedores que promovam
a transformação e o desenvolvimento social, econômico e
cultural da comunidade em que está inserida.

Missão da Faculdade Católica Paulista

Av. Cristo Rei, 305 - Banzato, CEP 17515-200 Marília - São Paulo.
www.uca.edu.br

Nenhuma parte desta publicação poderá ser reproduzida por qualquer meio ou forma
sem autorização. Todos os gráficos, tabelas e elementos são creditados à autoria,
salvo quando indicada a referência, sendo de inteira responsabilidade da autoria a
emissão de conceitos.
ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

SUMÁRIO
AULA 01 CONCEITOS INICIAIS SOBRE LINGUAGEM DE 05
PROGRAMAÇÃO C

AULA 02 ENTRADA E SAÍDA DE DADOS, EXPRESSÕES E 18


OPERADORES

AULA 03 INSTRUÇÕES CONDICIONAIS DE DECISÃO 37

AULA 04 ESTRUTURAS DE REPETIÇÃO, VETORES E MATRIZES 56

AULA 05 FUNÇÕES E PONTEIROS 72

AULA 06 LISTAS ENCADEADAS E DUPLAMENTE ENCADEADAS 82

AULA 07 LISTAS ORDENADAS E CIRCULARES 90

AULA 08 LISTAS DINÂMICAS 97

AULA 09 ESTRUTURAS DE PILHAS E FILAS 108

AULA 10 ÁRVORES BINÁRIA E ESTRITAMENTE BINÁRIA 123

AULA 11 ÁRVORE BINÁRIA COMPLETA E IMPLEMENTAÇÃO EM 132


LINGUAGEM C

AULA 12 BUSCAS EM ÁRVORES BINÁRIAS E MONTAGEM DE 141


ÁRVORES BINÁRIAS

AULA 13 TÉCNICAS DE ORDENAÇÃO BUBBLESORT E 149


INSERTIONSORT

AULA 14 TÉCNICAS DE ORDENAÇÃO SELECTIONSORT E QUICKSORT 155

AULA 15 TÉCNICAS DE ORDENAÇÃO SHELLSORT E MERGESORT 163

AULA 16 TEORIA DOS GRAFOS 173

FACULDADE CATÓLICA PAULISTA | 3


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

INTRODUÇÃO

Caro(a) aluno(a), seja bem-vindo(a) a este livro que foi elaborado especialmente
para que você possa conhecer os conceitos básicos e iniciais de lógica de programa-
ção e estrutura de dados. O livro está dividido em diversas aulas, nas quais aprende-
remos os conceitos iniciais da linguagem de programação C, que é uma linguagem
muito popularizada por ser considerada base para o desenvolvimento das linguagens
atuais, como C#, JAVA, PHP, entre outras. Todas as unidades apresentam exemplos
utilizando a linguagem C.
Veremos um breve histórico da linguagem C, suas características e os conceitos
iniciais sobre programação. Estudaremos como é a estrutura básica de um programa
em linguagem C, a declaração de variáveis e manipulação de dados através de entrada
e saída de dados. Conheceremos também os operadores e expressões, entre outros
conceitos que o(a) ajudarão no desenvolvimento de seus programas em linguagem
C, através disso, você, aluno(a), terá o conhecimento necessário para desenvolver os
seus primeiros programas em linguagem C.
Será apresentado a você as estruturas de dados em forma de árvore, que é muito
utilizada para a organização dos dados na memória por ser de fácil manipulação pelo
sistema. Iremos estudar também sobre as listas lineares que são um tipo de vetor
para armazenarmos e recuperamos dados. Veremos ainda as listas encadeadas, du-
plamente encadeadas, circulares e ordenadas. Por fim, será visto o conceito das duas
estruturas de dados mais importantes, estrutura de FILA e PILHA, conceitos esses
utilizados para diversos algoritmos de busca e ordenação de dados.
Conheceremos os conceitos sobre ordenação de dados, pois quanto mais organi-
zados e ordenados os elementos, mais rápida será a manipulação deles. Serão com-
preendidos alguns dos algoritmos de ordenação mais comuns como o BubbleSort
(método bolha), InsertionSort, ShellSort (concha), MergeSort (dividir para conquistar)
entre outros.
Por fim, vamos estudar sobre a teoria dos grafos, como esta teoria surgiu, a sua
importância para a área da computação, suas características e representações.
Desejo a você, aluno(a), uma ótima leitura e bons estudos!

FACULDADE CATÓLICA PAULISTA | 4


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 1
CONCEITOS INICIAIS SOBRE
LINGUAGEM DE PROGRAMAÇÃO C

Fonte: https://br.freepik.com/fotos-gratis/codigo-de-programacao-com-fundo-laptop_902700.htm

A linguagem C está entre uma das linguagens de programação mais conhecidas


entre a comunidade de programadores. Inicialmente desenvolvida para criação de sis-
temas operacionais, ao longo dos anos foi ganhando cada vez mais adeptos de sua
estrutura. Além de sistemas operacionais, a linguagem foi e ainda é muito utilizada
na criação de sistemas embarcados e jogos eletrônicos. Muitas vezes subestimada
por ser uma das primeiras linguagens de alto nível, a linguagem C oferece muitos
recursos e flexibilidade no desenvolvimento de software. Além disso, muito do que
iremos apresentar nesta unidade pode ser compartilhado com outras linguagens de
programação, visto que a estrutura apresentada possui características universais de
programação. Para iniciar nossa abordagem, vamos conhecer um pouco da história
dessa linguagem e suas primeiras contribuições para o desenvolvimento de software.

FACULDADE CATÓLICA PAULISTA | 5


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Neste primeiro momento, vamos apresentar um pouco da história e as caracterís-


ticas básicas da linguagem C. Esta que é uma das primeiras linguagens de programa-
ção e que deu origem a outras linguagens como C++, Java, C#, Objective C. Além de
influenciar o desenvolvimento de outras linguagens, a linguagem C é uma linguagem
bastante flexível, sendo facilmente utilizada em qualquer tipo de plataforma. Com
uma sintaxe simples e estruturada, a linguagem C permite a criação de programas
extremamente rápidos em tempo de execução.

1.1 Linguagem de programação C

Durante a evolução dos computadores, o desenvolvimento de softwares sempre


esteve condicionado à capacidade das linguagens de programação. À medida com
que os computadores foram avançando tecnologicamente, as linguagens de progra-
mação também tiveram avanços significativos que permitiram a criação de softwares
mais robustos. Dentre as linguagens de programação que permearam os primeiros
avanços da computação, a linguagem C foi uma das que se popularizou entre a comu-
nidade de programadores.
A linguagem C foi desenvolvida por Dennis Ritchie no início da década de 70, que
também era um dos responsáveis pelo desenvolvimento do sistema operacional Unix.
Inicialmente, a linguagem foi implementada em um computador DEC PDP-11 que uti-
liza o sistema operacional Unix. Vale ressaltar que a linguagem C origina-se a partir do
processo de desenvolvimento de outras linguagens como a BCPL, desenvolvida por
Martin Richards e que originou a criação da linguagem B, desenvolvida por Kenneth
Thompson. Pode-se dizer que a linguagem desenvolvida por Thompson foi a precur-
sora da linguagem C. Estes três indivíduos faziam parte da equipe de desenvolvedores
da Laboratórios Bell da AT&T, uma empresa de telecomunicações norte americana.
Inicialmente, a proposta da linguagem C era o desenvolvimento de sistemas opera-
cionais e compiladores, assim, uma nova versão do Unix foi totalmente desenvolvida
utilizando a nova linguagem. Isso fez com que a linguagem C ganhasse cada vez mais
adeptos pelo mundo, visto a popularidade do sistema Unix. Outro aspecto fundamen-
tal neste processo de disseminação da linguagem C foi por meio de uma publicação
feita no ano de 1978, denominada The C Programming Language por Kernigham e
Ritchie.
O sucesso do livro influenciou diretamente a adesão da linguagem por grande parte

FACULDADE CATÓLICA PAULISTA | 6


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

da comunidade de programadores. De acordo com Schildt (1997, p. 85), “embora não


houvesse um padrão, os códigos-fontes escritos em linguagem C, eram altamente
compatíveis”. Dessa forma, um programa que era escrito em um microcomputador
era facilmente compilado em outro.
Com a popularidade dos microcomputadores, um grande número de implementa-
ções de C foi criado. Quase que por um milagre, os códigos-fontes aceitos por essas
implementações eram altamente compatíveis (isto é, um programa escrito com um
deles podia normalmente ser compilado com sucesso usando-se outro) (SCHILDT,
1997, p. 3).
No entanto, a partir da década de 80, a linguagem C passou a ser adotada por
inúmeras empresas no desenvolvimento de aplicações de propósito geral. Esse cres-
cimento fez com que o número de compiladores para a linguagem C também au-
mentasse. Mas, existiam muitas discrepâncias entre eles, justamente por não haver
um padrão para a linguagem. Somente em 1983, foi estabelecido um padrão para a
linguagem C, por meio de um comitê organizado pelo American National Standards
Institute (ANSI). Atualmente, a maioria dos compiladores já adotam o padrão C ANSI.

A linguagem Estruturada C
Uma das características do C é o fato de ser uma linguagem estruturada. Embora
não apresente rigorosamente os mesmos atributos de outras linguagens estrutura-
das em blocos, ainda assim trata-se de uma linguagem estruturada, que permite a
compartimentalização do código e seus respectivos dados.
Por meio das sub-rotinas (funções), a linguagem emprega o uso de variáveis lo-
cais, dessa forma, eventuais ações que acontecem dentro de cada sub-rotina não
ocasionam efeitos inesperados em outras partes do código. O uso de variáveis locais
torna-se uma grande vantagem em relação às variáveis globais, visto que o uso exces-
sivo de variáveis globais pode resultar em erros de compilação ou até mesmo outras
situações indesejadas no programa.
A estrutura apresentada pela linguagem C permite ao programador compartilhar
funções de maneira fácil e dinâmica, de modo que não é necessário saber exatamen-
te como a função executa uma determinada ação. Basta que o programador saiba
o que ela faz e, então, chamá-la em um trecho de código que deseja contemplar. O
uso de funções estabelece a codificação em partes separadas, de acordo com suas
funcionalidades, permitindo um desenvolvimento modular. Assim como em outras lin-

FACULDADE CATÓLICA PAULISTA | 7


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

guagens, a linguagem C permite o uso de estruturas de repetição e estruturas condi-


cionais (laços), tornando o código mais limpo e eficiente.

1.2 Estrutura básica do arquivo em linguagem C

Agora que já conhecemos um pouco da estrutura que compõe a linguagem C, va-


mos avançar nossos estudos trazendo estes conceitos à prática. A seguir, temos um
exemplo de código em linguagem C, que apresenta a frase “Olá Mundo!”.
O primeiro passo para iniciarmos nosso programa é incluirmos a biblioteca que fun-
ciona como uma espécie de cabeçalho do programa, ou seja, deve ser declarada no
início do código. A biblioteca stdio.h é uma das mais conhecidas, pois permite utilizar
as funções de entrada e saída do programa, neste caso, os comandos printf e scanf.
No entanto, é óbvio que um programa pode possuir outras bibliotecas, considerando
suas necessidades específicas. Caso tente utilizar uma determinada função, cuja bi-
blioteca não tenha sido informada, certamente o programa apresentará um erro du-
rante a compilação. Mais adiante veremos outras bibliotecas.
Para declarar uma determinada biblioteca devemos utilizar o comando #include,
que representa a inclusão da biblioteca. Além disso, é importante destacar que toda
declaração de biblioteca deve ser informada entre os sinais <>. Segue abaixo o exem-
plo da biblioteca stdio.h:

#include <stdio.h>

Além da biblioteca, outro elemento obrigatório em nosso código é a função int main.
A função main define a estrutura contida dentro dela como sendo a parte principal do
programa. No padrão ANSI, esse tipo de função retorna um valor do tipo inteiro (int).
Assim, a declaração da função deve ser feita da seguinte forma:

#include <stdio.h>

int main(){

FACULDADE CATÓLICA PAULISTA | 8


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Após incluir a biblioteca e declarar a função int main, estamos prontos para apre-
sentar nosso primeiro programa em linguagem C com a expressão “Olá Mundo!”. Se-
gue abaixo o exemplo:

#include <stdio.h>

int main(){

printf(“Ola Mundo!!!”);

Basicamente, nosso primeiro programa em linguagem C está pronto. No entanto,


ainda precisamos adicionar o comando de retorno. Para isso utilizamos o comando
return:

#include <stdio.h>

int main(){

printf(“Ola Mundo!!!”);
return (0);

Opcionalmente, podemos atribuir um valor de retorno para o comando. Neste caso,


foi definido o valor 0 (zero), que representa a execução do programa com sucesso.
Com nosso primeiro programa totalmente finalizado, vamos à compilação e execu-
ção. Para realizar o processo de compilação e execução você poderá utilizar qualquer
IDE que interprete a linguagem de programação. Se estiver tudo ok, o programa está
pronto para ser executado:

Resultado do primeiro programa


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 9


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Após realizar esta breve sequência de passos, temos então nosso primeiro código
em linguagem C executado com sucesso.

1.3 Escrevendo código em linguagem C, primeiros passos

Ao escrever programas em C podemos utilizar IDEs que sejam compatíveis com a


linguagem. Como a DEVC++ , Eclipse, Netbeans, CodeBlocks entre outros. Estas IDEs
são ótimas opções, pois apresentam recursos que permitem a marcação de sinta-
xe, numeração de linhas, depuração1, compilação e a execução do programa escrito.
Também é possível escrever códigos em linguagem C por meio de um simples editor
de texto, como no Bloco de Notas do Windows. No entanto, sem a mesma gama de
recursos disponíveis nas ferramentas citadas.
Para escrever um código é importante que o programador adquira um bom conhe-
cimento, no que diz respeito à sintaxe e à semântica que compõem a estrutura da
linguagem C. Isso ajudará em inúmeras situações durante o desenvolvimento de seus
programas. Além disso, uma boa prática bastante utilizada em meio à comunidade
de programadores é o uso de comentários nas linhas de comando que permitem si-
nalizar ou até mesmo explicar de maneira detalhada o que um determinado trecho de
código faz. Isso auxilia a equipe de desenvolvimento e também outros programadores
que futuramente darão manutenção ao programa, a se localizarem melhor em meio à
infinidade de linhas de códigos que estarão presentes no programa. Exemplo:
Outro aspecto importante que deve ser levado em consideração durante a escrita
de um código é a prática da indentação que permite organizar o código de modo que
a leitura dele se torne mais fluida.

#include <stdio.h>

int main(){
// este printf deverá imprimir a frase Olá Mundo!!!
printf(“Ola Mundo!!!”);

return (0);

1 Esclarecimento: Conhecido também como debuging, a depuração é o processo de encontrar


e/ou reduzir os erros genéricos no código.

FACULDADE CATÓLICA PAULISTA | 10


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Exemplo: Imprimindo uma Linha


Conforme vimos anteriormente em nosso primeiro programa, podemos utilizar co-
mandos específicos para imprimir mensagens no console do DOS. No exemplo apre-
sentado, utilizamos a função printf que permite inserir o texto que desejamos apresen-
tar. A declaração da função printf deve ser feita utilizando parênteses e o texto a ser
apresentado na tela deve ser escrito entre aspas (duplas). Exemplo:

printf(“Ola Mundo!!!”);

Com o programa em execução, a mensagem a ser exibida ficará conforme o exem-


plo anteriormente apresentado em nosso primeiro programa em C, com a frase: Ola
Mundo. Vale lembrar que, inicialmente, a linguagem C é configurada a partir do idio-
ma inglês, sendo assim, a leitura de textos com acentuação do idioma em português
requer configuração por meio da função SET LOCALE que veremos mais adiante nas
próximas unidades.

A Biblioteca Padrão de C
Nos exemplos que já foram apresentados, pudemos perceber o uso de funções e
comandos que são responsáveis por realizar ações específicas dentro do programa.
Isso porque, a linguagem C é caracterizada pela chamada de funções que está presen-
te em sua biblioteca padrão. Esta biblioteca está presente em todos os compiladores
da linguagem C e é formada por um conjunto mínimo de arquivos de cabeçalho que
compõem o padrão C ANSI.
Para Schildt (1997, p. 3), “todo compilador C vem com uma biblioteca C padrão de
funções que realizam as tarefas necessárias mais comuns, O padrão C ANSI especifi-
ca o conjunto mínimo de funções que estará contido na biblioteca”.
Na tabela a seguir podemos conferir a descrição referente a cada arquivo de cabe-
çalho:

FACULDADE CATÓLICA PAULISTA | 11


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Biblioteca Descrição
assert.h Auxilia na identificação de erros em versões de depuração de programas.
complex.h Permite o tratamento no que se refere à manipulação de números complexos.
Realiza o tratamento de caracteres, como, por exemplo, a conversão de
ctype.h
maiúsculas, minúsculas.
errno.h Teste de códigos de erro reportados pelas funções de bibliotecas.
Definição de funções para tratamento de exceções em variáveis do tipo
fenv.h
ponto flutuante.
float.h Definição de limites e precisão para variáveis do tipo ponto flutuante.
inttypes.h Utilizada para o tratamento de conversão entre variáveis do tipo inteiro.
Permite a programação a partir da codificação de caracteres de acordo com
iso646.h
a ISO646.
limits.h Define a limitação de recursos
Permite a formação de acordo com a localização, como moeda, data,
locale.h
acentuação, etc.
math.h Utilizada na manipulação de funções matemáticas.
Permite definir macros (setjmp e longjmp) para saídas não locais e realização
setjmp.h
do tratamento de exceções.
signal.h Permite receber e realizar o tratamento de sinais específicos.
Utilizada no acesso aos argumentos passados para funções com parâmetro
stdarg.h
variável.
stdbool.h Tratamento de dados do tipo booleano.
stdint.h Padrões de definição de tipos de dados inteiros.
stddef.h Padrões de definições de tipos.
stdio.h Utilizada para funções de entrada/saída.
Possibilita o uso de funções nas mais diversas operações, como conversão,
stdlib.h
alocação de memória, controle de processo, funções de busca e ordenação.
string.h Utilizada para funções no tratamento de strings.
tgmath.h Permite implementar facilidades na utilização de funções matemáticas.
time.h Permite o tratamento de tipos de data e hora.
wchar.h Possibilita o tratamento de caracteres para suportar idiomas diversos.
wctype.h Contém funções para classificação de caracteres wide.
Biblioteca C padrão
Fonte: elaborado pelo autor

Basicamente, por se tratar de uma linguagem baseada no uso de funções, em al-


gum momento será inevitável informar a biblioteca correspondente às funções que
estão sendo chamadas no programa. Caso contrário, o programa certamente não

FACULDADE CATÓLICA PAULISTA | 12


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

será executado.

1.4 Variáveis e Tipos de Variáveis

Para efetuarmos a manipulação de dados em nossos programas é necessário


efetuar o armazenamento de determinadas informações e, para isso, utilizamos
as variáveis. Segundo Lopes e Garcia (2002, p. 25), “uma variável é um espaço na
memória principal do computador que pode conter diferentes valores e cada ins-
tante de tempo”.
As variáveis são o aspecto fundamental de qualquer linguagem de computador.
Uma variável em C é um espaço de memória reservado para armazenar certo tipo
de dado e tendo um nome para referenciar o seu conteúdo. [...] uma variável é um
espaço de memória que pode contar, a cada tempo, valores diferentes (MIZRAHI,
2008, p. 13).
Em linguagem C as variáveis mais utilizadas são do tipo: INT, FLOAT e CHAR,
sendo atribuídos a variáveis numéricas e string (caracteres), em linguagem C, não
existe o tipo de variável boolean, pois a linguagem considera qualquer valor verda-
deiro, intrinsecamente podemos dizer que todas as variáveis são diferentes de 0.
Outra particularidade é que variáveis do tipo CHAR armazenam um caractere ou
um conjunto de caracteres, sendo assim a mesma variável pode armazenar uma
letra apenas, uma palavra ou frase dependendo de como esta irá ser utilizada no
programa.
Conforme apresentado, as variáveis são armazenadas na memória do computa-
dor, consequentemente ocupam um determinado valor de bytes; podemos utilizar
alguns modificadores para determinar o tamanho de armazenamento, estes são:
unsigned, signed, short e long.
O modificador unsigned utilizamos para declarar como sem sinal, assim dupli-
cando a gama de valores, signed aceita valores positivos e negativos; podemos
utilizar o short para reduzir a capacidade de armazenamento e o long aumenta a
capacidade. Vejamos a tabela “Tipos de dados e faixa de valores” a seguir, a qual
apresenta a faixa de valores e o tamanho aproximado em bytes.

FACULDADE CATÓLICA PAULISTA | 13


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Tipo Faixa de valores Tamanho em Bytes

char -127 a 127 1

unsigned char 0 a 255 1

signed char -127 a 127 1

int -2.147.483.648 a 2.147.483.647 4

unsigned int 0 a 4.294.967.295 4

signed int -2.147.483.648 a 2.147.483.647 4

short int -32.768 a 32.767 2

unsigned short int 0 a 65.535 2

signed short int -32.768 a 32.767 2

long int -2.147.483.648 a 2.147.483.647 4

signed long int -2.147.483.648 a 2.147.483.647 4

unsigned long int 0 a 4.294.967.295 4

float seis dígitos de precisão 4

double dez dígitos de precisão 8

long double dez dígitos de precisão 10


Tipos de dados e faixa de valores
Fonte: Albano e Albano (2010, adaptado).

A criação ou declaração de uma variável é efetuada no início do programa, no


caso da linguagem C, logo após da declaração main(), uma variável começa com
a identificação do seu tipo, após isso, o nome da variável.

Sintaxe da declaração de uma variável:
tipo_variavel nome_variavel;

Exemplo de declaração de variável:


int numeros;
float valores;
char caracteres;

FACULDADE CATÓLICA PAULISTA | 14


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Vejamos na figura “Estrutura de declaração de variáveis”, a declaração de vari-


ável em linguagem C:

#include <stdio.h>

main(){

int numero1; // variável numérica


int numero2; // variável numérica
char nome1; // variável srting
char nome2; // variável string

/* bloco de código fonte em linguagem C */

Por vezes, teremos que declarar muitas variáveis do mesmo tipo para utilizar
no programa, podemos efetuar a declaração na mesma expressão, declarando o
tipo e, logo em seguida, os nomes das variáveis separadas por vírgula, conforme
apresentado na figura “Declaração de variáveis do mesmo tipo”, a seguir, em lin-
guagem C.

#include <stdio.h>

int main(){

int numero1, numero2, numero3; // variável numérica


char nome1, nome2; // variável string

/* bloco de código fonte em linguagem C */

}
Declaração de variáveis do mesmo tipo

Um detalhe importante que devemos atentar é para com os nomes das vari-
áveis, os nomes de referência não podem conter caracteres especiais (acentos,
%, &, #, dentre outros), espaços e também não podem começar com números,
vejamos, a seguir, na tabela “Declaração de variáveis de modo incorreto”, algumas
declarações incorretas em linguagem C.

FACULDADE CATÓLICA PAULISTA | 15


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Declaração da variável Descrição

float 85telefone; O nome de referência das variáveis se inicia


int 2nota, 3nota; com número.
char 1end;
char 1lugar, 2lugar;

float número; O nome de referência das variáveis contém


int telefone, código; caracteres especiais.
char endereço;
char município, cidade;

int numero de telefone; O nome de referência contém caracteres es-


float produto, código do produto; peciais e espaços.
char nome e sobrenome;
char primeiro nome, número da residência;
Declaração de variáveis de modo incorreto
Fonte: elaborado pelo autor

Devemos também nos atentar no modo de declarar as variáveis, o indicado é se


utilizar o nome das variáveis sempre em maiúscula ou minúscula, pois em lingua-
gem C se utiliza do conceito de Case Sensitive2; se declararmos o nome de referên-
cia sendo idade, esta será diferente de Idade, IDADE ou iDade.
Por vezes, temos a percepção de que nosso código pode conter erros, mas na
verdade, estamos apenas confundindo os nomes das variáveis, pois isso, temos
que ter atenção sobre os nomes das variáveis declaradas.
Por fim, temos as variáveis reservadas, chamadas como “Palavras reservadas”
são palavras que não se pode utilizar sendo uma variável criada pelo desenvolve-
dor, toda e qualquer linguagem de programa possui palavras que são de uso exclu-
sivo da linguagem e tem características exclusivas ao serem interpretadas por um
compilador, vejamos na tabela “Palavras Reservadas”, a seguir, algumas palavras
reservadas da linguagem C.

2 Esclarecimento: O conceito de case sensitive se baseia na forma de escrita, linguagens que


usam este conceito fazem diferença nas variáveis, por ex.: Soma e soma, para estas linguagens as
variáveis são tratadas sendo distintas.

FACULDADE CATÓLICA PAULISTA | 16


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

PALAVRAS RESERVADAS: dessa linguagem são nomes utilizados pelo compilador para re-
presentar comandos de controle do programa, operadores e diretivas.

abstract continue for new switch

assert default if package this

boolean do goto private synchronized

break double implements protected throw

byte else import public throws

case enum instanceof return transient

catch extens int short try

char final interface static void

class finally long strictfp volatile

const float native super while


Palavras reservadas
Fonte: Ascencio e Campos (2010, p. 30).

Conforme já apresentado, as variáveis são os elementos-chave para o funcio-


namento de um software, independente qual seja a linguagem em que ele foi de-
senvolvido. As escolhas pelos nomes e tipos de variáveis podem interferir no bom
desempenho de um software, por isso que é essencial saber sobre os tipos de
variáveis e como estas operam.

FACULDADE CATÓLICA PAULISTA | 17


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 2
ENTRADA E SAÍDA DE DADOS,
EXPRESSÕES E OPERADORES

Fonte: https://br.freepik.com/fotos-gratis/linguagem-de-programacao-no-local-de-trabalho_902701.htm

Escrever um programa em linguagem C requer a definição de alguns elementos


essenciais. Conforme mencionado anteriormente, os arquivos de cabeçalho são
responsáveis por definir o ponto inicial de um programa escrito em linguagem C.
Sendo assim, essa é uma informação que precisa estar presente nas primeiras
linhas do programa antes mesmo da função main

2.1 Funções I/O

As operações de entrada e saída são realizadas por funções específicas que


são responsáveis por garantir a leitura e a impressão dos dados de acordo com
seu tipo. Essas funções são o scanf e printf, que inclusive vimos exemplificado em

FACULDADE CATÓLICA PAULISTA | 18


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

nosso primeiro programa em C (“Ola Mundo”). A função scanf permite realizar a


leitura de dados a partir de uma fonte externa, como, por exemplo, o que é digitado
no teclado pelo usuário. Já a função printf é responsável por exibir os valores na
tela.
A função printf pode ser utilizada em sua sintaxe básica ou por meio da utiliza-
ção de argumentos que permitem apresentar textos e valores de variáveis.

Exemplo:
Sintaxe básica:
printf(“Mensagem que será apresentada na tela para o usuário:”);

Utilizando argumentos:
printf(“Sua renda mensal é: R$ %f”, renda);

Neste segundo exemplo, o %f define o local onde será escrita a variável do tipo
float. E o “total” representa a variável apresentada na posição %f.
Já a função scanf possui uma sintaxe um pouco diferente, pois obrigatoriamen-
te requer o uso de argumentos que definem o tipo de dado da variável que será
lida. A sintaxe básica é dada da seguinte forma:

scanf(“expressão de controle”, lista de argumentos);


Exemplo prático: scanf(“%f”, &renda);

Neste exemplo, nossa lista de argumento é responsável por informar o ende-


reço da variável (renda), para a qual utilizamos o símbolo & como prefixo. Assim
como no exemplo do printf, o %f representa o tipo de variável que deverá ser lida
pela função scanf. Mais adiante, veremos sobre os tipos e variáveis que compõem
a linguagem C. No entanto, para este tópico é importante destacar os tipos bási-
cos de dados, bem como sua respectiva representação. Confira a Tabela “Tipos
básicos de variáveis”, a seguir.

FACULDADE CATÓLICA PAULISTA | 19


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Tipo de dado Representação Formato

caractere char %c

inteiro int %d ou %i

real float %f

cadeia de caracteres char[] %s


Tabela 2: Tipos básicos de variáveis
Fonte: elaborado pelo autor.

Certamente, estes tipos de dados são apenas uma breve representação, for-
mando uma composição básica ou tipos primitivos. Mas, boa parte do que iremos
aprender em linguagem C será contemplado por estes tipos de dados.

2.2 Operadores Relacionais e Lógicos

Seja qual for a linguagem de programação, ao escrever um código, muitas vezes


se faz necessário o uso de operadores lógicos e/ou relacionais que permitem reali-
zar comparações de verdadeiro ou falso. Embora ofereçam recursos semelhantes,
vale ressaltar que se tratam de operadores com funções distintas.
De acordo com Schildt (1997, p. 74), “no termo operador relacional, relacional
refere-se às relações que os valores podem ter uns com os outros. No termo ope-
rador lógico, lógico refere-se às maneiras como essas relações podem ser conec-
tadas”. Enquanto os operadores relacionais são utilizados para estabelecer as re-
lações que podem ocorrer entre os valores comparados, os operadores lógicos
estão diretamente relacionados à maneira como estas relações podem acontecer.

Operadores Relacionais
Operadores relacionais também são conhecidos como operadores de compara-
ção, pois, possibilitam estabelecer uma relação de comparação entre dois valores
ou duas variáveis. Também é possível que esta relação de comparação seja feita
entre um determinado valor e uma variável. Um exemplo simples disso é quando,
pretende-se saber se o valor da variável Saldo é maior do que o valor 0. Neste
caso, estamos apenas fazendo uma comparação entre uma variável e um valor.
Ao escrever o código, essa comparação deve ser apresentada da seguinte forma:

Saldo > 0

FACULDADE CATÓLICA PAULISTA | 20


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Além do operador de comparação maior (>), visto no exemplo apresentado, exis-


tem outros operadores relacionais ou de comparação que são muito utilizados no
desenvolvimento de programas em linguagem C. Vejamos a tabela “Operadores
relacionais”, a seguir.

Operador Função Exemplo

<> Diferente 1 <> 2, X <> Y

== Igual a 1 == 1, X == Y

> Maior que 2 > 1, X > Y

< Menor que 1 < 2, X < Y

>= Maior ou igual a 2 >= 1, X >= Y

<= Menor ou igual a 1 <= 2, X <= Y


Operadores relacionais
Fonte: elaborado pelo autor

Ao realizar comparações de valores e/ou variáveis, o resultado obtido precisa


ser um valor lógico, ou seja, verdadeiro ou falso. Considerando o exemplo do Saldo
(apresentado acima), se o valor da variável Saldo for maior do que 0 (verdadeiro),
significa que a conta bancária possui dinheiro disponível. Caso contrário (falso), a
conta não possui dinheiro disponível.

Operadores Lógicos
Já os operadores lógicos realizam um outro tipo de verificação, mas que tam-
bém está baseada na ideia de verdadeiro ou falso. Em diversas linguagens de pro-
gramação são utilizados três operadores que foram definidos a partir da Álgebra
Booleana. Vejamos a tabela “Operadores lógicos” a seguir:

Operador Função Descrição

|| disjunção OU lógico (OR)

&& conjunção E lógico (AND)

! negação Negação (NOT)


Operadores lógicos
Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 21


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

É importante ressaltar que na programação operadores possuem precedência


sobre outros, assim como ocorre na matemática. Dessa forma, algumas opera-
ções possuem prioridade em relação às demais. Considerando os tipos de ope-
radores que foram vistos neste capítulo referentes à linguagem C, a ordem de
prioridade entre eles é representada, a seguir, na tabela “Precedência operadores”.

!, != NOT (Negação)
Maior prioridade
&& AND (E lógico)

|| OR (OU lógico)
Menor prioridade
=, <>, >, <, >=, <= Operadores relacionais

?: Operador ternário
Tabela 6: Precedência operadores
Fonte: elaborado pelo autor

É importante estar atento à ordem de prioridade de cada operador, pois isso


impacta diretamente no resultado final no código que está sendo escrito.

Operador Ternário (?)


O operador ternário permite verificar uma determinada condição e em seguida
retornar um entre dois valores previamente definidos. Este tipo de operador apre-
senta-se como uma alternativa para a estrutura de decisão IF, que veremos mais
adiante neste capítulo. No entanto, vale ressaltar que não se trata de uma estrutu-
ra de decisão propriamente dita, mas sim de um atalho que pode ser utilizado em
situações mais simples. Enquanto a estrutura IF utiliza ao menos quatro linhas de
código na escolha entre duas opções, o operador ternário possui uma estrutura
linear (inline), na qual a mesma situação pode ser executada em apenas uma linha
de código. A sintaxe do operador ternário é apresentada abaixo:

condição? primeira_expressão : segunda_expressão;

Enquanto o sinal de interrogação (?) é utilizado para testar a condição desejada,


o sinal de dois pontos ( : ) é responsável por separar os valores que serão retorna-
dos, caso a condição informada seja verdadeira ou falsa. A “primeira_expressão”
retorna o valor caso a condição testada seja verdadeira. Caso contrário, o valor

FACULDADE CATÓLICA PAULISTA | 22


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

retornado será o da “segunda_expressão”, (condição testada for falsa). Vejamos a


figura “Exemplo operador ternário”.

#include <stdio.h>

int main(){

int a, b, maior;

printf(“Informe o primeiro numero: “);
scanf(“%d”, &a);
printf(“Informe o segundo numero: “);
scanf(“%d”, &b);

// verificar os valores de a e b com operador ternário


maior = a > b ? a : b;
printf(“O valor maior e: %d”, maior);
return(0);
}
Exemplo operador ternário
Fonte: elaborado pelo autor

Neste trecho será feito o teste relacional para verificar qual dos dois valores in-
formados é o maior. Caso o valor de “a” seja maior, então a variável “maior” recebe
o seu valor. Caso contrário será o valor de “b”.

2.3 Operações Aritméticas

Operadores aritméticos são utilizados para efetuar cálculos em um software,


por meio destes, obtemos resultados numéricos que podem ser utilizados dentro
do software, sendo utilizados com variáveis do tipo inteiro (INT) ou real (FLOAT),
não sendo aplicados em expressões com caracteres.
As expressões estão diretamente relacionadas ao conceito de fórmula mate-
mática, em que um conjunto de variáveis e constantes relaciona-se por meio de
operadores (LOPES; GARCIA, 2002).
Vejamos na tabela “Operadores aritméticos” a seguir, os operadores aritméticos
utilizados na linguagem C, suas representações e forma de uso:

FACULDADE CATÓLICA PAULISTA | 23


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

OPERAÇÃO OPERADOR DESCRIÇÃO

Operador utilizado para efetuar a soma de variáveis. Exemplo:


Soma + duas variáveis do tipo inteiro A e B, para efetuar a soma dos
valores atribuídos destas variáveis vamos utilizar a seguinte ex-
pressão: A + B.

Simboliza a subtração de variáveis. Exemplo: duas variáveis do


Subtração - tipo inteiro C e D, para efetuar a subtração dos valores atribuídos
destas variáveis vamos utilizar a seguinte expressão: C – D.

Utilizado para efetuar a multiplicação de variáveis. Exemplo:


Multiplicação * duas variáveis do tipo inteiro C e D, vamos utilizar a seguinte
expressão: C * D.

Divisão / É operador utilizado para a divisão entre variáveis. Exemplo A / B.

Usamos esta expressão quando queremos encontrar o resto da


Resto % divisão entre duas variáveis. Dadas as seguintes variáveis A=3 e
B=2, usamos A%B, o resultado desta expressão será o número 1.
Operadores aritméticos
Fonte: elaborado pelo autor

Os mais variados softwares desenvolvidos se utilizam de algumas expressões arit-


méticas apresentadas, pode-se utilizar os operadores de modo simples, sendo A + B
ou podemos efetuar expressão mais complexas como A + B / C - D, note que utilizados
diversos operadores na mesma expressão, para exemplificar melhor, observe o código
fonte abaixo, ilustrado na figura “Código fonte, operadores aritméticos”.

#include <stdio.h>
#include <stdlib.h>

main(){

int A = 55;
int B = 68;
int C = 38;
int D = 2;
int resultado1, resultados2;

resultado1 = A + B;
printf(“%d”, resultado1);
printf(“%n”); // utilizamos o \n quando queremos forçar uma quebra de linha
resultado2 = A + B / C – D;
printf(“%d”, resultado2);

}
Código fonte, operadores aritméticos

FACULDADE CATÓLICA PAULISTA | 24


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Observe que ao declararmos as variáveis já estamos atribuindo os valores delas,


geralmente utilizamos esta estratégia quando estamos trabalhando com valores
fixos no código, mas em algumas situações apenas declaramos as variáveis e atri-
butos, os valores por meio da leitura do que o usuário digita, por meio do scanf(),
conforme estudado anteriormente. Vejamos, na figura “Programa em execução,
operadores aritméticos”, o resultado deste código fonte depois de compilado e
executado.

Programa em execução, operadores aritméticos


Elaborado pelo autor.


Devemos atentar para dois pontos muito importantes neste código que acaba-
mos de desenvolver:
1º Ponto: quando trabalhamos com variáveis do tipo int os resultados sempre
serão valores inteiros como 1, 63, 157, entre outros. Quando precisamos trabalhar
com valores que se utilizam de separações, como a altura 1.75, aplicamos o tipo
de variável float.
2º Ponto: note a que o resultado 2 obteve o valor de 54 na expressão A + B / C
- D, o valor correto seria 1, mas o porquê deste valor 54, então? A resposta é bem
simples, o computador não efetua o cálculo de modo linear: resultado de A + B
depois / C e posteriormente - D. O que acontece é que o computador elenca priori-
dades, operadores aritméticos como multiplicação (*) e divisão (/) recebem peso
maior na expressão do que os operadores de soma (+) e subtração (-).
Para resolver o problema apontado no segundo ponto basta priorizar o cálculo
manualmente, atribuindo o que deseja executar primeiro dentro dos parentes, igual
a cálculos matemáticos convencionais, vejamos, na figura “Código fonte, operado-
res aritméticos com prioridades”, o código fonte com esta atribuição.

FACULDADE CATÓLICA PAULISTA | 25


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#include <stdio.h>
#include <stdlib.h>

main(){

int A = 55;
int B = 68;
int C = 38;
int D = 2;
int resultado1, resultados2;

resultado1 = A + B;
printf(“%d”, resultado1);
printf(“%n”); // utilizamos o \n quando queremos forçar uma quebra de linha
resultado2 = (A + B) / C – D;
printf(“%d”, resultado2);

}
Código fonte, operadores aritméticos com prioridades
Elaborado pelo autor.

Agora, vejamos na figura “Programa em execução, operadores aritméticos com


prioridades”, o resultado do código compilado e executado.

Programa em execução, operadores aritméticos com prioridades


Fonte: elaborado pelo autor.


Com a atribuição da prioridade o resultado da operação aritmética está de acor-
do com o esperado, dependendo do cálculo que desejamos, podemos ter vários
pontos de prioridades em uma operação, como exemplo (A+B) / (C-D), a leitura
desta operação será: o resultado de A+B será dividido por C, o resultado é poste-
riormente subtraído por D, desta forma conseguimos obter o resultado esperado
sem problemas. Observe que o valor apresentado é 1 e não 1,23 este resultado não
é apresentado, pois a declaração da variável é como inteiro.

FACULDADE CATÓLICA PAULISTA | 26


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

2.4 Operadores de Atribuição e Acumuladores

Conforme apresentado no tópico anterior, os operadores aritméticos são de


grande importância e são utilizados constantemente nos códigos fontes de diver-
sos softwares.

Outros operadores muito úteis são os de atribuição e acumulação, os quais


recebem valores e os trata de modo simplificado, por exemplo: X = X + Y, podemos
atribuir para X += Y, o elemento de atribuição += pega o valor acumulado na variá-
vel X e soma o valor que está contido em Y, esses tipos de operadores são muito
utilizados, vejamos na tabela “Operadores de atribuição e acumulação”, a seguir,
outros operadores e suas funções:

Operador Exemplo Descrição

+= A += B Equivale a A = A + B

-= A -= B Equivale a A = A - B

*= A *= B Equivale a A = A * B

/= A /= B Equivale a A = A / B

%= A %= B Equivale a A = A % B

++ C++ Equivale a C = C + 1

C = ++D Equivale a D = D + 1 depois C = D

C = D++ Equivale a C = D depois D = D + 1

-- F-- Equivale a F = F - 1

F = --G Equivale a G = G - 1 depois F = G

F = G-- Equivale a F = G depois G = G - 1


Operadores de atribuição e acumulação
Fonte: adaptado de Ascencio e Campos (2010).

Os operadores de acumulação e atribuição são utilizados para representar de


maneira sintética uma operação aritmética, para aprimorar nossos estudos, ve-
jamos os mesmos sendo utilizados no código a seguir, conforme ilustra a Figura
Código fonte, operadores atribuição e acumulação.

FACULDADE CATÓLICA PAULISTA | 27


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#include <stdio.h>
#include <stdlib.h>

main(){

int A = 55;
int B = 68;
int C = 38;
int D = 2;
int h, i, j, k;

B+=D;
D-=A;
C++;
A--;

printf(“%d \n”, B);


printf(“%d \n”, D);
printf(“%d \n”, C);
printf(“%d \n”, A);

}
Código fonte, operadores atribuição e acumulação

Vejamos, agora na Figura “Programa em execução, atribuição e acumulação”, o


resultado do código compilado e executado.

Programa em execução, atribuição e acumulação


Fonte: elaborado pelo autor

O que devemos observar é que o computador lê as informações por ordem de


entrada, no caso da operação A-- antes da operação D-=A, o valor de A na segunda
operação não será 55, mas sim 54, pois efetuamos o decremento do valor de 55
antes, temos que tomar cuidado onde inserir os operadores de atribuição ou acu-
mulação em nossos códigos, pois um simples erro de posicionamento pode gerar
problemas futuros.

FACULDADE CATÓLICA PAULISTA | 28


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

2.5 Exemplos Dirigidos

Imaginamos que uma determinada empresa foi contratada para desenvolver


um software para uma instituição de ensino, um dos requisitos deste sistema é a
geração do boletim de notas dos alunos matriculados, em conversa com o diretor
desta instituição foi informado que a nota final dos alunos que deve constar no
boletim é a média3 de notas dos quatro bimestres do ano.
Pensando em atender este requisito, elaborou o seguinte código fonte em lin-
guagem C, ilustrado na Figura “Código fonte, média de notas”, a seguir.

#include <stdio.h>
#include <stdlib.h>

#define bim 4

main(){

float nota1, nota2, nota3 nota4, media;

printf(“Informe a nota do 1 Bimestre: ”);


scanf(“%f”, &nota1);

printf(“Informe a nota do 2 Bimestre: ”);


scanf(“%f”, &nota2);

printf(“Informe a nota do 3 Bimestre: ”);


scanf(“%f”, &nota3);

printf(“Informe a nota do 4 Bimestre: ”);


scanf(“%f”, &nota4);

media = (nota1 + nota2 + nota3 + nota4) / bim;


printf(“Media final do aluno: %.1f”, media);

}
Código fonte, média de notas
Fonte: elaborado pelo autor

3 Afirmação: O cálculo da média se dá pela soma dos grupos e depois dividindo pela quantida-
de de grupos. Ex.: (1+2+3+4)/4.

FACULDADE CATÓLICA PAULISTA | 29


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

No código-fonte apresentado, temos as seguintes composições:


A definição da quantidade de bimestres utilizando uma constante #define
bim 4;
Foram criadas cinco variáveis do tipo real float nota1, nota2 nota3, nota4,
media;
É utilizado o comando printf para informar ao usuário o que digitar;
O comando scanf, conforme vimos, é utilizado para efetuar a entrada de
dados;
É atribuído para a variável média o cálculo da média das notas de um alu-
no;
Por fim, o resultado da média de notas do aluno é apresentado na tela,
utilizamos a expressão %. 1f para que seja mostrado apenas um número após o
ponto.

Vejamos na figura “Programa em execução, média de notas”, a seguir, o código-


-fonte após ele ter sido compilado e executado.

Programa em execução, média de notas


Fonte: elaborado pelo autor


Podemos observar as entradas de dados para as variáveis, as quais compõem
o cálculo da média (6.8+7.5+5.5+6.3), como já foi definido a quantidade de bimes-
tres no início do código, basta então pegar o resultado da soma das entradas de
dados (21.1) e dividir por 4, assim obtendo a média do aluno e a quantidade de
valores que deve aparecer após o ponto.

Recebendo e Imprimindo Caracteres


Todo e qualquer programa desenvolvido com dois princípios básicos, o de re-
ceber dados dos usuários e o de imprimir os caracteres, sejam eles números ou
letras, na tela para o usuário. Para este procedimento, vamos nos utilizar dos co-
mandos scanf(), para a entrada de dados e printf() para a imprimir os dados.

FACULDADE CATÓLICA PAULISTA | 30


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Neste exemplo, vamos imaginar que você está testando os seus conhecimen-
tos em linguagem C, e que, gostaria de efetuar um programa que perguntasse para
um usuário qual o seu primeiro nome, sobrenome, idade e altura, e após todas as
informações preenchidas, imprimisse na tela os dados digitados.
Vejamos na figura “Código fonte, recebendo e imprimindo dados”, a seguir, como
seria o seu código fonte em linguagem C.

#include <stdio.h>
#include <stdlib.h>

main(){

char nome[50], sobrenome[50];


int idade;
float altura;

printf(“Informe qual o seu primeiro nome: “);


scanf(“%s”, &nome);

printf(“Informe qual o seu sobrenome: “);


scanf(“%s”, &sobrenome);

printf(“Informe a sua idade: “);


scanf(“%d”, &idade);

printf(“Informe sua altura: “);


scanf(“%f”, &altura);

system(“cls”); // limpa a tela para a impressão dos dados - Windows


// system(“clear”); // limpa a tela para a impressão dos dados - linux

printf(“Nome e sobrenome do usuario: %s %s \n”, nome, sobrenome);


printf(“Idade do usuario: %d \n”, idade);
printf(“Altura do usuario: %.2f \n”, altura);

}
Código fonte, recebendo e imprimindo dados
Fonte: elaborado pelo autor


Perceba, aluno(a), que neste código-fonte mesclamos vários tipos que irão rece-
ber os dados digitados pelos usuários, isso é muito comum nos sistemas desen-
volvidos, nos quais contamos com diversas declarações de variáveis diferentes.

FACULDADE CATÓLICA PAULISTA | 31


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Vejamos na Figura “Programa em execução, recebendo dados”, a seguir, o progra-


ma em execução para a entrada de dados:

Programa em execução, recebendo dados


Fonte: elaborado pelo autor

Após o usuário ter digitado todos os seus dados, a tela é limpa, por meio do sys-
tem(“cls”), sendo retornado apenas os dados impressos na tela, conforme a figura
“Programa em execução, imprimindo dados”, a seguir.

Programa em execução, imprimindo dados


Fonte: elaborado pelo autor

Perceba que os dados de entrada digitados pelo usuário são apagados da tela,
mas ainda estão armazenados na memória do computador, por isso que consegui-
mos imprimir os caracteres de entrada na tela sem problemas, podemos utilizar
a função system() para deixar a tela mais limpa, sem uma poluição visual para o
usuário assim ele pode compreender mais fácil as informações que estão sendo
impressas na tela.

Cálculo de IMC
Imaginamos que você é um programador recém-contratado em uma empresa
de desenvolvimento de software, e o seu primeiro programa a ser desenvolvido em
linguagem C é o sistema de acompanhamento de cálculo de IMC de uma acade-
mia, vejamos a seguir os requisitos apresentados pelos stakeholders4.

4 Esclarecimento: Stakeholders são partes interessadas, no contexto, podemos afirmar serem


os donos do projeto. É um termo utilizado em diversas áreas como gestão de projetos, comunicação
social, desenvolvimento de software, engenheiro de requisito, dentre outras áreas.

FACULDADE CATÓLICA PAULISTA | 32


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Requisitos do sistema
O sistema deve armazenar e mostrar na tela o nome e a idade do aluno.
Efetuar o cálculo de IMC do 1º e 2º mês, com base nos dados forneci-
dos pelo professor na academia.
No final, deve-se mostrar na tela, de modo limpo, apenas os dados do
aluno, seguido dos dados dos cálculos de IMC e a diferença entre os dois pri-
meiros meses.
Também é muito importante apresentar a quantidade de meses que o
aluno terá um acompanhamento junto ao professor da academia.
Após analisar dos requisitos levantados foi se desenvolvido o seguinte
código fonte, apresentado no Quadro Código fonte, sistema de cálculo de IMC,
a seguir.

#include<stdio.h>
#include<stdlib.h>
#include<locale.h>

#define plano 4

int main() {
setlocale(LC_ALL, “Portuguese”);
float peso1, altura1, IMC1;
float peso2, altura2, IMC2;
float diferenca;
char nome[50];
int idade;

printf(“Digite o nome do aluno: “);


scanf(“%s”, &nome);

printf(“Digite a idade do aluno: “);


scanf(“%d”, &idade);

system(“cls”); // limpa a tela para a impressão dos dados Windows


//system(“clear”); // limpa a tela para a impressão dos dados linux

printf(“Digite os dados para o cálculo de IMC do 1º Mês\n\n”);


printf(“Digite o peso: “);
scanf(“%f”, &peso1);

FACULDADE CATÓLICA PAULISTA | 33


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

printf(“Digite a altura: “);


scanf(“%f”, &altura1);

IMC1 = peso1 / (altura1*altura1);

system(“cls”); // limpa a tela para a impressão dos dados Windows


//system(“clear”); // limpa a tela para a impressão dos dados linux

printf(“Digite os dados para o cálculo de IMC do 2º Mês\n\n”);


printf(“Digite o peso: “);
scanf(“%f”, &peso2);

printf(“Digite a altura: “);


scanf(“%f”, &altura2);

IMC2 = peso2 / (altura2*altura2);

system(“cls”); // limpa a tela para a impressão dos dados Windows


//system(“clear”); // limpa a tela para a impressão dos dados linux

diferenca = IMC1 - IMC2;

printf(“Nome do aluno: %s \n”, nome);


printf(“Idade do aluno: %d \n”, idade);
printf(“-----------------------------\n”);
printf(“IMC do 1º Mês: %.2f \n”, IMC1);
printf(“IMC do 2º Mês: %.2f \n”, IMC2);
printf(“-----------------------------\n”);
printf(“Diferença entre o IMC do 1º e 2º Mês: %.2f \n”, diferenca);
printf(“Quantidade de acompanhamento com base no plano contratado: %d
\n”, plano);
}
Código fonte, sistema de cálculo de IMC
Fonte: elaborado pelo autor


Podemos observar que o código-fonte desenvolvido traz todos os elementos
que estudamos nesta unidade, conforme já apresentado em tópicos anteriores é
comum nos sistemas desenvolvidos termos várias funções e entradas de dados
em um sistema, onde contamos com diversas declarações de variáveis diferentes.
Vejamos um passo a passo até a execução final do programa.

FACULDADE CATÓLICA PAULISTA | 34


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

1º Passo - Dados de entrada do aluno, ilustrado na figura “Programa em execu-


ção, sistema de cálculo de IMC”.

Programa em execução, sistema de cálculo de IMC


Fonte: elaborado pelo autor

2º Passo - Dados para cálculo de IMC do 1º mês, ilustrado na Figura Programa


em execução, sistema de cálculo de IMC.

Figura: Programa em execução, sistema de cálculo de IMC


Fonte: elaborado pelo autor

3º Passo - Dados para cálculo de IMC do 1º mês, ilustrado na figura “Programa


em execução, sistema de cálculo de IMC”.

Programa em execução, sistema de cálculo de IMC


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 35


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

4º Passo - Resultado final, ilustrado na figura “Programa em execução, sistema


de cálculo de IMC”.

Programa em execução, sistema de cálculo de IMC


Fonte: elaborado pleo autor

Conforme os dados de entrada são digitados pelo usuário, este são apagados
da tela, mas continuam na memória do computador, após o preenchimento de
todos os dados e os cálculos efetuados, imprimimos na tela o que foi requisitado
pelos stakeholders do projeto.
Podemos dizer que ao término de seu primeiro programa desenvolvido em lin-
guagem C é possível compreender os diversos elementos que irão lhe ajudar a de-
senvolver os seus primeiros algoritmos e além de enriquecer o seu conhecimento
sobre a linguagem C.

FACULDADE CATÓLICA PAULISTA | 36


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 3
INSTRUÇÕES CONDICIONAIS
DE DECISÃO

Fonte: https://pixabay.com/pt/photos/decis%c3%a3o-dist%c3%a2ncia-lista-jun%c3%a7%c3%a3o-5291766/

Em determinados momentos devemos tomar decisões a partir de perguntas


ou situações geradas, tais como: qual a carreira profissional devo seguir? Devo
ou não viajar? Caso o tempo esteja virado para chuva, vou trabalhar de moto ou
carro?
Em um software isso também acontece, se determinadas situações ou variá-
veis apresentarem certos acontecimentos, o software poderá tratar determinados
blocos de códigos, chamamos isso de desvio condicional, em que, caso a situação
for favorável ou não se executar um trecho de código estabelecido, efetuamos
este processo por meio das expressões if e if-else.
Em nosso livro, estudamos a linguagem C, entretanto, toda e qualquer lingua-
gem de programação possui estas expressões de desvio condicional, para auxiliar

FACULDADE CATÓLICA PAULISTA | 37


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

seus usuários em suas tarefas ou tomada de decisões.

3.1 Instrução Condicional Simples

A estrutura condicional if é utilizada quando se trata de seleções simples, do


tipo SE - ENTÃO, a qual é testada antes de executar um trecho de código, de modo
bem simples podemos dizer que se a condição for atendida, um bloco de instru-
ções/códigos será executado, caso contrário não se executa nada.
Segundo Forbellone e Eberspacher (2005, p.33),

[...] uma estrutura de seleção simples permite a escolha de um grupo


de ações (bloco) a ser executado quando determinadas condições,
representadas por expressões lógicas ou relacionais, são ou não
satisfeitas.

Para melhor compreensão, vejamos a figura “Diagrama de execução da função


SE – ENTÃO”, a seguir:

Diagrama de execução da função SE - ENTÃO


Fonte: Forbellone e Eberspacher (2005, p. 34).

A expressão lógica ou condição a ser se refere a uma condição que deve ser
retornar como verdadeiro. Para lhe ajudar a entender, vamos imaginar que temos
duas variáveis de entrada A e B e os seus valores respectivos são 1 e 2, vejamos
possíveis condições:

A > B = caso a condição seja verdadeira o bloco será executado


A > B = caso a condição seja falsa o bloco não será executado.

No caso de nosso exemplo, a condição de A maior que B não será atendida

FACULDADE CATÓLICA PAULISTA | 38


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

(falsa), pois 1 não é maior que 2 tendo um retorno falso para expressão. Para
compor a expressão condicional, podemos utilizar qualquer um dos operadores
relacionais. Em linguagem C a forma de escrever a função if no código fonte é da
seguinte forma, observe a figura “Comando condicional simples”, a seguir.

Comando condicional simples


Fonte: elaborado pelo autor

Observe que a condição a ser validada está entre os parênteses ( ) e o bloco


de execução está entre chaves { }, conforme podemos notar no diagrama, caso
a condição for atendida, todo o conjunto de código que estiver entre chaves será
executado, caso não for atendida a condição, será ignorado. Vejamos um exemplo
prático se baseando do algoritmo de média de notas do aluno:
#include <stdio.h>
#include <stdlib.h>
#define bim 4

mai(){
float nota1, nota2, nota3, nota4, media;

printf(“Informe a nota do 1 Bimestre: “);


scanf(“%f”, &nota1);

printf(“Informe a nota do 2 Bimestre: “);


scanf(“%f”, &nota2);

printf(“Informe a nota do 3 Bimestre: “);


scanf(“%f”, &nota3);

printf(“Informe a nota do 4 Bimestre: “);


scanf(“%f”, &nota4);

media=(nota1+nota2+nota3+nota4)/bim;
printf(“Media final do Aluno: %.1f \n”, media);

if(media >= 7.0){ // expressão condicional a ser testada


printf(“Aluno Aprovado :)”);
}
}
Estrutura de declaração da função if

FACULDADE CATÓLICA PAULISTA | 39


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Ao executar este algoritmo, podemos obter duas situações mediante à ex-


pressão condicional a ser testada, caso a média de notas do aluno for maior
ou igual a 7, irá apresentar na tela a frase “Aluno Aprovado :)”, caso for menor,
o trecho é ignorado, vejamos o algoritmo em execução na figura “Retorno da
expressão condicional verdadeira” e na figura “Retorno da expressão condicio-
nal falsa”.

Retorno da expressão condicional verdadeira


Fonte: elaborado pelo autor

Retorno da expressão condicional falsa


Fonte: elaborado pelo autor

Perceba que no exemplo apresentado estamos validando apenas uma expressão


(media >= 7), mas podemos utilizar expressões e operadores lógicos em conjunto
para validar a expressão condicional da função if, para isso vamos utilizar o conceito
da tabela verdade. Imagine que no algoritmo de média de notas que acabamos para o
aluno ser aprovado ele tenha que atender os critérios:

1º Objeto A (media >= 7)


2º Objeto B (nota4 > 6)

Agora, para que o aluno seja aprovado, ele tem que atender às duas condições,
neste caso, ambas devem retornar como verdadeiro (operador lógico &&), acompanhe
o teste de mesa na tabela “Verdade condição &&”, a seguir:

FACULDADE CATÓLICA PAULISTA | 40


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

TABELA VERDADE

Objeto A Objeto B AeB Condição do aluno

Verdadeiro Verdadeiro Verdadeiro Aprovado

Verdadeiro Falso Falso Reprovado

Falso Verdadeiro Falso Reprovado

Falso Falso Falso Reprovado


Tabela verdade condição &&
Fonte: elaborado pelo autor

Mas se a nossa expressão condicional fosse apresentada em vez de &&, ambas as


expressões verdadeiras, fosse utilizado OU (operador lógico II), uma ou outra expres-
são verdadeira, vejamos, a seguir, na tabela “Verdade condição II”.

TABELA VERDADE

Objeto A Objeto B A ou B Condição do aluno

Verdadeiro Verdadeiro Verdadeiro Aprovado

Verdadeiro Falso Verdadeiro Aprovado

Falso Verdadeiro Verdadeiro Aprovado

Falso Falso Falso Reprovado


Tabela verdade condição II
Fonte: elaborado pelo autor

A estrutura do algoritmo irá ficar a mesma, apenas será inserida outra expres-
são condicional para a tomada de decisão, junto com um operador lógico, podemos
também ter no mesmo código várias funções IF, efetuando outros testes com outras
expressões condicionais, vejamos o exemplo, a seguir:

FACULDADE CATÓLICA PAULISTA | 41


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#include <stdio.h>
#include <stdlib.h>
#define bim 4

mai(){
float nota1, nota2, nota3, nota4, media;

printf(“Informe a nota do 1 Bimestre: “);


scanf(“%f”, &nota1);

printf(“Informe a nota do 2 Bimestre: “);


scanf(“%f”, &nota2);

printf(“Informe a nota do 3 Bimestre: “);


scanf(“%f”, &nota3);

printf(“Informe a nota do 4 Bimestre: “);


scanf(“%f”, &nota4);

media=(nota1+nota2+nota3+nota4)/bim;
printf(“Media final do Aluno: %.1f \n”, media);

if(media >= 7.0 && nota4 >=6){ // expressão condicional a ser testada
com operador lógico &&
printf(“Aluno Aprovado :) \n”);
}

if(nota2 > nota1 || nota4 > nota3){ // expressão condicional a ser testada
com operador lógico ||
printf(“Entre os bimestres o aluno aumentou a sua nota.”);
}
}
Função If com operadores lógicos
Fonte: elaborado pelo autor

Veja que no mesmo algoritmo temos duas funções IF, cada função tem expressões
condicionais e operadores lógicos, vejamos o algoritmo em execução na figura “Re-
torno do algoritmo atendendo apenas a segunda função IF” e na figura “Retorno do
algoritmo atendendo apenas a primeira função IF”.

FACULDADE CATÓLICA PAULISTA | 42


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Retorno do algoritmo atendendo apenas a segunda função IF


Fonte: elaborado pelo autor

Retorno do algoritmo atendendo apenas a primeira função IF


Fonte: elaborado pelo autor

3.2 Instrução Condicional Composta

Podemos notar que no tópico anterior a estrutura condicional IF atende em cená-


rios diferentes, entretanto nota-se que o resultado da estrutura ID trata apenas con-
dições verdadeiras e não casos de retornos falsos, não apresentando nenhum tipo
de mensagem caso as condições retornassem como “falso”, nestes casos podemos
utilizar o desvio condicional composto o SE – SENÃO. Vejamos um exemplo em pseu-
docódigo, ilustrado na figura “Representação textual, sobre desvio condicional com-
posto”, a seguir.

Representação textual, sobre desvio condicional composto


Fonte: elaborado pleo autor

Em linguagem C, este tipo de função é expressada sendo IF - ELSE, função está


muito utilizada, pois, desta forma, o usuário não fica sem resposta, ou em outros ca-
sos, se pode executar outro trecho de código, como se fosse um plano de contingên-
cia. O Plano de Contingência é o planejamento preventivo e alternativo para atuação
durante um evento que afete as atividades normais da organização.

FACULDADE CATÓLICA PAULISTA | 43


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Segundo Forbellone e Eberspacher (2005, p.35),

[...] quando tivermos situações em que duas alternativas dependem


de uma mesma condição, uma de condição verdadeira e outra de a
condição falsa, usamos a estrutura de seleção composta. Supondo
que um conjunto de ações dependa da avaliação verdadeiro e uma
única ação primitiva dependa da avaliação falso.

Para melhor compreensão, vejamos o diagrama a seguir, ilustrado na Figura Dia-


grama de execução da função SE - SENÃO.

Diagrama de execução da função SE - SENÃO


Fonte: Forbellone e Eberspacher (2005, p.36)

O pseudocódigo apresentado executa a expressão condicional sobre a nota de um


aluno, se for maior ou igual a 7, tornando-se assim uma condição verdadeira, será
impresso na tela “Aprovado”, em caso da condição retornar falsa, será impresso “Re-
provado”. Vejamos a estrutura do trecho de código em linguagem C, apresentado na
figura “Código de exemplo expressão condicional composta”.
Código de exemplo expressão condicional composta

Fonte: elaborado pelo autor

Para compreender como funciona a estrutura de IF - ELSE, vamos utilizar o mesmo


algoritmo com a função IF e complementar com a estrutura ELSE. Vejamos o código
fonte a seguir na figura “Função If - else com operadores lógicos”.

FACULDADE CATÓLICA PAULISTA | 44


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#include <stdio.h>
#include <stdlib.h>
#define bim 4

mai(){
float nota1, nota2, nota3, nota4, media;

printf(“Informe a nota do 1 Bimestre: “);


scanf(“%f”, &nota1);

printf(“Informe a nota do 2 Bimestre: “);


scanf(“%f”, &nota2);

printf(“Informe a nota do 3 Bimestre: “);


scanf(“%f”, &nota3);

printf(“Informe a nota do 4 Bimestre: “);


scanf(“%f”, &nota4);

media=(nota1+nota2+nota3+nota4)/bim;
printf(“Media final do Aluno: %.1f \n”, media);

// estrutura IF - ELSE
if(media >= 7.0 && nota4 >=6){ // expressão condicional a ser testada
com operador lógico &&
printf(“Aluno Aprovado :) \n”);
}else{
printf(“Aluno Reprovado :( \n”);
}

// estrutura IF - ELSE
if(nota2 > nota1 || nota4 > nota3){ // expressão condicional a ser testada
com operador lógico ||
printf(“Entre os bimestres o aluno aumentou a sua nota.”);
}else{
Printf(“O aluno nao aumentou a sua nota dentre os bimestres”);
}
}

Função If - else com operadores lógicos


Fonte: elaborado pelo autor


Com base no código fonte apresentado, agora temos duas opções de respostas
caso o aluno tenha sido aprovado ou reprovado, isso também se reflete sobre as no-

FACULDADE CATÓLICA PAULISTA | 45


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

tas do aluno entre os bimestres. Vejamos o algoritmo em execução, a seguir, na figura


“Retorno do algoritmo com a estrutura IF – ELSE”.

Retorno do algoritmo com a estrutura IF - ELSE


Fonte: elaborado pelo autor

Observe que agora temos uma resposta para cada desvio condicional, na primei-
ra estrutura, como a média das notas do aluno foi maior que 7 e também a nota do
quarto bimestre foi maior que 6, a mensagem que apareceu foi “Aluno Aprovado”, caso
uma das duas expressões não fosse atendida, o bloco de código presente no else
seria executado, neste caso, a informação impressa na tela seria “Aluno Reprovado”.

Entretanto, na segunda estrutura de desvio condicional composto, devemos notar


que mesmo com a expressão “nota2 > nota1” ter retornado falsa, já que as notas
foram 8 para o primeiro e 7 no segundo, ainda assim foi impresso na tela “Entre os
bimestres o aluno aumentou a sua nota”, isso aconteceu porque estamos utilizando
o operador lógico OU ( || ), como a segunda expressão retornou como verdadeira, se-
guindo o exemplo da tabela verdade apresentada, o bloco executado foi o do IF.

A estrutura de decisão é muito útil no desenvolvimento de um programa, pois ao


utilizá-la, sendo simples ou composta, podemos deixar o programa final mais auto-
matizado, com base nas informações disponibilizadas pelo usuário ou por meio do
comportamento de variáveis do programa.

3.3 Instrução de IFs Aninhados

Conforme visto, as estruturas IF e IF-ELSE são de grande importância e muito úteis


em um programa, mas, por vezes, a partir de uma decisão precisamos associar outra
tomada de decisão, vejamos um exemplo descrito de modo literal:

FACULDADE CATÓLICA PAULISTA | 46


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

SE vou viajar = sim ENTÃO


SE tanque = vazio ENTÃO
Ir ao posto
SENÃO
Ir para a rodovia
SENÃO
Guardar o carro

Compreende-se, então, que temos dois IFs, um dentro de outro, em que a resposta
final é associada às expressões condicionais de ambos, esta estrutura é chamada de
IFs aninhados.

Um if aninhado é um comando if que é o objeto de outro if ou else. IFs aninhados


são muito comuns em programação. Em C, um comando else sempre se refere ao co-
mando if mais próximo, que está dentro do mesmo bloco de else e não está associado
a outro if [..] O padrão C ANSI especifica que pelo menos 15 níveis de aninhamentos
devem ser suportados. Na prática, a maioria dos compiladores permite substancial-
mente mais (SCHILDT, 1997 p. 64).

Para melhor interpretar o conceito de IFs aninhados, observe o trecho de código a


seguir, na figura “Trecho de código com IFs aninhados”.

Figura: Trecho de código com IFs Aninhados


Fonte: Schildt (1997, p. 64)

É possível notar que no bloco de execução do primeiro IF(i), temos outras duas es-
truturas IF(j) e IF(k) - ELSE, poderíamos ter outros IFs no bloco de execução do ELSE
também se fosse o caso. Podemos melhorar o nosso algoritmo de média de notas
do aluno, caso ele tenha sido aprovado e suas notas entre os bimestres forem boas,

FACULDADE CATÓLICA PAULISTA | 47


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

vejamos este algoritmo com IFs aninhados.

#include <stdio.h>
#include <stdlib.h>
#define bim 4

mai(){
float nota1, nota2, nota3, nota4, media;

printf(“Informe a nota do 1 Bimestre: “);


scanf(“%f”, &nota1);

printf(“Informe a nota do 2 Bimestre: “);


scanf(“%f”, &nota2);

printf(“Informe a nota do 3 Bimestre: “);


scanf(“%f”, &nota3);

printf(“Informe a nota do 4 Bimestre: “);


scanf(“%f”, &nota4);

media=(nota1+nota2+nota3+nota4)/bim;
printf(“Media final do Aluno: %.1f \n”, media);

// estrutura IF - ELSE
if(media >= 7.0 && nota4 >=6){ // expressão condicional a ser testada
com operador lógico &&
if(nota4 >= 9){ // IF Aninhado
printf(“Aluno Aprovado, notas acima da media :) \n”);
}else{
printf(“Aluno Aprovado :) “)
}
}else{
printf(“Aluno Reprovado :( \n”);
}

// estrutura IF - ELSE
if(nota2 > nota1 || nota4 > nota3){ // expressão condicional a ser testada
com operador lógico ||
if(nota4 >= 9){ // IF Aninhado
printf(“Entre os bimestres o aluno aumentou a sua nota,
parabens pelo empenho.”);
}else{
printf(“Entre os bimestres o aluno aumentou a sua nota.”);
}
}else{
Printf(“O aluno nao aumentou a sua nota dentre os bimestres”);
}
}
Algoritmo com IFs aninhados
Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 48


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Agora, caso o aluno seja aprovado, efetuamos uma nova validação: caso a nota do
quarto bimestre deste aluno for maior ou igual a nove, a mensagem será “Aluno Apro-
vado, notas acima da média :)”, caso não, será apresentado apenas “Aluno Aprovado”.
A estrutura de IFs aninhados também foi implementada na condição de notas entre os
bimestres, vejamos agora o algoritmo em execução

Retorno do algoritmo com a estrutura de IFs aninhados


Fonte: elaborado pelo autor

O resultado que foi apresentado na tela está ligado diretamente com as estruturas de
desvio condicional IF e IF - ELSE podemos aplicar o conceito de IFs aninhados também
com IF - ELSE, assim iremos gerar uma cascata, cada vez vamos criando novos níveis e
blocos de código, mas devemos tomar cuidado ao usar IFs aninhados para não nos perder
no raciocínio entre estes deixando o código-fonte extremamente confuso.

3.4 Instrução Condicional Múltipla Escolha

As estruturas condicionais IF e IF - ELSE são úteis em casos de tomadas de deci-


sões simples, nos quais temos apenas dois desvios a serem tomados, com base nas
expressões ou operadores lógicos. Entretanto, podemos nos deparar com situações
em que temos diversos caminhos a serem seguidos, podemos chamar isto de seleção
múltipla ou estrutura condicional de múltipla escolha.

[...] C tem um comando interno de seleção múltipla, switch, que


testa sucessivamente o valor de uma expressão contra uma lista
de constantes internas ou de caractere. Quando o valor coincide, os
comandos associados àquela constante são executados (SCHILDT,
1997, p. 70) [...]

Podemos dizer que a estrutura de seleção switch é uma evolução das estruturas
condicionais simples e compostas, pois, por meio desta, podemos ter um leque de
opções e desvios.

FACULDADE CATÓLICA PAULISTA | 49


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

3.4.1 Estrutura do switch

A estrutura de seleção múltipla switch deixa os algoritmos mais dinâmicos, pois po-
demos testar diversas condições a partir de uma variável. Vamos pensar no seguinte ce-
nário: um sistema de cadastro de indicação de filmes de uma locadora devemos fazer o
cadastro dos itens seguindo as classificações indicativas que são regulamentações sobre
as idades indicadas para consumir cada obra. Elas são feitas pela Secretaria Nacional de
Justiça (SNJ), do Ministério da Justiça brasileiro.
Ao desenvolvermos um algoritmo que efetue a leitura do dado informado, podemos ter
diversas opções para a indicação, podemos utilizar a estrutura switch em conjunto com
a expressão case, assim podemos compreender sendo uma lista com a validação dos
desvios.
A execução da estrutura switch compara todos os cases até encontrar um desvio con-
dicional satisfatório, assim executando seu bloco de código, após iniciar a sequência de
códigos, chamamos o comando break, o qual veremos com mais detalhes no próximo
tópico.
Caso nenhum dos itens do switch seja atendido, a estrutura default é acionada, este
item é identificado sendo a saída padrão, caso nenhum dos case atenda à necessidade,
neste momento, o bloco de código a ser executado será apenas o default. Vejamos, a se-
guir, na figura “Composição do SWITCH CASE textual”, os comandos em linguagem C:

Composição do SWITCH CASE textual


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 50


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Mesmo sendo uma estrutura mais poderosa que as de IF - ELSE, devemos atentar
para alguns pontos importantes. Segundo Schildt (1997 p. 70-71), estes itens são:

1. O comando switch difere do comando if porque switch só pode testar igualda-


de, enquanto if pode avaliar uma expressão lógica ou relacional.
2. Duas constantes cases no mesmo switch não podem ter valores idênticos.
Obviamente, um comando switch, incluído em outro switch mais externo, pode ter as
mesmas constantes case.
3. Se constantes de caractere são usadas em um comando switch, elas são
automaticamente convertidas para seus valores inteiros.

Para compreendermos melhor, vamos relembrar o cenário anteriormente apresen-


tado, no qual estamos desenvolvendo um sistema de cadastro de indicação de filmes
com base na informação gerada do usuário e a classificação indicativa. Vejamos o
código-fonte em C, a seguir:

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

main (){
setlocale(LC_ALL, “Portuguese”);
int classificacao;

printf(“-----------------------\n”);
printf(“0 = Livre \n1 = 10 anos \n”);
printf(“2 = 12 anos \n3 = 14 anos \n”);
printf(“4 = 16 anos \n5 = 18 anos \n”);
printf(“9 = Sem Classificação \n”);
printf(“-----------------------\n”);
printf(“Digite a classificação indicativa do filme: “);
scanf(“%d”, &classificacao);

switch (classificacao){
case 0 :
printf(“\n Classificação livre: desenho animados.\n”);
break;

FACULDADE CATÓLICA PAULISTA | 51


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

case 1 :
printf(“\n Classificação 10: presença de armas, medo e ten-
são.\n”);
break;

case 2 :
printf(“\n Classificação 12: violência, lesão corporal, des-
crição de violência.\n”);
break;

case 3 :
printf(“\n Classificação 14: morte, vulgaridade, drogas ilíci-
tas.\n”);
break;

case 4 :
printf(“\n Classificação 16: tortura, mutilação, violência,
morte.\n”);
break;

case 5 :
printf(“\n Classificação 18: violência de forte impacto,
crueldade.\n”);
break;
default:
printf(“\n Sem classificação.\n”);
}
return(0);
}

Algoritmo de classificação de filmes


Fonte: elaborado pelo autor

No algoritmo apresentado será exibida na tela a classificação indicada, conforme


os dados informados pelo usuário, a estrutura será percorrida até encontrar uma con-
dição satisfatória ou será apresentada a mensagem que consta no desvio default.
Vejamos este algoritmo em execução na figura “Retorno do algoritmo de adivinhe
o número oculto”.

FACULDADE CATÓLICA PAULISTA | 52


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Retorno do algoritmo de adivinhe o número oculto


Fonte: elaborado pelo autor

Ao executar o algoritmo, digitamos o número 2, que equivale à classificação de 12


anos, quando a estrutura processada é comparada ao primeiro case, como este não é
o número 2 e passado para o segundo case este também não corresponde ao número
2, já o terceiro case corresponde com o que foi digitado, neste momento, o que estiver
associado a ele será executado, com base em nosso algoritmo a informação exibi-
da em tela terá sido “Classificação 12…”; compreender esta estrutura é interessante,
porque funciona praticamente com a operação lógica de comparação, igualdade de
elementos, não sendo aplicada quando trabalhamos com outros operadores lógicos
como os de maior que, menor que, maior ou igual, dentre outros.

3.4.2 Comando break
O comando break é implementado em diversas estruturas, uma destas é a switch -
case que acabamos de ver, podemos utilizar o comando break ou o comando continue,
para representar a parada ou o andamento da execução do bloco de códigos a serem
executados.

Os comandos break e continue são usados para alterar o fluxo de contro-


le. O comando break, quando executado em uma estrutura while, for, do...
while ou switch causa uma saída imediata dessa estrutura. A execução do
programa continua com a próxima instrução. Os usos comuns do comando
break são para escapar mais cedo de um loop ou para pular o restante de
uma estrutura switch. (DEITEL; DEITEL, 2011, p. 94)

Sobre as estruturas mencionadas, while - for - do...while, estas são consideradas


como estruturas de repetição ou laço de repetição para compreendermos o quão im-
portante é o uso do comando break na estrutura switch, vejamos o código, a seguir,

FACULDADE CATÓLICA PAULISTA | 53


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

sem o uso do comando break:

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

main (){
setlocale(LC_ALL, “Portuguese”);
char operacao;

printf(“Escolha uma oeração [ + - * / ]:”);


scanf(“%c”, &operacao);

switch (operacao){
case ‘+’ :
printf(“\n Adição.\n”);
break;

case ‘-’ :
printf(“\nSubtração”);
break;

case ‘*’ :
printf(“\nMultitplicação”);
break;

case ‘/’ :
printf(“\nDivisão”);
break;

default:
printf(“\nNenhuma operação válida”);
}
return(0);
}

Algoritmo de classificação de filmes


Fonte: elaborado pelo autor


Este algoritmo é bem simples, ele requisita para o usuário escolher uma opera-
ção aritmética, após isso, executamos a estrutura switch - case, observe que neste
código-fonte desenvolvido em linguagem C não utilizamos o comando break após a

FACULDADE CATÓLICA PAULISTA | 54


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

comparação de cada case, neste caso, vejamos este algoritmo em execução na figura
“Retorno do algoritmo sem o comando break”.

Retorno do algoritmo sem o comando break


Fonte: elaborado pelo autor


Ao executar o algoritmo e digitarmos o sinal de adição a estrutura switch é proces-
sada, note que mesmo tendo um caminho de desvio compatível, todos os cases foram
acessados e impressos na tela. O comando break é necessário nesta e em outras es-
truturas para dar a saída da estrutura e não executar o bloco de códigos errados, com
base nisto, vemos que é sempre necessário utilizar o comando break na estrutura de
seleção múltipla.

FACULDADE CATÓLICA PAULISTA | 55


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 4
ESTRUTURAS DE REPETIÇÃO,
VETORES E MATRIZES

Fonte: https://br.freepik.com/vetores-gratis/simbolo-do-infinito-com-efeito-de-reflexo-de-lente_2547657.htm

Uma das vantagens encontradas na computação é capacidade dos computadores


em realizar determinadas tarefas repetidas vezes em um curto espaço de tempo, efe-
tuadas em frações de segundos. De fato, algo muito rápido e quase imperceptível para
o cérebro humano.
Ao escrever um programa em linguagem C, existem muitas situações em que pre-
cisamos repetir um determinado trecho de código por inúmeras vezes. Um exemplo
simples disso é quando queremos identificar a quantidade de números pares existen-
tes em um intervalo de 0 a 100, ou, então, quando queremos que o sistema continue
aberto até que o usuário digite a palavra “SAIR”. Para situações como esta podemos
utilizar uma estrutura que permite estabelecer uma série de repetições do trecho de
código desejado, quantas vezes forem necessárias. Uma estrutura de repetição tam-
bém pode ser definida como um laço de repetição ou malhas de repetição. E para a

FACULDADE CATÓLICA PAULISTA | 56


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

série de repetições utilizamos o termo loop.

O loop é uma das principais características da programação estruturada, pois per-


mite que a tomada de decisão aconteça a partir de uma determinada condição. Ba-
sicamente, um loop pode ter seu número de repetições definido de maneira fixa ou
condicional. Na linguagem C existem 3 tipos de estruturas de repetição: for, while e
do while. O for é uma estrutura do tipo laço contado, pois utiliza um valor previamente
definido para a quantidade de repetições que irá executar. Já as estruturas while e do
while representam laços condicionais, pois o número de repetições está relacionado a
uma determinada condição ser atendida ou não.

De maneira gráfica, podemos exemplificar o funcionamento de um loop da seguinte


forma:

Exemplo gráfico de loop.


Fonte: elaborado pelo autor

Sempre que a condição for verdadeira o programa irá executar um fluxo alternativo,
seguindo as instruções previamente definidas para este caso, garantindo assim que
alguma ação será executada. No entanto, caso a condição seja falsa, o programa irá
seguir o fluxo normal do algoritmo, caracterizando a saída do loop.
Temos que ter muito cuidado também na hora de trabalhar com estruturas de re-
petição para não criarmos um loop infinito. As estruturas de repetição tem como base

FACULDADE CATÓLICA PAULISTA | 57


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

uma condição que é responsável por definir o elemento de parada do loop, sendo,
então, fundamental para que o número de repetições desejadas aconteça da maneira
correta. Quando esse elemento não é informado da maneira adequada ou simples-
mente não é informado, o programa estará sujeito à ocorrência de um loop infinito.
Isto acontece sempre que uma condição nunca se torna falsa ou que seu elemento de
parada nunca é alcançado ou satisfeito.
Exemplo utilizando o comando for:

#include<stdio.h>

int main()
{
int x;
for(x=0;.......; x++)
printf(“%d”, x);
}

Loop infinito.
Fonte: elaborado pelo autor

Neste exemplo, note que não existe uma condição de parada, ou seja, até quando
o laço deve ser executado. Dessa forma, ao executar este programa, a impressão da
variável X acontecerá de maneira infinita.

4.1 Estrutura de Repetição FOR

Muito utilizada na linguagem C, a estrutura de repetição for é caracterizada pelo


laço de repetição contado, ou seja, trata-se de uma estrutura cujo número de repeti-
ções é previamente definido. Esse tipo de estrutura é muito utilizado quando sabemos
exatamente o número de vezes que um determinado trecho de código precisa ser
repetido.
A sintaxe da estrutura de repetição for é composta por uma variável de inicialização,
a condição e o incremento/decremento da variável de inicialização, além da própria
instrução que deverá ser executada durante o laço de repetição. A variável de inicia-
lização é responsável por iniciar a variável por meio de um valor atribuído a ela. Este
valor define a partir de onde o laço inicia suas iterações. A condição representa uma
expressão relacional que é responsável por determinar em que momento o laço de

FACULDADE CATÓLICA PAULISTA | 58


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

repetição deverá ser encerrado. O incremento estabelece como a variável de controle


será atualizada durante as iterações. Podendo ser uma ação para incrementar ou de-
crementar.

O laço for permite muitas variações. Entretanto, a inicialização é,


geralmente, um comando de atribuição que é usado para colocar um
valor na variável de controle do laço. A condição é uma expressão
relacional que determina quando o laço acaba. O incremento define
como a variável de controle do laço varia a cada vez que o laço é
repetido (SCHILDT, 1997, p. 74).

A declaração do laço for deve ser escrita utilizando o próprio nome da estrutura se-
guido de parênteses (). Dentro dos parênteses deve ser informada a variável que será
testada, bem como a condição e o incremento/decremento. Cada uma das seções
precisa ser separada das demais, utilizando ponto e vírgula. Toda essa informação é
apresentada em uma única linha, não sendo permitido realizar a quebra de linha. Na
sequência, define-se a instrução que deverá ser executada. Para escrever a instrução,
podemos utilizar chaves ({}) separá-la das demais instruções que podem ser inseridas
dentro de uma mesma estrutura de repetição, como, por exemplo, em estruturas de
repetição encadeadas. Quando informamos apenas uma instrução, o uso das chaves
é dispensado. Segue abaixo a sintaxe da estrutura de repetição for:

for (i = valor inicial; condição; incremento ou decremento de i)


{
instruções;
}

O laço de repetição for pode ser encontrado em muitas outras linguagens de pro-
gramação, além da C. Isso se dá devido a sua flexibilidade e capacidade de estruturar
o código de uma forma bastante organizada e simples.
Como forma de exemplificar o que foi apresentado até este momento, vamos es-
crever um código em linguagem que permita inserir um nome e que este nome seja
repetido na tela 10 vezes, conforme podemos perceber:

FACULDADE CATÓLICA PAULISTA | 59


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#include <stdio.h>

int main()
{
char nome[20];
int i;
printf(“\n Informe o nome: “);
scanf(“%s”, nome);
for(i=1; i<=10; i++)
{
printf(“\n %s”, nome);
}
return(0);
}

Exemplo for nome.


Fonte: elaborado pelo autor

Neste exemplo, temos a variável “nome” que é do tipo caractere (char) que será uti-
lizada para receber o nome que será digitado e, também a variável “i”, que irá controlar
o número de vezes que o laço será repetido. Ao informar o nome, o programa arma-
zenará a informação dentro da variável e em seguida executará o laço de repetição.
Perceba que dentro do próprio laço de repetição a variável “i” é iniciada com o valor 1.
Sendo assim, o laço deverá ser repetido até que a variável “i” seja menor/igual a 10. A
verificação desta condição é feita por meio do operador relacional menor igual (<=).
Durante a execução do laço for a variável “i”, que inicialmente havia sido definida com
o valor 1, passa a ser atualizada a cada ciclo de repetição do laço. Para isso, utilizamos
o sinal de incremento (++), para que a cada iteração do laço, o valor da variável seja
acrescido de mais 1. Definida a condição do laço de repetição, o programa irá executar
as instruções configuradas dentro da estrutura, conforme abaixo:

Exemplo laço for digitar nome.


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 60


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Impressão do nome digitado


Fonte: elaborado pelo autor

A instrução informada será repetida até que o laço alcance seu limite de iterações,
que, neste caso, é 10. Assim, o nome informado inicialmente será impresso na tela 10
vezes.

4.2 Estrutura de Repetição WHILE

A estrutura de repetição é utilizada em diversas situações, por meio dela podemos


especificar a quantidade de vezes que queremos que um determinado bloco de código
seja executado. Cada estrutura de repetição é uma particularidade, caso esta não seja
atendida, o bloco de código pode ou não ser executado.
Uma das vantagens de se utilizar um laço de repetição é um código-fonte menor e
mais fácil de se manter, pois reduzimos para poucas linhas o bloco de execução, cada
estrutura de repetição tem a sua particularidade, mas todas têm o mesmo fim, a repe-
tição, até que a condição a ser analisada seja satisfeita.

A particularidade da estrutura de repetição while está justamente no fato de que


para executá-la, deve-se atender a uma determinada condição para assim ser execu-
tado o laço, a cada laço esta condição é testada.

O comando while consiste na palavra-chave while seguida de uma


expressão de teste entre parentes. Se a expressão de teste for
verdadeira, o corpo do laço é executado uma vez e a expressão de
teste é avaliada novamente. Esse ciclo de teste e execução é repetido
até que a expressão de teste se torne (igual a zero), então o laço
termina e o controle do programa passa para a linha seguinte ao laço
(MIZRAHI, 2008, p. 73).

FACULDADE CATÓLICA PAULISTA | 61


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

while (condição){
<bloco de código a ser executado>

função de incremento
}
Composição da estrutura de repetição While
Fonte: elaborado pelo autor

Para compreendermos melhor como podemos utilizar a estrutura while, vamos com-
preender melhor o algoritmo que foi implementado quando trabalhamos estudamos so-
bre if aninhados, o algoritmo no qual o usuário tenta descobrir qual o número oculto, a
diferença, neste caso, é que ele não terá mais um limite de chances e o número está em
torno de 0 a 100, em que o usuário irá contar com as dicas, se o número oculto é maior ou
menor do que o digitado pelo usuário. Vejamos o código fonte a seguir.

#include<stdio.h>
#include<stdlib.h>
#include<locale.h>

int main()
{
setlocale(LC_ALL, “Portuguese”);
int nOculto, nUsuario = 0;
nOculto = rand() % 100;

printf(“Descubra qual o numero oculto, entre 0 e 100. \nVocê não tem
um limite de chances\n\n”);
while(nUsuario != nOculto)
{
printf(“Qual o seu primeiro palpite? “);
scanf(“%d”, &nUsuario);
// estrutura IF - ELSE
if (nUsuario == nOculto){
printf(“Parabéns você descobriu o número %d \n”, nOcul-
to);
break; // força a parada do algoritmo
}else{
if(nOculto > nUsuario){
printf(“O Número oculto é maior que %d \n\n”, nU-
suario);
}else{
printf(“O Número oculto é menor que %d \n\n”, nU-
suario);
}
}
}
}
Estrutura de repetição while
Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 62


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Note que a expressão no laço de repetição while é nUsuario != nOculto, sendo que se
o número digitado pelo usuário foi diferente do número oculto, o laço de repetição ficará
em constante loop até que o usuário digite o número correto, para que possamos forçar
a entrada no laço de repetição while, já que este só se inicia se a expressão foi atendida.
Testando a expressão no início, inicializamos a variável nUsuario sendo 0, desta forma,
podemos considerar que o laço sempre vai ser executado, e mesmo que o número oculto
seja realmente zero, o laço não será executado. Vejamos o algoritmo em execução.

Retorno do algoritmo “acerte o número oculto”


Fonte: elaborado pelo autor

Perceba que a aplicação só parou de executar quando o número oculto foi encon-
trado, este tipo de estrutura de repetição não entra em um loop infinito, pois, em algum
momento, o número oculto será descoberto, parando o processo é apresentado na
tela qual é o número, conforme demonstrado na imagem acima.

4.3 Estrutura de Repetição DO-WHILE

Vimos como é útil utilizar uma estrutura de repetição; uma derivação da while é a
estrutura DO --- WHILE que também é considerada como um laço de repetição, ambas
têm a sua composição bem parecida, entretanto, com alguns pequenos detalhes.

A estrutura do while é uma estrutura do tipo laço condicional, isto é, o


loop baseia-se na análise de uma condição. Essa estrutura é utilizada
quando temos um número indefinido de repetições e precisamos
que o teste condicional seja realizado após a execução do trecho
de código. Nesse tipo de estrutura, o trecho de código é executado
pelo menos uma vez, pois o teste condicional é realizado no fim
(ASCENCIO; CAMPOS, 2010 p. 67).

FACULDADE CATÓLICA PAULISTA | 63


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Os pontos de maior diferença entre as duas estruturas estão no fato de entrada e


teste condicional, na estrutura while, o laço só é executado se a expressão condicional
inicial for atendida, caso contrário, este nem é executado, podendo assim nem ser
executado no programa. A estrutura do -- while já não testa a condição de entrada,
desta forma, seu laço será executado ao menos uma vez, seu teste condicional não é
de entrada, mas, sim, de saída do laço.
Veja a sintaxe do laço de repetição:

do{
<bloco de código a ser executado no loop>

}while(condição);

Título Composição textual do laço Do … While


Fonte: elaborado pelo autor

Para lhe ajudar a compreender o funcionamento desta estrutura vejamos o código-


-fonte em linguagem C, em que o usuário digita a quantidade de repetição desejada
com a estrutura do -- while para que execute e informe por linha cada laço. Observa-
mos o código a seguir:

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

main(void){
setlocale(LC_ALL, “Portuguese”);
int numero, i=0;
printf(“Digite a quantidade de repetições: “);
scanf(“%d”, &numero);
do{
i++;
printf(“%dº Número\n”, i);

}while (i < numero);
printf(“\nFim da Estrutura DO -- WHILE\n\n”);
}

Algoritmo de exemplo DO --- WHILE


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 64


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Note que após o usuário digitar um determinado número, a estrutura do -- whi-


le já é executada, não sendo validada a entrada, o laço ficará efetuando as repetições
até que a condição i < numero seja atendida. Vejamos o algoritmo em execução.

Figura: Resultado do programa de exemplo DO --- WHILE


Fonte: elaborado pelo autor

Esta estrutura de repetição é interessante de se utilizar quando pretendemos de-


senvolver um código que force o laço, uma utilização seria o menu de um programa,
pois este sempre tem que se repetir a cada iteração e ao ser executado, já deve ficar
disponível para o usuário.

4.4 Vetores e Matrizes

As estruturas de vetores e matrizes são muito utilizadas quando é necessário ter-


mos que armazenar muitas variáveis para o mesmo fim. Por exemplo, vamos pensar
que estamos desenvolvendo um sistema que deverá armazenar/manipular por vez
uma quantidade de 10 registros, teríamos que ter no caso 10 variáveis declaradas,
em vez disso podemos utilizar um vetor ou matriz, para fazer este armazenamento,
declarando apenas 1 variável.

Vetores
Um vetor pode ser identificado como array por autores diferentes ou em linguagem
específicas, em tese, ambos podem ser considerados a mesma coisa e têm as mes-
mas propriedades e características.
Um array é um conjunto de espaços de memória que se caracterizam pelo fato de
que todos têm o mesmo nome e o mesmo tipo de variável (CHAR, INT, FLOAT) (Adap-

FACULDADE CATÓLICA PAULISTA | 65


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

tado de DEITEL, 2011, p.161).

Um vetor também é conhecido como variável composta homogênea unidimensio-


nal. Isso quer dizer que se trata de um conjunto de variáveis de mesmo tipo, as quais
possuem o mesmo identificador (nome) e são alocadas sequencialmente na memó-
ria. Como as variáveis têm o mesmo nome, o que as distingue é um índice que referen-
cia sua localização dentro da estrutura (ASCENCIO; CAMPOS, 2007, p.144).

Ao trabalharmos com vetores devemos nos atentar a sua declaração, pois con-
forme as variáveis em geral a entrada de dados nesse vetor só será aceito se ele for
de igual tipo declarado. Exemplo: se o vetor for declarado como CHAR, só receberá
caracteres, caso o vetor for declarado com o tipo INT, só serão armazenados dados
numéricos inteiros.

Veja a sintaxe da declaração de um vetor:

Estrutura da declaração de um vetor do tipo inteiro


Fonte: elaborado pelo autor

No trecho de código apresentado temos a declaração de um vetor com o nome nu-


mero, cujo tamanho será de armazenamento será 5, do tipo INT. O tamanho do vetor
aceita apenas números inteiros, a quantidade 5 posteriormente representará o local
que um dado será armazenado no vetor.

FACULDADE CATÓLICA PAULISTA | 66


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Representação de alocação de um dado no vetor


Fonte: Ascencio e Campos (2007, p.144).

Para que possamos acessar algum local no vetor, devemos informar qual o local:

x[1] = representa a 1º posição do vetor, é possível acessar o dado armazenado


se referenciando a sua posição.
x[4] = representa a 4º posição do vetor, é possível acessar o dado armazenado
se referenciando a sua posição.
x[45] = representa a 45º posição do vetor, é possível acessar o dado armaze-
nado se referenciando a sua posição.

Exemplo de alocação de dados no vetor


Fonte: Ascencio e Campos (2007, p.145).

Em um mesmo programa podemos ter vários vetores de diversos tipos, normal-


mente as informações são inseridas no vetor através de um laço de repetição ( FOR,
WHILE ou DO ... WHILE ), conforme visto no código a seguir.

FACULDADE CATÓLICA PAULISTA | 67


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#include <stdio.h>

int idade[3];
int i, j;

main(){
for(i=0; i<3; i++){
printf(“Digite sua Idade:”);
scanf(“%d”, &idade[i]);
}

for(j=0; j<3; j++){


printf(“Idade Armazenada no local %d: %d \n”, j, idade[j]);
}
}

Resultado do exemplo utilizando vetores


Fonte: elaborado pelo autor

Através do laço de repetição for, foram inseridas 3 entradas de dados nas posições
do vetor número, posteriormente, em outro laço de repetição for, foram apresentados
os dados na tela.

Um ponto muito importante que devemos observar é que todo e qualquer vetor ou
matriz tem sua posição inicial como zero, por exemplo:
ao declararmos um vetor de 3 posições idade[3]
as posições respectivamente para acessar os dados armazenados serão ida-
de[0], idade[1] e idade [2]

FACULDADE CATÓLICA PAULISTA | 68


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Matrizes

Podemos considerar que uma matriz é um vetor melhorado, um vetor trabalha com
elementos em apenas 1 dimensão já uma matriz trabalha em 2 dimensões, pois os
vetores guardam dados do mesmo tipo de variável em uma única linha, através de
colunas, já uma matriz trabalha com linhas e colunas, sendo a primeira posição a
quantidade de linha e a segunda, a de colunas, assim podemos multiplicar os espaços
de armazenamento, por isso a matriz é considerada uma estrutura bidimensional.

A sintaxe da declaração de uma matriz:

Fonte: elaborado pelo autor

Ao recordarmos o modo de declararmos um vetor sendo idade[5], estamos infor-


mando que a variável irá armazenar 5 registros, cada um em uma posição no vetor,
iniciando de 0 a 4, ao efetuarmos a declaração de uma matriz sendo idade[5][3], será
possível armazenar 5*3, um total de 15 registros, pois teremos 5 linhas e 3 colunas.

Para manipular os elementos dentro de uma matriz, são utilizadas as coordenadas


de sua posição:
idade[3][2] = será acessada a 3ª linha e buscados os dados contidos na 2ª
coluna;
numero[1][16] = será acessada a 1ª linha e buscados os dados contidos na
16ª coluna;
idade[45][13] = será acessada a 45ª linha e buscados os dados contidos na
13ª coluna.

A forma de entrada de dados é muito parecida com a do vetor, mas dessa vez te-
mos que utilizar dois laços de repetição, um que representa a linha, e outro, a coluna.

FACULDADE CATÓLICA PAULISTA | 69


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#include <stdio.h>

main (){
int numero[3][4];
int m, p;

printf (“\nDigite os numeros para os elementos da matriz\n\n”);

for ( m=0; m<3; m++ ){ // laço de repetição da linha

for ( p=0; p<4; p++ ){ // laço de repetição da coluna



printf (“Elemento[%d][%d] = “, m, p);
scanf (“%d”, &numero[ m ][ p ]);
}
}

printf(“\n\n******************* Resuldato da Matriz ********************* \n\n”);

for ( m=0; m<3; m++ ){

printf (“ [%d][%d][%d][%d] \n”, numero[m-1][p], numero[m-1][p+1], numero[m-1]


[p+2], numero[m-1][p+3]);
}

Resultado do programa utilizando uma Matriz


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 70


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

No resultado apresentado podemos observar como os elementos de 1 a 4 foram


armazenados na primeira linha, elementos de 5 a 8 segunda linha e por fim os elemen-
tos de 9 a 12 na terceira linha. Podemos associar o conceito de uma matriz a uma
tabela, onde em cada célula da tabela podemos ter o armazenamento de dados.
O uso de matrizes é muito útil quando estivermos trabalhando com um volume de
dados mais complexos de manipulação.

FACULDADE CATÓLICA PAULISTA | 71


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 5
FUNÇÕES E PONTEIROS

Fonte: https://pixabay.com/pt/photos/codifica%c3%a7%c3%a3o-computador-hacker-1841550/

Em certos pontos de um programa, temos que repetir um bloco de código por vá-
rias vezes, essa repetição deixará nosso código fonte muito extenso podendo causar
lentidão quando executado. Uma solução para esta situação seria um laço de repe-
tição, mas imagine que você deseja aproveitar apenas pequenos trechos de códigos
em locais específicos, a intenção não seria fazer um repetição, mas sim aproveitar
trechos já existentes.
Para fazer o reuso de trechos de código podemos utilizar funções para evitar que
um trecho seja repetido por várias vezes de modo desnecessário, assim havendo um
reaproveitamento do código já desenvolvido.
Podemos também aprimorar o nosso código utilizando os ponteiros, os quais
podem assumir o armazenamento de outras variáveis, posteriormente efetuando o
apontamento do local.

FACULDADE CATÓLICA PAULISTA | 72


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

5.1 Funções

Função são estruturas poderosas, onde é possível escrever um bloco de código e


posteriormente utilizar o mesmo em qualquer momento do programa. Podemos dizer
que esta estrutura seria uma base considerada para o paradigma de orientação a ob-
jetos, onde é aplicado um conceito parecido com o uso de Classes. Os principais be-
nefícios de se utilizarem funções seriam: uma melhor organização e reaproveitamento
do código, consequentemente, um melhor entendimento do código fonte.
As funções são blocos de construção em C, em que ocorrem todas as atividades do
programa. Assim que uma função tenha sido escrita e depurada, poderá ser reutiliza-
da quantas vezes for necessário (SCHILDT, 1986 p.78).
Uma função é uma subrotina que tem como objetivo desviar a execução do progra-
ma principal para realizar uma tarefa específica e retornar um valor. São estruturas
que possibilitam ao usuário separar seus programas em blocos (ASCENCIO; CAM-
POS, 2010).
Em linguagem C uma função é um conjunto de ações que são executadas a partir
da sua chamada no código. Cada função pode conter declarações de variáveis, instru-
ções, ou até mesmo, outras funções.

Veja a sintaxe da declaração de uma função:

Composição textual da declaração de função


Fonte: elaborado pelo autor

Podem-se declarar as variáveis que serão utilizadas em função de três formas: glo-
bais, locais e parâmetros formais.
Variáveis globais: são declaradas fora da função, como as demais, Albano
e Albano (2010 p.132). Podemos dizer que são as variáveis declaradas no início do
código fonte, podendo ser utilizadas ou manipuladas por qualquer função ou bloco de
comando.
Variáveis locais: são declaradas dentro da função a ser utilizada, Albano e Al-
bano (2010 p.132) afirmam que “as variáveis locais pertencem apenas à função onde

FACULDADE CATÓLICA PAULISTA | 73


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

foram declaradas, não podendo, portanto, ser acessadas por meio de outra função de
forma direta”.
Parâmetros formais: são declarados na passagem de dados para a função,
veremos com mais detalhe no próximo tópico.

Exemplo da criação de uma função


Fonte: elaborado pelo autor

Vamos analisar os códigos a seguir, sendo um desenvolvido de modo convencional


e outro com a aplicação de funções:

Exemplo de programa sem utilizar funções


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 74


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Na imagem apresentada, podemos observar que o trecho de código de soma é


replicado 3 vezes, deixando o código mais extenso, além de utilizar diversas variáveis
de modo desnecessários, Vejamos agora a mesma lógica algorítmica, mas desta vez
aplicando o uso da estrutura de função:

Código com aplicação de funções


Fonte: elaborado pelo autor

É possível ver claramente que, ao se utilizar a função, nosso código fonte ficou me-
nor, podendo agora efetuar a chamada da função soma() em qualquer parte do código
fonte.

Resultado do programa em C apresentado


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 75


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Compreenda prezado(a) aluno(a), que para o usuário final, ambas as soluções pa-
recem as mesmas, visto que o usuário final não tem acesso ao código fonte, mas
perceba que o código em si sofre modificações consideráveis, sendo menor e mais
organizado.

5.2 Passagem parâmetros de função

Ao utilizarmos funções podemos enviar informações a serem tratadas dentro das


mesmas, pode-se efetuar este procedimento por meios das variáveis de parâmetros
formais, ou em outras palavras por passagem de parâmetros. A sintaxe da função so-
fre apenas algumas modificações, pois é inserida uma lista de parâmetros esperada
para ser utilizada dentro da função.
As funções com passagem de parâmetros são aquelas que recebem valores no
momento em que são chamadas. Na passagem de parâmetros, os valores são incluí-
dos na chamada da função, respectivamente conforme são declarados no escopo da
função. A passagem de parâmetro ocorre quando é realizada a substituição dos parâ-
metros declarados pelos indicados no momento da chamada de execução da função.
A passagem de parâmetro por valor não altera o conteúdo, quando o parâmetro
formal é manipulado na função. Isto é, qualquer alteração na variável local da função
não afetará o valor do parâmetro real correspondente. Na passagem de parâmetros
por valor, a função trabalha com cópias dos valores passados no momento de sua
invocação (MANZANO; OLIVEIRA, 1997; ASCENCIO; CAMPOS, 2010).

<tipo_de_retorno> <nome_da_função> (<parâmetros>) {


<corpo_da_função>
}

O tipo_de_retorno informa que tipo de dado é esperado como retorno, nome_fun-


ção nome de identificação a ser utilizado quando chamada, parâmetros as variáveis
de manipulação contidas na função, por fim corpo_da_função instruções a serem exe-
cutadas dentro da função.

Na passagem de parâmetros, os dados das variáveis são armazenados em novas


variáveis declaradas dentro dos parentes (..), sendo respeitada a respectiva ordem de
parâmetros, mas temos um ponto de atenção “caso seja declarado uma variável do
tipo inteiro, no momento da chamada da função, deve-se passar um argumento do

FACULDADE CATÓLICA PAULISTA | 76


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

mesmo tipo”. Temos também dois tipos de parâmetros a serem utilizados: os reais,
que são dados obtidos na entrada pelo usuário, e os formais, que são os parâmetros
declarados na função.

Fonte: elaborado pelo autor

Resultado do programa em C apresentado


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 77


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Na passagem de parâmetro por referência, os parâmetros passados para a função


consistem em endereços de memória ocupados por variáveis. Na passagem por refe-
rência, o valor do parâmetro real é alterado quando o parâmetro formal é manipulado
dentro da função (ASCENCIO; CAMPOS, 2010).

Fonte: elaborado pelo autor

Observe que, na chamada da função areaQua, temos a declaração do endereço


de memória que ocupado a variável não o seu valor alocado. Perceba que, agora as
operações que são realizadas no interior dentro da função são sobre ponteiros, veja
que os tipos da variáveis de manipulação são do tipo pointer (observe o asterisco “*”
na declaração do parâmetro). Assim, temos que inserir o operador “*” antes do iden-
tificador para trabalhar com os valores armazenados e não o endereço da memória.
O protótipo de uma função é uma linha igual ao cabeçalho da função, acrescido de
ponto e vírgula que deve ser escrito antes da função main. Esta linha é responsável
por informar ao compilador que outras funções deverão ser encontradas ao término
do main (ASCENCIO; CAMPOS, 2010).
Por fim, podemos compreender que a aplicação de funções será uma prática muito
importante para o seu conhecimento, ao trabalharmos com linguagens baseadas em
orientação a objetivos, a utilização de funções e manipulação de parâmetros será de
grande auxílio ao futuro desenvolvedor de sistemas.

5.3 Ponteiros

Conforme apresentado em unidades anteriores, quando declaramos uma variável

FACULDADE CATÓLICA PAULISTA | 78


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

em nosso código fonte, automaticamente é reservado um espaço na memória para


armazenamento dos dados para a mesma, cada espaço possui um endereço lógico,
um número hexadecimal e, por meio desse endereço, é possível recuperar e manipular
as informações armazenadas. Mas vamos com calma, não precisamos saber qual é o
endereço lógico da variável para fazer a sua manipulação, a linguagem de programa-
ção possui bibliotecas específicas para este fim, exemplo STDIO.H, como também o
próprio SO (Sistema Operacional) e o programa em execução.
Basicamente, um ponteiro é uma variável que armazena um endereço de memória,
isto é, o ponteiro é um tipo de variável capaz de atribuir somente os endereços de
outra variável ao seu conteúdo, o qual é bem diferente das variáveis comuns com as
quais estávamos trabalhando até o momento (ALBANO, ALBANO 2010 p.156).
Podemos utilizar ponteiros em nosso código fonte, o seu uso é considerado como
uma variável, o modo de declará-lo inclusive é bem parecido com a forma de declara-
ção demais variáveis, a única diferença é que antes do nome do ponteiro é inserido o
caractere asterisco *, vejamos a sintaxe de declaração de um ponteiro:

Composição textual da declaração de um ponteiro


Fonte o autor

Pode-se utilizar um ponteiro com variável de diversos tipos como INT, FLOAT, CHAR
e também STRUCT, vejamos a seguir um código no qual se utiliza um ponteiro do tipo
inteiro

Exemplo de programa utilizando ponteiro


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 79


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Resultado do programa utilizando ponteiro


Fonte: elaborado pelo autor

Perceba prezado(a) aluno(a), que um ponteiro vai armazenar o endereço de memó-


ria de outra variável, no primeiro momento você poderá ter a ilusão que temos duas
variáveis armazenando o mesmo valor 15, mas na verdade o valor 15 está contido
apenas o endereço de memória da variável numero, um ponteiro literalmente apenas
aponta qual é o endereço de memória. Vejamos mais um exemplo.

Exemplo 2 de programa utilizando ponteiros


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 80


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Resultado do exemplo 2, utilizando ponteiros


Fonte: elaborado pelo autor

Ao colocar em prática os conceitos de ponteiro devemos observar que quando al-


teramos o valor de uma variável, a qual mantém a informação original armazenada,
esse novo valor reflete no conteúdo para o qual o ponteiro está apontando. Também
é importante ressaltar que ao criar um ponteiro, na verdade estamos criando uma va-
riável que aponta para um endereço de um determinado tipo, ou seja, tanto o ponteiro
e a variável original devem ser do mesmo tipo.

FACULDADE CATÓLICA PAULISTA | 81


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 6
LISTAS ENCADEADAS E
DUPLAMENTE ENCADEADAS

Fonte: https://www.pexels.com/pt-br/foto/papel-de-parede-de-graficos-de-computador-1544947/

Uma lista linear nada mais é que um vetor onde os dados são armazenados e agru-
pados, os dados armazenados podem estar dispostos de maneira sequencial ou não,
isso não fará diferença, pois cada elemento possui uma identificação sobre qual será
o próximo elemento no vetor. Os elementos do vetor não precisam estar necessaria-
mente na sequência física, alocados na memória, mas sim, logicamente, na ordem
crescente no vetor. Podemos utilizar como exemplo o atendimento de um banco, con-
forme as pessoas chegam ao local é atribuído a elas uma senha, estas pessoas pode-
rão estar dispersas no interior do banco, mas conforme forem sendo chamadas o que
prevalece é a senha.
As listas lineares sempre dão sentido na ordem, por exemplo, um elemento que
está armazenado na posição 3 do vetor irá apontar para o próximo, este poderá estar
na posição 4 do vetor ou não, a ideia é que o elemento atual sempre irá apontar para

FACULDADE CATÓLICA PAULISTA | 82


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

alguma outro ou atribuir null e assim por diante. Temos vários tipos de listas, mas
todas têm o mesmo princípio.

6.1 Listas Encadeadas

Conforme visto anteriormente, uma lista é um vetor no qual são armazenados vá-
rios elementos, tais elementos poderão estar ou não ordenados, como também não
precisam ser necessariamente valores numéricos, como uma lista encadeada se re-
fere a um vetor o qual é possível percorrer de forma ordenada, mesmo se os dados
não estiverem em ordem dentro do vetor, ou seja, o que irá interferir na forma de per-
correr é a informação contida no apontamento.

Numa lista encadeada, para cada novo elemento inserido na estrutura,


alocamos um espaço de memória para armazená-lo. Desta forma,
o espaço total de memória gasto pela estrutura é proporcional ao
número de elementos nela armazenado. No entanto, não podemos
garantir que os elementos armazenados na lista ocuparão um
espaço de memória contíguo, portanto não temos acesso direto
aos elementos da lista. Para que seja possível percorrer todos os
elementos da lista, devemos explicitamente guardar o encadeamento
dos elementos, o que é feito armazenando-se, junto com a informação
de cada elemento, um ponteiro para o próximo elemento da lista
(RANGEL, 2008, p.85).

Em uma lista encadeada simples consiste em diversos nós (posições do vetor) pre-
enchidos uma sequência de elementos, sendo que cada alocação segue a posição de
preenchimento do vetor, o elemento em si poderá estar fora de ordem, o que dará sen-
tido a lista será os apontamentos. Uma lista se inicia com um elemento e um ponteiro
que indica o próximo nó, dessa forma, a partir do primeiro elemento podemos percor-
rer todo o vetor, seguindo o encadeamento. O último elemento aponta para NULL, o
que sinaliza que não temos mais elementos.

Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 83


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

No exemplo apresentado na Figura XXX, ao se percorrer o vetor, a leitura se inicia


pela alocação X1, junto ao valor alocação, é armazenado um ponteiro que informa
qual será a próxima posição dentro do vetor. Conforme cada elemento da lista sendo
visitado temos pelo menos 2 informações: o valor armazenado e um ponteiro que in-
dica o próximo elemento. No caso apresentado, a leitura será feita da seguinte forma:
X1 -> X2 -> X3 -> X4 -> X5 e para, pois X5 não aponta para nenhum outro elemento.

Um ponto interessante ao analisar este exemplo é que os valores das posições do


vetor (0-4) são fixos, sendo assim esta seria uma lista desordenada, mas não impede
a navegação pela mesma por causa dos direcionamentos dos ponteiros.

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

typedef struct elem elemento;

struct elem {
int dado;
elemento *prox;
};

void insere (int x, elemento *p){


elemento *nova;
nova = (elemento *) malloc (sizeof(elemento));
nova->dado = x;
nova->prox = p->prox;
p->prox = nova;
}
void imprime(elemento *ini){
elemento *p;
system(“cls”);
printf(“\nElementos na lista:\n”);

for (p = ini->prox; p != NULL; p = p->prox) {
printf (“%d\t”, p->dado);
}
printf (“\n”);
}
int main() {
setlocale(LC_ALL, “”);

FACULDADE CATÓLICA PAULISTA | 84


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

int op = -1, valor;


elemento *lista = NULL;
lista = (elemento *) malloc(sizeof(elemento));

while (op != 0) {
printf(“\nOpções do Menu:\n”);
printf(“\t1 - mostrar lista.\n”);
printf(“\t2 - inserir novo elemento na lista.\n”);
printf(“\t0 - sair do programa.\n”);

printf(“Digite a opção desejada: “);
scanf(“%d”, &op);

switch(op) {
case 0: printf(“\n\nSair do sistema\n”); break;
case 1: imprime(lista); break;
case 2:{
printf(“\nEntre valor a ser inserido na lista: “);
scanf(“%d”, &valor);
insere(valor, lista);
system(“cls”);
break;
}
default: printf(“\n\nOpção invalida !\n”);
}
}
return 0;
}

Fonte: elaborado pelo autor

Com base no código de implementação da lista encadeada, podemos observar


com mais detalhes a função insere():

void insere (int x, elemento *p){


elemento *nova;
nova = (elemento *) malloc (sizeof(elemento));
nova->dado = x;
nova->prox = p->prox;
p->prox = nova;
}
Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 85


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Nesta função a cada elemento inserido é informado o dado “valor armazenado” e o


prox “ponteiro do próximo elemento da lista”, neste exemplo em particular os elemen-
tos vão ser inseridos em ordem de inclusão, mas caso fosse a necessidade poderia
ser modificado para indicar a posição do vetor.

6.2 Listas Duplamente Encadeadas

A estrutura apresentada anteriormente é conhecida como lista encadeada simples,


na qual se armazena apenas o ponteiro do próximo elemento a ser lido. Um problema
que encontramos nesse tipo de estrutura é que sempre somos levados para frente,
não podemos voltar em nenhum elemento já visitado não podendo navegar pela lista,
caso precise acessar o elemento anterior, isso não é possível, da mesma forma que
somos obrigados a percorrer toda a lista para encontrar o elemento desejado, lem-
brando que ainda não estamos lidando com listas ordenadas.

Caso seja necessário ler um elemento anterior, temos que concluir toda a leitura e
reiniciá-la. Rangel (2008 p. 18) afirma que uma solução é a lista duplamente encade-
ada:

Nelas, cada elemento tem um ponteiro para o próximo elemento e um


ponteiro para o elemento anterior. Desta forma, dado um elemento,
podemos acessar ambos os elementos adjacentes: o próximo e o
anterior. Se tivermos um ponteiro para o último elemento da lista,
podemos percorrer a lista em ordem inversa, bastando acessar
continuamente o elemento anterior, até alcançar o primeiro elemento
da lista, que não tem elemento anterior (o ponteiro do elemento
anterior vale NULL).

Com a lista duplamente encadeada é possível percorrer toda a estrutura, chegando


ao último elemento, podemos também encerrar ou efetuar a leitura inversa dos ele-
mentos e, em qualquer momento, podemos voltar para o elemento anterior.

FACULDADE CATÓLICA PAULISTA | 86


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Fonte: elaborado pelo autor

Vemos como é percorrida a lista ao ser iniciada pelo elemento que está armazena-
do no X1:

Indicação do Elemento Elemento Atual Indicação do Próximo


Anterior Elemento
NULL X1 X2
X1 X2 X3
X2 X3 X4
X3 X4 X5
X4 X5 NULL
Fonte: elaborado pelo autor

Perceba, caro(a) aluno(a), que se estivermos no elemento X4 podemos retornar


para o elemento X3, ou podemos ir para o X5, entretanto desejarmos ir para o elemen-
to X1 temos que percorrer todos os demais elementos até chegar no nosso destino,
sendo também possível ir para frente ou para trás a qualquer momento.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>

FACULDADE CATÓLICA PAULISTA | 87


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

typedef struct DPessoa{


char nome[30];
int idade;
char sexo;
} Pessoa;

typedef struct No{


Pessoa p;
struct No *ant, *prox;
} ListaDE;

ListaDE* insere (ListaDE *l){


ListaDE *novo;
char nome[30], sexo; int idade;
novo = (ListaDE *) malloc (sizeof (ListaDE));
printf(“Nome: “); scanf(“%s”,&novo->p.nome);
printf(“Idade: “); scanf(“%d”,&novo->p.idade);
printf(“Sexo (F ou M): “); scanf(“%s”,&novo->p.sexo);
novo->prox = l;
novo->ant = NULL;
if (l!=NULL) l->ant = novo;
l = novo;
return l;
}
void percorre (ListaDE *l){
if (l == NULL){
return;
}else {
printf(“%s - %d - %c \n”,l->p.nome, l->p.idade, l->p.sexo);
percorre(l->prox);
}
}
int main(){
setlocale(LC_ALL, “”);
int op = -1, valor;
ListaDE *l;
l = NULL;

while (op != 0) {
printf(“\nOpções do Menu:\n”);
printf(“\t1 - mostrar lista.\n”);
printf(“\t2 - inserir novo elemento na lista.\n”);
printf(“\t0 - sair do programa.\n”);

FACULDADE CATÓLICA PAULISTA | 88


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

printf(“Digite a opção desejada: “);


scanf(“%d”, &op);

switch(op) {
case 0: printf(“\n\nSair do sistema\n”); break;
case 1: {system(“cls”); percorre(l); break;}
case 2:{ l = insere(l); system(“cls”); break;
}
default: printf(“\n\nOpção invalida !\n”);
}
}
}
Implementação em linguagem C de uma lista duplamente encadeada
Fonte: elaborado pelo autor

Podemos notar que o código fonte sofreu modificação, mas o ponto mais relevante
está na função insere().

ListaDE* insere (ListaDE *l){


ListaDE *novo;
char nome[30], sexo; int idade;
novo = (ListaDE *) malloc (sizeof (ListaDE));
printf(“Nome: “); scanf(“%s”,&novo->p.nome);
printf(“Idade: “); scanf(“%d”,&novo->p.idade);
printf(“Sexo (F ou M): “); scanf(“%s”,&novo->p.sexo);

novo->prox = l;
novo->ant = NULL;
if (l!=NULL) l->ant = novo;
l = novo;
return l;
}

Observamos que no trecho destacado estamos informando e validando a questão


da identificação dos ponteiros do próximo e elemento anterior. Assim é possível na-
vegar pela estrutura de lista.

FACULDADE CATÓLICA PAULISTA | 89


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 7
LISTAS ORDENADAS
E CIRCULARES

Fonte: https://br.freepik.com/vetores-gratis/maquete-de-estante-branca-livros-na-prateleira-na-biblioteca_8548736.htm#page=3&query=livros&position=46

Vimos na aula anterior os princípios sobre a estrutura de dados de lista encadeadas


simples e duplamente encadeadas. Vale lembrar que os elementos podem ser inseri-
dos de modo desordenado nas listas, neste sentido o uso dos apontamentos próximo
e anterior se fazem necessários, mas pense nunca caso uma busca em uma vetor,
se este estiver desordenado você teria que percorrer diversos vetores até encontrar o
dado procurado, ou até mesmo percorrer toda a lista para descobrir que o que você
procura nem está armazenado.
Façamos uma analogia ao comparar os elementos de uma lista a um livro em uma
biblioteca física, caso as obras não estejam organizadas (ordenadas) a procura pelo
livro poderá se tornar inviável, na estrutura de lista acontece a mesma coisa, em caso
de lista com vários elementos, poderá acontecer um processamento e tempo de con-
sumo desnecessário.
Nesta aula vamos estudar sobre as listas ordenadas e circulares, as circulares fa-
zem com que podemos navegar pelas listas indo para frente ou para trás, sem proble-
mas, todos os elementos poderão ser acessados.

FACULDADE CATÓLICA PAULISTA | 90


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

7.1 Listas Ordenadas

Compreendemos que ao se utilizar a lista duplamente encadeada temos uma maior


flexibilidade ao lidar com os elementos armazenados, entretanto temos uma situação
visto que os elementos poderão ser inseridos fora de ordem, por estarem fora de or-
dem não de inserção no vetor, mas sim os dados armazenados em si. O fato de es-
tarem fora de ordem, gera um consumo mais elevado dos recursos computacionais.
Tanto na lista encadeada simples quanto na dupla, encontramos a mesma situação,
uma solução para isso é a ordenação dos elementos no vetor, apenas temos que ob-
servar uma situação, em caso de múltiplos elementos armazenados no nó, teríamos
que escolher um destes para fazer a ordenação, exemplo: caso seja armazenado no
nó o nome e idade, devemos escolher um dos dois elementos para fazer a ordenação.
A ordenação da lista faz sentido se pensarmos que temos que percorrer toda ou
parte dela para encontrar um elemento. Podemos ordenar a lista de modo crescente
ou decrescente, alfabética de A - Z ou Z - A, dependendo do tipo de aplicação, assim,
gerando agilidade no retorno dos resultados.

Lista duplamente ordenada


Fonte: elaborado pelo autor

Com a lista ordenada, o sistema pode encontrar mais fácil os elementos utilizando
menos recursos, perceba, caro(a) aluno(a), que o apontamento de próximo e anterior
se permanecem da mesma forma, mas por estarem próximos no vetor isso diminui
processamento, outro aspecto é que caso estivermos procurando o elemento X3 este
está mais próximo no vetor. Vejamos alguns exemplos de ordenação de listas, utilizan-
do elementos numéricos e caracteres.

FACULDADE CATÓLICA PAULISTA | 91


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Exemplo de lista com elementos numéricos:

Lista de elementos numéricos ordenados


Fonte: elaborado pelo autor

Lista com caracteres


Fonte: elaborado pelo autor

A ordenação dos elementos pode acontecer no momento da inserção dos dados


ou após o preenchimento do mesmo, vejamos a seguir a implementação de uma lista
encadeada simples com a opção de ordenação dos elementos.

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

FACULDADE CATÓLICA PAULISTA | 92


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

typedef struct LISTA{


int dado;
struct LISTA *prox;
}lista;

lista *inserirElemento(lista *p, int valor){


lista *novo;
novo=(lista*)malloc(sizeof(lista));
novo->dado = valor;
novo->prox = p;
return novo;
}

void mostrarLista(lista *p){


lista *novo;
for(novo = p; novo!= NULL; novo=novo->prox){
printf(“%d - “,novo->dado);
}
}
lista *ordenarLista(lista *p) {

lista *aux = p;
lista *t;
int c;

if (p == NULL || p->prox == NULL)


return NULL;

while (aux != NULL) {


t = aux->prox;
while (t != NULL) {
if (aux->dado > t->dado) {
c = aux->dado;
aux->dado = t->dado;
t->dado = c;
}
t = t->prox;
}
aux = aux->prox;
}
return p;
}
main(){
setlocale(LC_ALL, “”);

FACULDADE CATÓLICA PAULISTA | 93


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

int op = -1, valor;


lista *l,i;
lista *primeiro, *ultimo;
l = NULL;

while (op != 0) {
printf(“\nOpções do Menu:\n”);
printf(“\t1 - Inserir novo elemento na lista.\n”);
printf(“\t2 - Mostrar lista.\n”);
printf(“\t3 - Ordenar lista.\n”);
printf(“\t0 - Sair do programa.\n”);

printf(“Digite a opção desejada: “);
scanf(“%d”, &op);

switch(op) {
case 0: printf(“\n\nSair do sistema\n”); break;
case 1:{ printf(“\nInforme uma valor a ser inserido na lista:
“);
scanf(“%d”, &valor);
l = inserirElemento(l,valor); system(“cls”); break;}
case 2:{ system(“cls”); mostrarLista(l); break;}
case 3:{ system(“cls”); l = ordenarLista(l); mostrarLista(l);
break;}
default: printf(“\n\nOpção invalida !\n”);
}
}
}
Implementação em linguagem C da lista encadeada simples com ordenação
Fonte: adaptado pelo autor

No código fonte apresentado é possível inserir os valores e ordena a lista a qualquer


momento, inclusive é possível inserir alguns elementos iniciais para fazer a ordena-
ção, continuar incluído mais valores e requisitar a ordenação novamente. A função
ordenarLista() é responsável pela ordenação, onde é analisado cada valor incluído na
lista comparando com os demais para verificar a sua ordem correta.

7.2 Listas Circulares

As listas circulares foram pensadas para que a leitura chegue ao fim e possa retor-
nar ao início sem que seja necessário realizar diversas iterações, uma possibilidade

FACULDADE CATÓLICA PAULISTA | 94


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

também seria incluir no nó inicial a informação que o nó anterior seria o último. Va-
mos pensar que você está procurando um valor número em uma lista duplamente
encadeada e ordenada, este valor seria um elemento com um valor alto 150, seria
mais interessante iniciar a busca de modo a contrário. O método de lista circular pode
ser aplicado em qualquer conceito estudado até o momento, listas simples, duplas e
ordenadas.

Ao aplicar a busca em uma lista simples ou dupla ordenada, as interações partem


do ponteiro na posição inicial e vão até o último, antes a leitura se encerrava ou efetu-
ava a busca inversa, no caso da lista duplamente ordenada, aplicando o conceito de
listas circulares, o ponteiro do último elemento informa que o próximo elemento é o
início da lista.

Lista duplamente ordenada circular


Fonte: elaborado pelo autor

Vemos como é percorrida a lista ao ser iniciada pelo elemento que está arma-
zenado no X1:

Indicação do Elemento Elemento Atual Indicação do Próximo


Anterior Elemento
X5 Posição 4 do vetor X1 X2
X1 X2 X3
X2 X3 X4
X3 X4 X5
X4 X5 X1 Posição 0 do vetor
Fonte: elaborado pelo autor

Perceba, caro(a) aluno(a), que se estivermos no elemento X5 podemos retornar


para o elemento X4, ou podemos ir para o X1 início de nossa lista, mas mantemos
a ideia de que não podemos pular nós na lista, se desejarmos ir para o elemento X2
FACULDADE CATÓLICA PAULISTA | 95
ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

temos que percorrer todos os demais elementos até chegar no nosso destino, sendo
também possível ir para frente ou para trás a qualquer momento.

Dessa forma, é possível visitar todos os elementos a partir do ponteiro inicial até
alcançá-lo novamente ou a partir do primeiro elemento facilmente chegar no último
elemento iniciando uma busca inversa. A lista circular só retorna para o início atra-
vés do último elemento, para isso, é preciso percorrê-la por completo. Por padrão, o
elemento inicial possui o ponteiro que irá identificar o próximo elemento, mas o que
identifica o elemento anterior irá identificar-se como NULL, mas como dito isso pode
ser modificado.

FACULDADE CATÓLICA PAULISTA | 96


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 8
LISTAS DINÂMICAS

Fonte: https://br.freepik.com/fotos-gratis/vista-superior-azul-e-amarelo-ganchos_8002927.htm

Olá prezado(a) aluno(a), em nossas aulas anteriores foi nos oportunizado falar so-
bre as características das estruturas de listas lineares, estas como a encadeada sim-
ples, dupla, circular ou ordenada. Um detalhe muito importante que devemos desta-
car é que o modo de inclusão ou remoção de elementos pode acontecer a qualquer
momento, ou seja, a inclusão de elementos pode acontecer no início, meio ou final da
lista, mesmo estando ordenada ou não.
Nesta aula veremos as propriedades sobre inclusão e remoção de elementos em
uma lista, como também ao final vamos analisar um algoritmo completo em lingua-
gem C contendo as funcionalidades em uma lista.

8.1 Inclusão de dados em listas

A inserção de um novo elemento em uma lista poderá acontecer a qualquer mo-


mento, inclusive podendo ser uma simples ou dupla temos que ter um ponto de aten-

FACULDADE CATÓLICA PAULISTA | 97


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

ção em casos de listas ordenadas.


Em uma lista sem ordenação, o elemento poderá ser inserido no final do vetor ou
no início, dependendo de como está feita a implementação do código. Em exemplos
de código anteriores vimos estas duas variações, o que vale lembrar é que, ao incluir
no final da lista identificamos apenas o elemento anterior (em caso de uma lista dupla-
mente encadeada), mas se for no início devemos modificar todos os nós a frente, por
isso o indicação é a inclusão no final, isso não alterar nada no processo de ordenação
da lista.

Inclusão de elemento em uma lista não ordenada


Fonte: Adaptado pelo autor

Em casos de uma lista ordenada, antes de efetuar a inclusão do elemento é efetua-


da uma leitura para identificar a posição correta, a lista pode estar ordenada de forma
crescente ou decrescente, no momento de efetuar a inclusão os elementos adjacen-
tes ao novo elemento também poderão sofrer modificações, visto que se for uma lista
dupla temos que identificar os ponteiros de próximo e anterior.

Inclusão de elemento em uma lista duplamente or denada


Fonte: Adaptado pelo autor

FACULDADE CATÓLICA PAULISTA | 98


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Conforme informado, caso a inclusão seja em uma lista ordenada, antes da inclu-
são, é efetuada uma leitura para encontrar o local onde será inserido o elemento na
ordem correta. Para compreendermos melhor vejamos a simulação da inclusão do
número 23, o qual irá ocupar uma nova posição no vetor.

Posição no vetor Pont. Anterior Elemento Pont. Próximo


0 NULL 8 Posição 1 do vetor
1 Posição 0 do vetor 15 Posição 2 do vetor
2 Posição 1 do vetor 67 Posição 3 do vetor
3 Posição 2 do vetor 75 Posição 4 do vetor
4 Posição 3 do vetor 95 NULL
Lista encadeada dupla ordenada, sem a inclusão do número 23.
Fonte: elaborado pelo autor

Posição no vetor Pont. Anterior Elemento Pont. Próximo


0 NULL 8 Posição 1 do vetor
1 Posição 0 do vetor 15 Posição 2 do vetor
2 Posição 1 do vetor 23 Posição 3 do vetor
3 Posição 2 do vetor 67 Posição 4 do vetor
4 Posição 3 do vetor 75 Posição 5 do vetor
5 Posição 4 do vetor 95 NULL
Lista encadeada dupla ordenada, com a inclusão do número 23.
Fonte: elaborado pelo autor

O que devemos observar é que com a inclusão do valor 23 em uma lista ordenada,
as informações contidas no vetor (nó) 1 para traz não sofrem modificações, já do
vetor (nó) 2 em diante sim, agora o vetor 2 recebe as informações dos novos valores,
isso faz com que o valor dos demais vetores sejam alterados, recebendo um novo ele-
mento assim e ao final criando uma nova posição para a inclusão do último elemento.
O procedimento de inclusão de valores ou dados no meio de uma lista é um pouco
completo, mesmo que isso seja perdido, o indicado é incluir no final e depois fazer o
processo de ordenação.

FACULDADE CATÓLICA PAULISTA | 99


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

8.2 Remoção de dados em listas

A remoção de qualquer elemento da lista poderá acontecer a qualquer momento na


execução do programa, o processo de exclusão de um elemento acontece da mesma
forma da inclusão, a diferença está na posição do elemento no vetor, caso este estiver
no final o processo é simples, sendo apenas removido o nó final da lista, assim a lista
não sofre nenhum tipo de movimentação no vetor, caso o elemento esteja no início ou
no meio do vetor, haverá movimentos na lista.

Vamos utilizar como exemplo a lista apresentada anteriormente:

Posição no vetor Pont. Anterior Elemento Pont. Próximo


0 NULL 8 Posição 1 do vetor
1 Posição 0 do vetor 15 Posição 2 do vetor
2 Posição 1 do vetor 23 Posição 3 do vetor
3 Posição 2 do vetor 67 Posição 4 do vetor
4 Posição 3 do vetor 75 Posição 5 do vetor
5 Posição 4 do vetor 95 NULL
Lista encadeada dupla ordenada.
Fonte: elaborado pelo autor

Vamos imaginar que desejamos remover o número 95, o procedimento é simples.


Iniciando por uma busca no vetor e encontrando o elemento de exclusão, após isso
basta excluir o nó do vetor e editar o elemento anterior, sendo que o apontamento do
próximo nó seja NULL.

Posição no vetor Pont. Anterior Elemento Pont. Próximo


0 NULL 8 Posição 1 do vetor
1 Posição 0 do vetor 15 Posição 2 do vetor
2 Posição 1 do vetor 23 Posição 3 do vetor
3 Posição 2 do vetor 67 Posição 4 do vetor
4 Posição 3 do vetor 75 NULL

Lista encadeada dupla ordenada, exclusão número 95.


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 100


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Agora caso desejássemos excluir o número 67, teríamos que fazer uma movimen-
tação maior no vetor, pois temos que fazer as modificações em seus nós adjacentes.

Posição no vetor Pont. Anterior Elemento Pont. Próximo


0 NULL 8 Posição 1 do vetor
1 Posição 0 do vetor 15 Posição 2 do vetor
2 Posição 1 do vetor 23 Posição 3 do vetor
3 Posição 2 do vetor 75 Posição 4 do vetor
4 Posição 3 do vetor 95 NULL
Lista encadeada dupla ordenada, exclusão do número 67.
Fonte: elaborado pelo autor

Com a exclusão do elemento 67, os valores que estavam abaixo do mesmo não
sofrem modificações, entretanto os que tinham seus valores acima sim, pois além
de ocuparem uma nova posição as informações de anterior e próximo também são
modificados.
A exclusão de elementos é comum e muito útil, em um primeiro momento parece
ser trabalhoso, mas com o algoritmo certo isso se torna um processo fácil, por isso
em nosso último tópico desta aula vamos ver a implementação das funcionalidades
completas em uma lista.
8.3 Implementação de listas em linguagem C

Após compreendermos como funcionam as listas e suas particularidades, além de


vermos também como pode-se inserir e remover conteúdo de uma lista, vejamos a
seguir um exemplo de código fonte em linguagem C, contemplando as mais variadas
funcionalidades ao trabalharmos com estruturas de listas.

#include <stdio.h>
#include <stdlib.h>
struct Node{
int num;
struct Node *prox;
};
typedef struct Node node;
int tam;

FACULDADE CATÓLICA PAULISTA | 101


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

void inicia(node *LISTA);


int menu(void);
void opcao(node *LISTA, int op);
node *criaNo();
void insereFim(node *LISTA);
void insereInicio(node *LISTA);
void exibe(node *LISTA);
void libera(node *LISTA);
void insere (node *LISTA);
node *retiraInicio(node *LISTA);
node *retiraFim(node *LISTA);
node *retira(node *LISTA);
int main(void)
{
node *LISTA = (node *) malloc(sizeof(node));
if(!LISTA){
printf(“Sem memoria disponivel!\n”);
exit(1);
}else{
inicia(LISTA);
int opt;
do{
opt=menu();
opcao(LISTA,opt);
}while(opt);
free(LISTA);
return 0;
}
}
void inicia(node *LISTA)
{
LISTA->prox = NULL;
tam=0;
}
int menu(void)
{
int opt;
printf(“Escolha a opcao\n”);
printf(“0. Sair\n”);
printf(“1. Zerar lista\n”);
printf(“2. Exibir lista\n”);
printf(“3. Adicionar node no inicio\n”);
printf(“4. Adicionar node no final\n”);
printf(“5. Escolher onde inserir\n”);

FACULDADE CATÓLICA PAULISTA | 102


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

printf(“6. Retirar do inicio\n”);


printf(“7. Retirar do fim\n”);
printf(“8. Escolher de onde tirar\n”);
printf(“Opcao: “); scanf(“%d”, &opt);
return opt;
}
void opcao(node *LISTA, int op)
{
node *tmp;
switch(op){
case 0:
libera(LISTA);
break;
case 1:
libera(LISTA);
inicia(LISTA);
break;
case 2:
exibe(LISTA);
break;
case 3:
insereInicio(LISTA);
break;
case 4:
insereFim(LISTA);
break;
case 5:
insere(LISTA);
break;
case 6:
tmp= retiraInicio(LISTA);
printf(“Retirado: %3d\n\n”, tmp->num);
break;
case 7:
tmp= retiraFim(LISTA);
printf(“Retirado: %3d\n\n”, tmp->num);
break;
case 8:
tmp= retira(LISTA);
printf(“Retirado: %3d\n\n”, tmp->num);
break;
default:
printf(“Comando invalido\n\n”);
}
}

FACULDADE CATÓLICA PAULISTA | 103


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

int vazia(node *LISTA)


{
if(LISTA->prox == NULL)
return 1;
else
return 0;
}
node *aloca()
{
node *novo=(node *) malloc(sizeof(node));
if(!novo){
printf(“Sem memoria disponivel!\n”);
exit(1);
}else{
printf(“Novo elemento: “); scanf(“%d”, &novo->num);
return novo;
}
}
void insereFim(node *LISTA)
{
node *novo=aloca();
novo->prox = NULL;
if(vazia(LISTA))
LISTA->prox=novo;
else{
node *tmp = LISTA->prox;
while(tmp->prox != NULL)
tmp = tmp->prox;
tmp->prox = novo;
}
tam++;
}
void insereInicio(node *LISTA)
{
node *novo=aloca();
node *oldHead = LISTA->prox;
LISTA->prox = novo;
novo->prox = oldHead;
tam++;
}
void exibe(node *LISTA)
{
system(“cls”);
if(vazia(LISTA)){

FACULDADE CATÓLICA PAULISTA | 104


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

printf(“Lista vazia!\n\n”);
return ;
}
node *tmp;
tmp = LISTA->prox;
printf(“Lista:”);
while( tmp != NULL){
printf(“%5d”, tmp->num);
tmp = tmp->prox;
}
printf(“\n “);
int count;
for(count=0 ; count < tam ; count++)
printf(“ ^ “);
printf(“\nOrdem:”);
for(count=0 ; count < tam ; count++)
printf(“%5d”, count+1);
printf(“\n\n”);
}
void libera(node *LISTA)
{
if(!vazia(LISTA)){
node *proxNode,
*atual;
atual = LISTA->prox;
while(atual != NULL){
proxNode = atual->prox;
free(atual);
atual = proxNode;
}
}
}
void insere(node *LISTA)
{
int pos,
count;
printf(“Em que posicao, [de 1 ate %d] voce deseja inserir: “, tam);
scanf(“%d”, &pos);
if(pos>0 && pos <= tam){
if(pos==1)
insereInicio(LISTA);
else{
node *atual = LISTA->prox,
*anterior=LISTA;

FACULDADE CATÓLICA PAULISTA | 105


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

node *novo=aloca();
for(count=1 ; count < pos ; count++){
anterior=atual;
atual=atual->prox;
}
anterior->prox=novo;
novo->prox = atual;
tam++;
}
}else
printf(“Elemento invalido\n\n”);
}
node *retiraInicio(node *LISTA)
{
if(LISTA->prox == NULL){
printf(“Lista ja esta vazia\n”);
return NULL;
}else{
node *tmp = LISTA->prox;
LISTA->prox = tmp->prox;
tam--;
return tmp;
}
}
node *retiraFim(node *LISTA)
{
if(LISTA->prox == NULL){
printf(“Lista ja vazia\n\n”);
return NULL;
}else{
node *ultimo = LISTA->prox,
*penultimo = LISTA;
while(ultimo->prox != NULL){
penultimo = ultimo;
ultimo = ultimo->prox;
}
penultimo->prox = NULL;
tam--;
return ultimo;
}
}
node *retira(node *LISTA)
{
int opt,

FACULDADE CATÓLICA PAULISTA | 106


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

count;
printf(“Que posicao, [de 1 ate %d] voce deseja retirar: “, tam);
scanf(“%d”, &opt);
if(opt>0 && opt <= tam){
if(opt==1)
return retiraInicio(LISTA);
else{
node *atual = LISTA->prox,
*anterior=LISTA;
for(count=1 ; count < opt ; count++){
anterior=atual;
atual=atual->prox;
}
anterior->prox=atual->prox;
tam--;
return atual;
}
}else{
printf(“Elemento invalido\n\n”);
return NULL;
}
}
COMO fazer uma lista em C -Implementação completa (inserindo e retirando nós de qualquer posição). C progressivo
Fonte: https://www.cprogressivo.net/2013/10/Como-fazer-uma-lista-em-C.html

FACULDADE CATÓLICA PAULISTA | 107


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 9
ESTRUTURAS DE
PILHAS E FILAS

Fonte: https://pixabay.com/pt/photos/livros-pilha-biblioteca-estantes-768426/

As estruturas de dados pilha e fila são consideradas com lista lineares, mas com
características próprias. Podemos abstrair o entendimento sobre a estrutura de uma
pilha como se fosse uma pilha de livros, um em cima do outro, mas se pegarmos os
mesmo livros e colocarmos todos um a frente do outro temos uma estrutura de lista.
As funções básicas de vistas em listas como incluir elementos, remover elementos
ou buscar estão presentes nessa estrutura. O que irá diferenciar essas listas das que
já vimos até o momento é o seu modo de manutenção, pois cada uma possui uma
característica própria.
Essas estruturas são muito utilizadas na busca de dados em uma árvore ou em um
grafo, assuntos estes que vamos estudar em aulas mais a frente, utilizamos o concei-
to de busca em largura e em profundidade associado a estrutura de um lista e pilha.

FACULDADE CATÓLICA PAULISTA | 108


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

ANOTE ISSO

A busca em profundidade se utiliza de uma pilha e se inicia pelo nó raiz e desce pela
árvore até o último nível ou até encontrar uma folha, após isso, volta na estrutura da
árvore e vai visitando os demais nós até efetuar a busca completa.
A busca em largura se utiliza de uma fila e também se inicia pelo nó raiz e desce
para o próximo nó adjacente, a diferença é que olha todos os filhos do nó antes de
descer na árvore.

9.1 Filas

Fonte: https://br.freepik.com/vetores-gratis/fila-de-pessoas-em-pe-para-usar-atm_7416575.htm

Em nosso cotidiano enfrentamos diversas filas como em mercados, bancos, estra-


das, dentre outras situações. O conceito da estrutura de fila no mundo computacional
segue a mesma ideia de uma fila convencional, em que ao chegar em algum local
somos posicionados de modo linear, esperamos para ser atendidos e, conforme a fila
anda com o atendimento ou deslocamento dos primeiros, vamos caminhando. Segun-
do Pulga e Rissetti (2009, p. 219):
Conceito é conhecido como first in, first out ou FIFO, expressão
conhecida em português como PEPS ou “primeiro que entra, primeiro
que sai”. Então, no conceito de fila, os elementos são atendidos, ou
utilizados, sequencialmente na ordem em que são armazenados. As
filas (queues) são conjuntos de elementos (as listas) cujas operações
de inserção são feitas por extremidade, e as de remoção, por outra.

FACULDADE CATÓLICA PAULISTA | 109


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Como exemplo pode-se utilizar o conceito da fila de acesso a um caixa eletrônico


de um banco, onde as primeiras pessoas que chegam vão utilizar, conforme as primei-
ras pessoas vão utilizando e saindo da fila novas pessoas assumem o seu lugar de
primeiro, ao mesmo tempo, mais pessoas vão chegando e posicionado ao final.

Conceito de FIFO
Fonte: Adaptado pelo autor

Em uma lista linear, algumas das regras que devem ser seguidas nesse conceito de
FIFO são:
Os novos elementos sempre entram por último, no final da fila, mesmo se
essa estiver ordenada.
O elemento que é lido será o primeiro que entrou ou o que ocupa a primeira
posição.
O tempo de espera na lista depende do programa em execução.
A lista pode ficar vazia.

O sentido da leitura poderá variar com base no programa implementando, sendo o


Início a esquerda ou direita, mas o processo de inclusão de elementos sempre será o
mesmo.

FACULDADE CATÓLICA PAULISTA | 110


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Exemplo de uma FILA em execução


Fonte: Adaptado pelo autor

Prezado(a) aluno(a), agora que você sabe como funciona uma fila de modo teórico,
vejamos um código no qual foi implementado esse conceito, trata-se da Implementa-
ção da Estrutura FILA em linguagem C. Devemos lembrar que para estrutura de FILA
tem como base uma lista encadeada simples.

//FIFO
//Bibliotecas utilizadas
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <locale.h>

//Se o sistema for Windows adiciona determinada biblioteca, e definindo co-


mandos de limpar e esperar
#ifdef WIN32
#include <windows.h>
#define LIMPA_TELA system(“cls”)
//Senão for Windows (se for Linux)
#else

FACULDADE CATÓLICA PAULISTA | 111


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#include <unistd.h>
#define LIMPA_TELA system(“/usr/bin/clear”)
#endif

//Espera 3 segundos
#define ESPERA sleep(3)

//Estrutura da lista que será criada


typedef struct Fila {
int valor;
struct Fila *proximo;
} Dados;

void insere();
void exclui();
void mostra();
void mostra_erro();

//Inicializando os dados da lista


Dados *principal = NULL;
Dados *final = NULL;

main(){
setlocale(LC_ALL, “”); // ajuste do idioma
char escolha;
//Laço que irá mostrar o menu esperando uma opção (char)
do {
//Limpando a tela, e mostrando o menu
LIMPA_TELA;
printf(“\nMétodo Fila\n\n”);
printf(“Escolha uma opção: \n”);
printf(“\t1 - Inserir valor na Fila\n”);
printf(“\t2 - Remover valor da Fila\n”);
printf(“\t3 - Mostrar valores da Fila\n”);
printf(“\t9 - Sair\n\n”);
printf(“Resposta: “);
scanf(“%c”, &escolha);
switch(escolha) {
//Inserindo
case ‘1’:
insere();
break;
//Excluindo
case ‘2’:

FACULDADE CATÓLICA PAULISTA | 112


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

if(principal!=NULL){
exclui();
}
else{
printf(“\nA Fila está vazia!\n”);
getchar();
}
break;
//Mostrando
case ‘3’:
if(principal!=NULL){
mostra();
}
else{
printf(“\nA Fila está vazia!\n”);
getchar();
}
break;
case ‘9’:
printf(“\nObrigado por utilizar esse programa!\n”);
printf(“------>Terminal de Informação<------\n\n”);
ESPERA;
exit(0);
break;
//Se foi algum valor inválido
default:
mostra_erro();
break;
}
//Impedindo sujeira na gravação da escolha
getchar();
}
while (escolha > 0); //Loop Infinito
}

//Inserção
void insere(){
int val;
LIMPA_TELA;
printf(“\nInserção: \n”);
printf(“--------------------------------------\n”);
printf(“Insira o valor a ser inserido: “);
scanf(“%d”,&val);
Dados *atual = (Dados*)malloc(sizeof(Dados));

FACULDADE CATÓLICA PAULISTA | 113


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

atual -> valor = val;


atual -> proximo = NULL;

//se o principal estiver vazio, será o atual


if(principal == NULL){
principal = final = atual;
}
//senão, o próximo valor que será o atual
else{
final->proximo=atual;
final=atual;
}

printf(“\nValor inserido!\n”);
printf(“--------------------------------------”);
getchar();
}

//Exclusão
void exclui(){
Dados *auxiliar;
printf(“\nExclusão: \n”);
printf(“--------------------------------------\n”);
//o auxiliar será o próximo da principal
auxiliar=principal->proximo;
//limpando a principal
free(principal);
//a principal será a auxiliar
principal=auxiliar;
printf(“\nValor excluido!\n”);
printf(“--------------------------------------”);
getchar();
}

//Mostrando
void mostra(){
int posicao=0;
Dados *nova=principal;
LIMPA_TELA;
printf(“\nMostrando valores: \n”);
printf(“--------------------------------------\n”);
//laço de repetição para mostrar os valores
for (; nova != NULL; nova = nova->proximo) {
posicao++;

FACULDADE CATÓLICA PAULISTA | 114


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

printf(“Posição %d, contém o valor %d\n”, posicao, nova->valor);


}
printf(“--------------------------------------”);
getchar();
}

//Mostrando erro de digitação


void mostra_erro(){
LIMPA_TELA;
printf(“\nErro de Digitação: \n”);
printf(“--------------------------------------\n”);
printf(“\nDigite uma opção válida (pressione -Enter- p/ continuar)!\n\n”);
printf(“--------------------------------------”);
getchar();
}

Fonte: https://terminaldeinformacao.com/2013/07/23/entendendo-pilha-e-fila/

Menu do Programa em execução


Fonte: elaborado pelo autor

Mostrando a fila após a inclusão dos valores 3 - 6 - 25


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 115


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Um ponto de observação é que a estrutura de fila não faz a inclusão ordenada, ou


seja, não importa os valores ou a estrutura que está contida no nó da fila, quando se é
feito a inclusão sempre será do final e a remoção sempre do início.

9.2 Pilhas

Fonte: https://br.freepik.com/fotos-gratis/pilha-de-varios-livros-sobre-uma-mesa_991451.htm

Como apresentado na estrutura de filas, em nosso cotidiano também nos depara-


mos com vários tipos de pilhas, como a pilha de pratos no armário, pilha de roupas,
com uma pilha de sacos de arroz no mercado ou até mesmo uma pilha de livros. Uma
estrutura em pilha é uma das mais simples no ambiente computacional e segue os
mesmos princípios de uma pilha no mundo real, ou seja, os elementos seguem o prin-
cípio do empilhar.
As pilhas são estruturas de dados conhecidas como lista LIFO (Last
In, First Out); em português, significa que o último elemento a entrar
é o primeiro a sair UEPS. Trata-se de uma lista linear em que todas as
operações de inserção e remoção são feitas por um único extremo,
denominado topo (PUGA; RISSETTI, 2016, p.186)

Como exemplo, pode-se utilizar o conceito de uma pilha de sacos de arroz em uma

FACULDADE CATÓLICA PAULISTA | 116


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

prateleira de supermercado, onde estes são empilhados, conforme cada cliente retira
um pacote a pilha diminui, os pacotes são retirados sempre do topo da pilha, quando
alguém for abastecer (incluir) mais pacotes de arroz, estes serão empilhados um em
cima do outro no topo.

Conceito da estrutura de pilha


Fonte: adaptado pelo autor

A implementação do conceito de pilha na computação também seria uma lista li-


near, ou seja, a sua representação não seria visualmente igual a uma pilha no aspecto
vertical, sendo desenvolvida na horizontal com o uso de vetores, mas seguindo os
respectivos pontos:
Os novos elementos sempre entram por último, no final da pilha, mesmo se a
essa estiver ordenada.
O elemento que é lido será o último inserido ou próximo da pilha.
O tempo de espera na pilha depende do programa em execução.
A pilha pode ficar vazia.

Como em filas o sentido da leitura poderá variar com base no programa implemen-
tando, sendo o Início a esquerda ou direita, mas o processo de inclusão de elementos
sempre será o mesmo.

FACULDADE CATÓLICA PAULISTA | 117


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Exemplo de uma PILHA em execução


Fonte: Adaptado pelo autor

Prezado(a) aluno(a), agora que você sabe como funciona uma pilha de modo teó-
rico, vejamos um código no qual foi implementado esse conceito, trata-se da Imple-
mentação da Estrutura PILHA em linguagem C. Devemos lembrar que para estrutura
de PILHA tem como base uma lista encadeada simples.

//LIFO
//Bibliotecas utilizadas
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <locale.h>

//Se o sistema for Windows adiciona determinada biblioteca, e definindo co-


mandos de limpar e esperar
#ifdef WIN32
#include <windows.h>
#define LIMPA_TELA system(“cls”)
//Senão for Windows (se for Linux)
#else
#include <unistd.h>

FACULDADE CATÓLICA PAULISTA | 118


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#define LIMPA_TELA system(“/usr/bin/clear”)


#endif

//Espera 3 segundos
#define ESPERA sleep(3)

//Estrutura da lista que será criada


typedef struct pilha {
int valor;
struct pilha *proximo;
} Dados;

void insere();
void exclui();
void mostra();
void mostra_erro();

//Inicializando os dados da lista


Dados *principal = NULL;

main(){
setlocale(LC_ALL, “”); // ajuste do idioma
char escolha;
//Laço que irá mostrar o menu esperando uma opção (char)
do {
//Limpando a tela, e mostrando o menu
LIMPA_TELA;
printf(“\nMétodo Pilha\n\n”);
printf(“Escolha uma opção: \n”);
printf(“\t1 - Inserir valor na Pilha\n”);
printf(“\t2 - Remover valor da Pilha\n”);
printf(“\t3 - Mostrar valores da Pilha\n”);
printf(“\t9 - Sair\n\n”);
printf(“Resposta: “);
scanf(“%c”, &escolha);
switch(escolha) {
//Inserindo
case ‘1’:
insere();
break;
//Excluindo
case ‘2’:
if(principal!=NULL){
exclui();

FACULDADE CATÓLICA PAULISTA | 119


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

}
else{
printf(“\nA Pilha está vazia!\n”);
getchar();
}
break;
//Mostrando
case ‘3’:
if(principal!=NULL){
mostra();
}
else{
printf(“\nA Pilha está vazia!\n”);
getchar();
}
break;
case ‘9’:
printf(“\nObrigado por utilizar esse programa!\n”);
printf(“------>Terminal de Informação<------\n\n”);
ESPERA;
exit(0);
break;
//Se foi algum valor inválido
default:
mostra_erro();
break;
}
//Impedindo sujeira na gravação da escolha
getchar();
}
while (escolha > 0); //Loop Infinito
}

//Inserção
void insere(){
int val;
LIMPA_TELA;
printf(“\nInserção: \n”);
printf(“--------------------------------------\n”);
printf(“Insira o valor a ser inserido: “);
scanf(“%d”,&val);
//gerando a posição atual
Dados *atual = (Dados*)malloc(sizeof(Dados));
atual -> valor = val;
//próximo do atual será a principal
atual -> proximo = principal;
//principal volta a ser a atual

FACULDADE CATÓLICA PAULISTA | 120


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

principal = atual;
printf(“\nValor inserido!\n”);
printf(“--------------------------------------”);
getchar();
}

//Exclusão
void exclui(){
Dados *auxiliar;
printf(“\nExclusão: \n”);
printf(“--------------------------------------\n”);
//guardando o valor depois da principal
auxiliar=principal->proximo;
//limpando a principal
free(principal);
//a principal será a auxiliar
principal=auxiliar;
printf(“\nValor excluido!\n”);
printf(“--------------------------------------”);
getchar();
}

//Mostrando
void mostra(){
int posicao=0;
Dados *nova=principal;
LIMPA_TELA;
printf(“\nMostrando valores: \n”);
printf(“--------------------------------------\n”);
//laço de repetição para mostrar os dados
for (; nova != NULL; nova = nova->proximo) {
posicao++;
printf(“Posição %d, contém o valor %d\n”, posicao, nova->valor);
}
printf(“--------------------------------------”);
getchar();
}
//Mostra erro de digitação
void mostra_erro(){
LIMPA_TELA;
printf(“\nErro de Digitação: \n”);
printf(“--------------------------------------\n”);
printf(“\nDigite uma opção válida (pressione -Enter- p/ continuar)!\n\n”);
printf(“--------------------------------------”);
getchar();
}
Fonte: https://terminaldeinformacao.com/2013/07/23/entendendo-pilha-e-fila/

FACULDADE CATÓLICA PAULISTA | 121


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Menu do Programa em execução


Fonte: elaborado pelo autor

Mostrando a pilha após a inclusão dos valores na respectiva ordem 36 - 65 - 2 - 14


Fonte: elaborado pelo autor

Mostrando a pilha após a exclusão de uma elemento


Fonte: elaborado pelo autor

Um ponto de observação é que a estrutura de pilha não faz a inclusão ordenada, ou


seja, não importa os valores ou a estrutura que está contida no nó da pilha, quando se
é feito a inclusão sempre será do final e a remoção sempre do final.

FACULDADE CATÓLICA PAULISTA | 122


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 10
ÁRVORES BINÁRIA E
ESTRITAMENTE BINÁRIA

Fonte: https://br.freepik.com/fotos-gratis/3d-rendem-de-uma-arvore-de-carvalho-na-paisagem-graminea-2701_1036771.htm

Olá prezado(a) aluno(a), você poderá estar se perguntando, como o conceito de


uma árvore do mundo real poderá estar sendo representada computacionalmente?
Pois bem, é simples uma a árvore no ambiente computacional tem algumas se-
melhanças com a do mundo real, quando estamos falando sobre nós raízes, galhos
e folhas. Uma estrutura de dados em árvore é utilizada por diversos sistemas e pro-
gramas para organização das informações armazenadas na memória secundária e
principal no momento de execução.
A vantagem de se utilizar essa estrutura está no fato de ela permitir acesso fácil
e rápido aos dados nas árvores, as quais são aplicadas de forma binária, conforme
veremos.

FACULDADE CATÓLICA PAULISTA | 123


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

10.1 Árvores Binária

Acredito eu que você já deve ter visto alguma árvore na sua vida :) Em um ambiente
computacional uma árvore é representada de modo visual bem parecido, inclusive
adota alguns termos usados em uma árvore do mundo real, a diferença está no for-
mato de implementação, visto que sua estrutura é aplicada de modo binário. Segundo
Tenenbaum (1995, p. 303):

Uma árvore binária é um conjunto finito de elementos que está vazio


ou é particionado em três subconjuntos. O primeiro subconjunto
contém um único elemento, chamado raiz da árvore. Os outros
dois subconjuntos são em si mesmos árvores binárias, chamadas
subárvores esquerda e direita da árvore original. Uma subárvore
esquerda ou direita pode estar vazia. Cada elemento de uma árvore
binária é chamado nó da árvore.

Podemos associar dizendo que o nó raiz, o primeiro elemento da árvore binária


seria a base da árvore, cada ponto de ligação entre os nós poderíamos dizer que são
galhos e por fim as extremidades as folhas dos galhos. Uma árvore binária é carac-
terizada pela composição de uma raiz e 2 subárvores (direita e esquerda), podemos
também chamar a raiz de pai, e cada subárvore, de filho à esquerda e filho à direita.

Uma árvore binária tem no máximo 2 filhos a partir do pai, outra característica im-
portante é que a árvore binária computacional é vista e montada de ponta-cabeça
se comparado com uma árvore normal, ou seja, a raiz fica na extremidade superior e
seus galhos e folhas são expostos de cima para baixo, conforme a imagem a seguir:

Exemplo de árvore binária


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 124


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Na imagem apresentada, podemos observar que a raiz se inicia no nó A e se subdi-


vide para baixo para os demais nós. As letras A, B, C, D, E, F, G, H e I são considerados
nós, lembrando que um nó pai deverá conter pelo menos um filho a esquerda ou direi-
ta, neste caso, os elementos B, C, E e F são considerados nós PAI. O nó que não pos-
sui um filho é considerado vazio, sendo chamado de folha da árvore, nesse caso, os
elementos D, G, H e I são folhas da árvore apresentada. O nó A poderá ser considerado
como um nó pai, mas devemos lembrar que este por ser o primeiro é denominado
como RAIZ em vez de PAI.

Para identificar em qual nível (altura) da árvore se encontra é contada a quantidade


de vezes que se desce, os níveis se iniciam por 0 e é somado + 1 para cada nível que
se desce com base no nível anterior, não temos um limite de níveis:

Identificação do nível da árvore


Fonte: elaborado pelo autor

Podemos agora identificar qual o nível da árvore, seus nós e folhas e também quais
são os pais e seus filhos:

Descrição Elemento
Nós no nível 0 A
Nós no nível 1 B-C
Nós no nível 2 D-E-F
Nós no nível 3 G-H-I
Nó Raiz A
Nós Pai A-B-C-E-F
Nós Folhas D- G-H-I
Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 125


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Elemento PAI FILHO FILHO TIPO


ESQUERDA DIREITA
A - B C Raiz

B A D E No Pai
C A - F No Pai
D B - - Folha
E B G - No Pai
F C H I No Pai
G E - - Folha
H F - - Folha
I F - - Folha

Identificação dos níveis, nós e folhas


Fonte: elaborado pelo autor

Um ponto de atenção na representação é que o nó raiz A, também é considerado


um nós pai, pois tem dois filhos. Na implementação uma estrutura em árvore pode-
ria utilizar o conceito de listas lineares, onde será armazenado o nó pai (elemento
anterior), o valor do elemento e possíveis dois filhos a esquerda ou à direita (próximo
elemento). Veja agora uma implementação em linguagem C da construção de uma
árvore binária utilizando vetores.
Fonte: elaborado pelo autor

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
int arvore[21];
int i,j,aux;
int resp=0,troca,busca;
int menu (){
system(“cls”);
printf(“\n____________________________________________________________\n\n”);
printf(“\t\t|------------->MENU<-----------|”);
printf(“\n\t\t|______________________________|\n”);
printf(“\t\t| 1 - Inserir numeros |\n”);
printf(“\t\t| 2 - Exibir numeros inseridos |\n”);
printf(“\t\t| 3 - Exibir arvore binaria |\n”);
printf(“\t\t| 4 - Sair |”);

FACULDADE CATÓLICA PAULISTA | 126


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

printf(“\n\t\t|______________________________|\n”);
printf(“\t\t\n\t\t\t Digite sua opcao: \a”);
scanf(“%d”,&resp);
return resp;
}
void comandos(int resp){
if(resp==0){ resp = menu();}
switch(resp){
//insere numeros
case 1:
system(“cls”);
printf(“\n______________________________________________________\n\n”);
printf(“ -->>Informe os números a serem inseridos na arvore\n\n”);
for (i=0; i<15; i++){
printf(“\t\tPosicao %d : “,i+1);
scanf(“%d”,&arvore[i]);
//arvore[i]=rand()%100;
}
printf(“\n__________________________________________________________\n\n”);
comandos(0);
break;
case 2:
system(“cls”);
printf(“\n__________________________________________________\n\n”);
printf(“ -->>Elementos no vetor da arvore!\n\n”);
for (i=0; i<15; i++){
printf(“\n\t -->> POSICAO %d = %d”,i,arvore[i]);
}
printf(“\n______________________________________________________________\n\n”);
system(“pause”);
comandos(0);
break;
case 3:
system(“cls”);
printf(“\n___________________________________________________________\n\n”);
printf(“\n\n -->>ARVORE BINARIA!\n\n”);
printf(“ %d\n”,arvore[0]);
printf(“ / \\ \n”);
printf(“ / \\ \n”);
printf(“ / \\ \n”);
printf(“ / \\ \n”);
printf(“ / \\ \n”);
printf(“ / \\ \n”);
printf(“ / \\ \n”);

FACULDADE CATÓLICA PAULISTA | 127


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

printf(“ %d %d \n”,arvore[1],arvore[2]);
printf(“ / \\ / \\ \n”);
printf(“ / \\ / \\ \n”);
printf(“ / \\ / \\ \n”);
printf(“ %d %d %d %d \n”,arvore[3],arvore[4],arvore[5],arvore[6]);
printf(“ / \\ / \\ / \\ / \\ \n”);
printf(“ %d %d %d %d %d %d %d %d \n”,arvore[7], arvore[8],arvore[9],arvo-
re[10], arvore[11],arvore[12],arvore[13], arvore[14]);
printf(“\n___________________________________________________________\n\n”);
system(“pause”);
comandos(0);
break;
//finaliza
case 4:
resp = 0;
system(“cls”);
printf(“\n_________________________________________________\n”);
printf(“ -->> Ate Logo!”);
printf(“\n______________________________________________________\n\n\n”);
}
}
main(){
for (i = 0; i<21; i++){
arvore[i] = i;
}
comandos(0); }

Menu do programa em execução

FACULDADE CATÓLICA PAULISTA | 128


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Inclusão de 15 elementos

Exibindo a árvore binária

FACULDADE CATÓLICA PAULISTA | 129


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

10.2 Árvores Estritamente Binária

A principal característica da estrutura de uma árvore binária é que sempre vamos


ter um nó pai e pelo menos 1 filho (esquerda ou direita), mas devo ressaltar que um nó
Pai nunca terá mais que dois filhos.
Ao analisarmos uma árvore binária podemos nos deparar com uma estrutura de-
nominada como estritamente binária, visualmente, esta tem como base os mesmos
princípios da árvore binária comum, sendo composta por uma raiz, nós e folhas. Po-
rém, esta será totalmente binária, ao considerarmos a seguinte afirmação: é conside-
rada uma árvore estritamente binária se todos os nós que não são folhas possuírem
sempre duas subárvores, sendo a esquerda e a direita não vazias.

Vejamos um exemplo.

Exemplo de árvore estritamente binária


Fonte: Adaptado pelo autor

Podemos observar na imagem que todos os nós PAI têm dois filhos (esquerda ou
direita), exceto os nós folhas que não possuem filhos. Caso algum dos nós folha (C -
D - F - G) tivesse pelo menos 1 um filho, esta árvore já não seria estritamente binária.
Em uma árvore estritamente binária é possível encontrar a quantidade de nós uti-

FACULDADE CATÓLICA PAULISTA | 130


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

lizando a quantidade de folhas com a seguinte fórmula n = (2 * f) - 1, sendo que F é o


número de folhas da árvore. Vejamos a resolução da fórmula:

Sabemos que a nossa árvore possui 4 nós que são folhas C, D, F e G:


N=(2*4)-1

Após realizar a multiplicação:


N=8-1

Ao efetuarmos a subtração teremos o seguinte resultado:


N=7

Se analisarmos a nossa árvore binária, veremos que a quantidade de nós é exata-


mente 7: A, B, C, D, E, F e G. Esta resolução só é possível de executar em árvores com
sua estrutura estritamente binária. Também podemos calcular a quantidade de folhas
em uma árvore estritamente binária usando a mesma fórmula, aplicando um simples
ajuste:

Adicionando 1 em ambos os lados da igualdade: n +1 = (2* f ) −1+1


Efetuando-se o cálculo: n +1 = (2* f )
Dividindo ambos os lados da igualdade por 2: N+1 / 2 = 2* F /2
Efetuando-se o cálculo: N+1 / 2 = F
Vamos inverter os lados da igualdade para deixar a variável isolada à esquerda: F
= N+1 / 2
No caso da árvore estritamente binária apresentada, sabemos que possui 7 nós.
Colocando na fórmula: F = 7 +1 / 2
Realizando a soma e em seguida a divisão:F = 8 / 2
Sendo assim vamos ter como resultado: F = 4
A árvore possui exatamente 4 folhas: C, D, F e G.

FACULDADE CATÓLICA PAULISTA | 131


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 11
ÁRVORE BINÁRIA COMPLETA
E IMPLEMENTAÇÃO
EM LINGUAGEM C

Fonte: https://br.freepik.com/fotos-gratis/foto-de-grande-angular-de-uma-unica-arvore-crescendo-sob-um-ceu-nublado-durante-um-por-do-sol-cercado-por-
grama_11342065.htm

Olá, prezado(a) aluno(a)! Vimos na aula anterior o conceito sobre a estrutura de ár-
vores binárias, seus princípios básicos sobre os nós (pai) e seus nós adjacentes (filho
a esquerda ou direita). Também observamos a estrutura de uma árvore estritamente
binária e suas características.
Além da estrutura de uma árvore binária comum é estritamente binária podemos
ter a estrutura de uma árvore completa, conforme veremos a seguir.

FACULDADE CATÓLICA PAULISTA | 132


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

11.1 Árvore Binária Completa

A estrutura de uma árvore binária completa é extremamente parecida com uma


árvore estritamente binária, onde cada nó pai tem dois filhos ou o nó é folha, o critério
para considerar então esta árvore sendo completa é que no último nível temos apenas
nós folhas.

Devemos lembrar que o nó raiz de uma árvore binária está localizado no nível 0.
A partir do nó raiz temos os nós adjacentes, onde podemos dizer que estamos des-
cendo na estrutura, conforme vamos descendo os níveis vão aumentando um a um.
A altura de uma árvore corresponde a profundidade do nó raiz até o mais baixo, isso
equivale ao tamanho do percurso mais distante da raiz até uma folha.

Exemplo de árvore binária completa


Fonte: elaborado pelo autor

Podemos observar que no último nível temos apenas nós folhas, sendo os elemen-
tos H, I J, K, L, M, N e O, no nível superior temos todos nós PAI com todos dois filhos
(esquerda e direita) caracterizando uma árvore estritamente binária. Vale lembrar que
caso seja incluído qualquer outro elemento sendo filho de uma folha, esta árvore já
não se torna mais completa nem estritamente binária, sendo uma árvore comum.

11.2 Implementação em linguagem C

Podemos implementar a estrutura de uma árvore binária, em linguagem C pode-


mos utilizar de modo simples o conceito de vetores e listas lineares. Cada posição do
vetor será identificado como um nó, sendo armazenado pelo menos quatro valores:
pai, esquerda, direita e valor do elemento.

FACULDADE CATÓLICA PAULISTA | 133


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

O nosso primeiro passo é criar a estrutura de nós e as informações que serão ar-
mazenadas, como também fazer a declaração da estrutura como um vetor para ar-
mazenar as posições.

//Estrutura do nó
typedef struct str_no {
char dado;
int FilhoEsq;
int FilhoDir;
int pai;
} str_no;

struct str_no arvore[tamanho];


int indice=0;

Após criarmos a estrutura do nó, devemos criar a função que irá fazer a inclusão
dos dados do nó na árvore, sendo necessário informar quem é o seu pai, o valor a ser
armazenado e se ele é um filho esquerda ou direita, como também identificar se o nó
inserido é o raiz.

//Inserir nó
void InserirElemento(int pai, char dado, int lado){
switch (lado){
case E:
arvore[pai].FilhoEsq = indice;
arvore[indice].dado = dado;
arvore[indice].pai = pai;
arvore[indice].FilhoEsq = -1;
arvore[indice].FilhoDir = -1;
indice++;
break;
case D:
arvore[pai].FilhoDir = indice;
arvore[indice].dado = dado;
arvore[indice].pai = pai;
arvore[indice].FilhoEsq = -1;
arvore[indice].FilhoDir = -1;
indice++;
break;
case R:
arvore[indice].dado = dado;

FACULDADE CATÓLICA PAULISTA | 134


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

arvore[indice].pai = -1;
arvore[indice].FilhoEsq = -1;
arvore[indice].FilhoDir = -1;
indice++;
break;
}
}

//Inserir nó
void InserirElemento(int pai, char dado, int lado){
switch (lado){
case E:
arvore[pai].FilhoEsq = indice;
arvore[indice].dado = dado;
arvore[indice].pai = pai;
arvore[indice].FilhoEsq = -1;
arvore[indice].FilhoDir = -1;
indice++;
break;
case D:
arvore[pai].FilhoDir = indice;
arvore[indice].dado = dado;
arvore[indice].pai = pai;
arvore[indice].FilhoEsq = -1;
arvore[indice].FilhoDir = -1;
indice++;
break;
case R:
arvore[indice].dado = dado;
arvore[indice].pai = -1;
arvore[indice].FilhoEsq = -1;
arvore[indice].FilhoDir = -1;
indice++;
break;
}
}

Na estrutura apresentada devemos observar a variável chamada indice, está arma-


zena a próxima posição livre do vetor. O parâmetro pai que é passado na estruturação
da função indica qual a posição do nó pai. Caso seja um filho esquerdo o valor de
indice é atribuído na posição arvore[pai].FilhoEsq, caso for um filho a direta o valor de

FACULDADE CATÓLICA PAULISTA | 135


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

indice é atribuído na posição arvore[pai].FilhoDir, caso for um nó raiz não atribuímos


a informação de FilhoEsq ou FilhoDir.

Agora que já temos a estrutura do nó e a função de inclusão de elementos, vamos


criar uma nova função para efetuar a procura de elementos no vetor e retornar as in-
formações armazenadas na estrutura do nó.

//Procura nó
int ProcurarElemento(char dado){
int i;
if (indice != 0){
for (i = 0; i<indice; i++){
if (arvore[i].dado == dado) {
return (i);
}
}
}
else {
return (0);
}
}

Agora que já temos os elementos básicos necessários para a implementação, ve-


jamos o código completo trazendo as declarações de bibliotecas, constantes e variá-
veis, funções, dentre outras funcionalidades.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>

//Estrutura do nó
typedef struct str_no {
char dado;
int FilhoEsq;
int FilhoDir;
int pai;
} str_no;

FACULDADE CATÓLICA PAULISTA | 136


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

//Constantes
#define tamanho 100
#define E 0
#define D 1
#define R -1

//Variáveis
struct str_no arvore[tamanho];
int lado,indice=0;
int opt=-1;
char pai, no;

//Protítipos das funções


void InserirElemento(int pai, char dado, int lado);
int ProcurarElemento(char dado);
void menu_mostrar(void);

//Procura nó
int ProcurarElemento(char dado){
int i;
if (indice != 0){
for (i = 0; i<indice; i++){
if (arvore[i].dado == dado) {
return (i);
}
}
}
else {
return (0);
}
}

//Inserir nó
void InserirElemento(int pai, char dado, int lado){
switch (lado){
case E:
arvore[pai].FilhoEsq = indice;
arvore[indice].dado = dado;
arvore[indice].pai = pai;
arvore[indice].FilhoEsq = -1;
arvore[indice].FilhoDir = -1;
indice++;
break;

FACULDADE CATÓLICA PAULISTA | 137


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

case D:
arvore[pai].FilhoDir = indice;
arvore[indice].dado = dado;
arvore[indice].pai = pai;
arvore[indice].FilhoEsq = -1;
arvore[indice].FilhoDir = -1;
indice++;
break;
case R:
arvore[indice].dado = dado;
arvore[indice].pai = -1;
arvore[indice].FilhoEsq = -1;
arvore[indice].FilhoDir = -1;
indice++;
break;
}
}

//Função principal
int main(void){
setlocale(LC_ALL, “”); // ajuste do idioma
int temp;
do {
menu_mostrar();
scanf(“%d”, &opt);
fflush(stdin);
switch (opt){
case 1:
printf(“\nInforme qual é o Elemento PAI (deixar em
Branco caso for a Raiz): “);
scanf(“%c”,&pai);
fflush(stdin);
//scanf(“%c”,&pai);
printf(“Digite o elmento do NO: “);
scanf(“%c”,&no);
fflush(stdin);
//scanf(“%c”,&no);
printf(“Digite o lado da subarvore \n Filho a Esquer-
da = %d \n Filho a Direita = %d \n Nó Raiz = %d: “, E,D,R);
scanf(“%d”,&lado);
fflush(stdin);
temp = ProcurarElemento(pai);
InserirElemento(temp,no,lado);

FACULDADE CATÓLICA PAULISTA | 138


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

break;
case 2:
printf(“Digite o Elemento a ser pesquisado: “);
scanf(“%c”,&no);
fflush(stdin);
//scanf(“%c”,&no);
temp = ProcurarElemento(no);
printf(“No %c\nFilho Esquerda: %c \nFilho Direita:
%c\n\n”, arvore[temp].dado, arvore[arvore[temp].FilhoEsq].dado, arvore[arvo-
re[temp].FilhoDir].dado);
system(“pause”); break;
}
}while (opt!=0);
system(“pause”);
return(0);
}

//Desenha o menu na tela


void menu_mostrar(void){
int i;
system(“cls”);
for (i = 0; i < indice; i++){
printf(“| %c “,arvore[i].dado);
}
printf(“\n1 - Inserir um Elemento na arvore (A-Z)”);
printf(“\n2 - Pesquisar um Elemento na arvore (A-Z)”);
printf(“\n0 - Sair do Programa\n\n”);
}
Fonte: elaborado pelo autor

Menu do programa em execução

Inclusão do Elemento A raiz

FACULDADE CATÓLICA PAULISTA | 139


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Inclusão do elemento B, filho a esquerda do nó A

Inclusão do elemento C, filho à direita do nó A

Busca pelo Elemento A

FACULDADE CATÓLICA PAULISTA | 140


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 12
MONTAGEM DE ÁRVORES
BINÁRIAS E BUSCAS EM
ÁRVORES BINÁRIAS

Fonte: https://br.freepik.com/fotos-gratis/parque-verde_1278420.htm

Com os dados armazenados em árvores podemos realizar buscas, em um elemen-


to dentro de uma árvore, sendo também possível montar uma árvore binária para a
busca através de elementos de a partir de um vetor, ordenado ou não ordenado.
Nesta aula veremos como é possível criar uma estrutura de árvore binária seguindo
alguns passos simples, como também é possível efetuar busca em uma árvore de
modo simples.

FACULDADE CATÓLICA PAULISTA | 141


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

12.1 Montagem de árvores binárias

Vimos em aulas anteriores a estrutura em árvore e como que é utilizada para orga-
nizar os dados, sendo considerada uma excelente estrutura pelo fácil acesso às infor-
mações, estamos falando da árvore binária. Observamos também as características
de várias estruturas, tais como a árvore binária simples, a completa, a estritamente
binária. Acredito que você deve ter se relembrando como são estas estruturas e tam-
bém revistos os algoritmos de implementação sobre a criação de uma árvore binária.
Ao analisar os algoritmos anteriores podemos associar que os dados que são armaze-
nados em uma árvore binária, podem ser derivados de outras estruturas, além da en-
trada de dados comum a ser digitada pelo usuário, dentre estas outras possibilidades
temos um vetor. Conforme visto em aulas anteriores em um vetor é possível armaze-
nar informações em uma única variável, guardando os dados em posições no vetor.
Agora que você relembrou o que são as árvores binárias e também o que são veto-
res, vamos aprender a montar uma árvore binária a partir de um vetor, estando este or-
denado ou não. Vamos utilizar como exemplo um vetor de 10 posições não ordenado.

vetor com 10 posições


Fonte: elaborado pelo autor

Como já visto, uma árvore binária é composta por um nó raiz e seus adjacentes, en-
tão, nosso primeiro passo é identificar no vetor o elemento raiz. Um vetor é composto
por posições, sendo assim, devemos encontrar a posição do elemento raiz, para isso
vamos utilizar um cálculo simples para este fato, iniciando encontrar o meio do vetor
na busca binária. Devo lembrar que um vetor se inicia com a posição 0 e termina com
o tamanho do vetor-1, no caso de nosso vetor de dez posições a posição final seria 9
(10 -1 = 9).

Fórmula para encontrar o meio do vetor


Fonte o autor

FACULDADE CATÓLICA PAULISTA | 142


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Com base na fórmula apresentada vemos encontrar o meio de nosso vetor:

Ao final do processo o valor encontrado foi 4,5, como um vetor só possui posições
representadas por números inteiros, o valor após a vírgula é ignorado sendo assim a
posição do meio será 4, ao analisar o vetor veremos que o número 35 ocupa a 4ª po-
sição, assim encontramos o nosso nó raiz.
Agora que nossa árvore possui um nó raiz, vamos dar andamento na inclusão dos
demais elementos do vetor para a árvore binária. Agora que já incluímos a nota raiz,
vamos retornar para a posição 0 do vetor. Assim, iniciamos uma comparação do ele-
mento na posição 0 com a raiz, caso o valor armazenado seja maior que o elemento
raiz, ele será uma subárvore à direita, caso seja menor, será uma subárvore à esquer-
da. Vejamos o exemplo a seguir:

Primeira iteração do vetor para montar a árvore binária


Fonte: elaborado pelo autor

Após alocar o elemento na árvore passamos para o elemento seguinte no vetor,


sendo a posição 1:

FACULDADE CATÓLICA PAULISTA | 143


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Ao analisar o elemento alocado nessa posição é o 2, como este é menor que a raiz,
então este é alocado para esquerda, entretanto como no lado esquerdo já temos um
elemento armazenado na subárvore devemos descer mais um nível.

Após alocar o elemento na árvore passamos para o elemento seguinte no vetor: a


posição 2:

Ao analisar o elemento alocado na segunda posição é o 15, que é menor que a raiz,
mas maior que o nó seguinte que é 7. Nesse caso, vamos inserir o elemento à direita
do nó 7, um filho à direita do nó 7

FACULDADE CATÓLICA PAULISTA | 144


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Após alocar o elemento na árvore passamos para o elemento seguinte no vetor: a


posição 3:

O elemento na posição três do vetor é o 52, nesse caso, ele é maior que a raiz, as-
sim, é alocado para subárvore direita da raiz:

Vamos efetuar o processo de comparação dos elementos no vetor, até que este
seja inteiramente lido e incluído os elementos na árvore binária. Vejamos como a ár-
vore binária ficará após todos os elementos inseridos.

Árvore Binária montada através dos elementos do vetor


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 145


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Ao analisar a árvore binária montada é possível identificar que possui três níveis e
quatro nós folhas (5, 13, 50, 95), repare, inclusive, que ela não é uma árvore completa
ou estritamente binária.

12.2 Buscas em árvores binárias

Agora que já conhecemos a estrutura e sabemos como montar uma árvore binária,
vamos compreender como efetuar uma busca nesta estrutura. Compreenda que bus-
car um elemento dentro dessa estrutura significa navegar pelos nós e seus pontos de
ligação.
Para simplificar o nosso processo de busca será utilizada a árvore binária montada
anteriormente. O procedimento de busca em estrutura de árvores binária é bem sim-
ples: se elege o número a ser buscado e inicia a verificação pelo nó raiz, onde é ana-
lisado se o elemento a ser encontrado é maior ou menor que a raiz, caso seja maior
que a raiz, todo lado esquerdo é descartado, se não, todo o lado direito é descartado.
Este processo de eliminação de galhos da árvore acontece de modo recursivo, a cada
iteração no próximo nó.

Vamos escolher o número 15 para ser encontrado em nossa árvore binária, ao se


comparar o mesmo como o nó raiz (35) observamos que 15 é menor que a raiz, sendo
assim, todo o lado direito é descartado da busca, sendo efetuado o procedimento de
busca novamente apenas no lado esquerdo com os números menores, desta forma
reduzimos a complexidade da busca, além de utilizar menos recursos computacio-
nais.

FACULDADE CATÓLICA PAULISTA | 146


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Busca em árvore binária, lado direito removido na primeira iteração da busca


Fonte: elaborado pelo autor

Dando sequência com a eliminação do lado direito, vamos à busca descendo pelo
lado esquerdo da árvore até o próximo nó, onde se efetua novamente a comparação
do elemento do nó com o que estamos buscando, neste caso chegamos ao nós 7,
como 15 é maior que 7 todo o lado esquerdo a partir do nó 7 é eliminado também.

Busca em árvore binária, lado esquerdo removido na segunda iteração


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 147


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Dando andamento, vamos descer novamente para mais um nível, desta vez, para a
direita do nó 7, chegando até o nó 15, onde é verificado que este se trata do valor de
busca em questão, assim, a busca se encerra. Por fim, podemos dizer que o caminho
percorrido para encontrar o elemento 15 na árvore binária foi 35 -> 7 -> 15, sendo utili-
zados apenas 3 iterações para encontrá-lo.

Passos da busca em árvore binária para encontrar o elemento 15


Fonte: elaborado pelo autor

Caso o número buscado fosse 38 o processo de busca iria iniciar normalmente, pois
o sistema computacional não sabe se este valor estará armazenado ou não, após 4 ite-
rações o algoritmo para e indica que o valor não foi encontrado. Mas por que 4 iterações:
1ª Iteração: é comparado se o valor 38 é maior ou menor que a raiz, neste caso
desloca-se para a direita.
2ª Iteração: é comparado se o valor 38 é maior ou menor que 52, neste caso deslo-
ca-se para a esquerda.
3ª Iteração: é comparado se o valor 38 é maior ou menor que 40, neste caso deslo-
ca-se para a esquerda.
4ª Iteração: ao tentar se deslocar novamente o algoritmo irá identificar que não exis-
te elemento de comparação, parando a execução e informando número não encontrado.
Lembrando que é possível criar a estrutura de uma árvore binária em listas ou vetores,
mas este tipo de busca apresentada é diferente, pois em listas ou vetores onde é efetua-
do um laço de repetição para percorrer estes por completo desde o vetor 0 até o último,
comparando os elementos armazenados sem a eliminação de trechos do mesmo. Deste
modo, o processo de busca apresentado é diferente quando trabalhamos diretamente na
estrutura em árvore.

FACULDADE CATÓLICA PAULISTA | 148


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 13
TÉCNICAS DE ORDENAÇÃO
BUBBLESORT E INSERTIONSORT

Fonte: https://br.freepik.com/fotos-gratis/postura-plana-de-arranjo-de-lapis-coloridos_6864396.htm

Prezado(a) aluno(a), vamos imaginar uma caixa de lápis de cores, onde temos apro-
ximadamente 25 lápis, cada cor tem uma numeração e desejamos colocar o mesmo
em ordem do menor para maior número podemos utilizar alguns procedimentos para
fazer este processo de ordenação, no final o nosso objetivo é ter os lápis ordenados e
organizados. No mundo computacional temos por vezes o mesmo problema, dados
armazenados de modo desordenado e desejamos deixar estes em ordem, o que mais
se busca no ambiente computacional é uma melhora constante de desempenho, isso
significa procurar desenvolver técnicas que melhorem o desempenho dos algoritmos.
As técnicas e algoritmos de ordenação são de grande importância para efetuar
processos massantes e desgastantes de ordenação de estruturas de dados. Você irá

FACULDADE CATÓLICA PAULISTA | 149


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

compreender em nossas próximas aulas como os algoritmos de ordenação executam


seus procedimentos.

13.1 BubbleSort

O método ordenação Bubblesort é o mais simples de todos no que se diz respeito à


ordenação e elementos, este também é conhecido por ordenação por flutuação ou por
método da bolha. Mesmo este sendo o mais simples implementação e identificado
como de alto custo computacional. Seu procedimento consiste em efetuar a compa-
ração e troca dos elementos vizinhos no vetor, seu modo de execução consiste em:

Realizar a ordenação comparando os elementos, dois a dois, e


trocando-se de posição, de acordo com o critério estabelecido de
ordem crescente ou decrescente. Seu nome se deve à ideia de que
os elementos vão “subindo” para as posições corretas, como bolhas
(PUGA; RISSETTI, 2016, p.172).

O procedimento se inicia na primeira posição do vetor, comparando o elemento atu-


al com o elemento do próximo, caso o valor da posição atual seja maior do que o valor
verificado é efetuado uma troca entre os dois números. Assim os valores mais altos
vão flutuando para o final do vetor, criando a ordenação da estrutura. Esse processo
se repete para cada uma das posições, sendo que ao chegar no final da estrutura é
analisado novamente a mesmo por completo para confirmar se a estrutura está orde-
nada.
A ordenação poderá ser efetuada por meio de listas lineares, vamos utilizar como
exemplo um vetor com 5 posições, no qual queremos efetuar a ordenação crescente
(menor para maior) dos valores:

FACULDADE CATÓLICA PAULISTA | 150


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

1º laço de ordenação método Bubblesort


Fonte: Ascencio e Araújo (2010, p.22).

2º laço de ordenação método Bubblesort


Fonte: Ascencio e Araújo (2010, p.22).

A quantidade de trocas a serem efetuadas é indefinida, pois depende do tamanho


do vetor e quanto desordenado este esteja. No exemplo apresentado, a lista não esta-
va totalmente desordenada, por isso exigiu apenas duas iterações, mas dependo da
posição dos valores o algoritmo e rodado novamente, até que toda a lista seja orde-
nada, o maior problema desse método é que ele deve percorrer todos os elementos,

FACULDADE CATÓLICA PAULISTA | 151


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

comparando dois a dois e isso poderá levar um tempo considerável.


Em listas menores este método não será um grande problema, contudo, em listas
maiores, a complexidade irá aumentar, pois será necessário um número maior de in-
terações, vejamos a seguir a implementação do método em linguagem C:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

main(){

int X[5], n, i, aux;

// inserindo os números no vetor


for(i=0; i<=4; i++){
printf(“Digite um numero”);
scanf(“%d”, &X[i]);
}
printf(“\n\nVetor antes do metodo BubbleSort\n”);
for(i=0; i<=4; i++){
printf(“Vetor %d: %d \n”, i, X[i]);
}

// ordenação de forma crescente


for(n=1; n<=5; n++){
// Laço que percorre e ordena o vetor
for(i=0; i<=4; i++){
if(X[i]>X[i+1]){
aux = X[i];
X[i]=X[i+1];
X[i+1]=aux;
}
}
}
printf(“\n\nVetor depois do metodo BubbleSort\n”);
// mostrando o vetor ordenado
for(i=0; i<=4; i++){
printf(“Vetor %d: %d \n”, i, X[i]);
}
}

Script em linguagem C, BubbleSort


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 152


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Resultado do programa BubbleSort


Fonte: elaborado pelo autor

Um detalhe neste método é que a comparação só poderá acontecer com o seu


vizinho mais próximo além do sentido ser único, sempre olhando o próximo elemento
nunca olha os que já passaram. Este método executa N operações, onde N represen-
ta o número de elementos do a serem analisados. No pior caso são feitas operações.
A complexidade desse algoritmo é de ordem quadrática, onde temos os valores de seu
resultado são proporcionais ao quadrado do valor do seu argumento.

13.2 InsertionSort

O método de ordenação InsertionSort também é conhecido como inserção de ele-


mento para ordenação, este método tem o princípio básico de eleger um elemento do
vetor e procurar sua posição ideal no vetor e inseri-lo ordenado.

Será eleito o segundo número do vetor para iniciar a ordenação;


assim, os elementos à esquerda do número eleito estão sempre
ordenados de forma crescente ou decrescente. Logo, um laço com
as comparações será executado do segundo elemento ao último, ou
seja, na quantidade de vezes igual ao número de elementos do vetor
menos um.[...] Enquanto existirem elementos à esquerda do número
eleito para comparações e a posição que atende a ordenação que
se busca não for encontrada, o laço será executado (ASCENCIO;
ARAÚJO, 2010, p.38).

FACULDADE CATÓLICA PAULISTA | 153


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Ao executar o InsertionSort o primeiro elemento do vetor é eleito e removido do


vetor para efetuar as comparações com os demais, ao encontrar sua posição ideal, o
elemento eleito é reinserido no vetor e assim um novo elemento é eleito, repetindo o
processo até que esteja tudo ordenado. Vejamos o exemplo a seguir:

Implementação do método de InsertionSort


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 154


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 14
TÉCNICAS DE ORDENAÇÃO
SELECTIONSORT E QUICKSORT

Fonte: https://www.freeimages.com/pt/photo/abstract-1182296

Na aula anterior, estudamos dois métodos de ordenação e busca ambos de simples


entendimento. Veremos agora novos métodos com uma complexidade maior que os
já apresentados, um método que têm como base a ordem quadrática e outro com o
princípio de divisão de estruturas.

14.1 Ordenação SelectionSort

O método SelectionSort é bem parecido com o InsertionSort e também bem sim-


ples e também de alto consumo computacional. Ele consiste em trocar os elementos
de posição, a partir da primeira posição, procura-se o menor valor em todo o vetor, ao
se escolher um elemento, ele percorre todo o vetor e efetua as trocas quando neces-
sário.

FACULDADE CATÓLICA PAULISTA | 155


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Neste algoritmo de ordenação cada número do vetor, a partir do


primeiro, será eleito e comparado com o menor ou maior, dependendo
da ordenação desejada, número dentre aqueles que estão à direita
do eleito. Nessas comparações procura-se um número menor que o
eleito (quando a ordenação for crescente) ou um maior que o eleito
(quando a ordenação for decrescente). Quando um número satisfaz
as condições da ordenação desejada (menor ou maior que o eleito),
este trocará de posição com o eleito, assim, todos os números à
esquerda do eleito ficam sempre ordenados ( ASCENCIO; ARAÚJO
2010 p.44).

A lógica deste método é trocarmos os menores valores encontrados com a primei-


ra posição. Os elementos são sempre levados a frente do vetor, sendo trocado um
a um, Iniciando o na primeira posição, procurando o menor valor e trocando, depois
procurando o segundo menor valor do vetor até o final, isso se repete até que a lógica
seja aplicada a cada uma das posições.
Para compreendermos melhor, pensamos na seguinte proposição: a cada nova in-
teração, é efetuada uma busca à direita do elemento escolhido é verificado se esse
elemento é o menor do que o que estamos comparando, caso este elemento seja me-
nor é efetuada a troca entre os dois, o eleito e novo elemento, vejamos como o método
funciona com um vetor de 5 elementos ( 5, 4, 2, 8, 3 ).

Implementação do método SelectionSort


Fonte: adaptado de Ascencio e Araújo (2010).

FACULDADE CATÓLICA PAULISTA | 156


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Perceba, prezado(a) aluno(a), compreenda que a lógica do selectionsort é bem pare-


cida com o conceito do bubblesort, onde acontece a comparação, sempre é analisado
dois a dois, mas devemos lembrar que a lógica do Bubblesort é trocar a posição atual
apenas com o elemento a frente caso seja maior, o Selectionsort faz a troca apenas
quando tem certeza que o menor valor foi encontrado para a atual posição, este bus-
ca o menor número do resto do vetor à direita, ou seja, com o elemento eleito o vetor
inteiro poderá ser percorrido para encontrar o menor valor, não se baseando apenas
no próximo elemento adjacente. Vejamos a seguir a implementação em linguagem C.

#include <stdio.h>
#include <conio.h>
main(){
int X[5], j, i, select, menor, troc;
// inserindo os números no vetor
for(i=0; i<=4; i++){
printf(“Digite um numero:”);
scanf(“%d”, &X[i]);
}
printf(“\n\nVetor antes do metodo SelectionSort\n”);
for(i=0;i<=4;i++){
printf(“Vetor %d: %d \n”, i, X[i]);
}
// ordenando de forma crescente
for(i=0;i<=3;i++){
select = X[i];
menor = X[i+1];
troc = i+1;

for(j=i+1;j<=4;j++){
if(X[j] < menor) {
menor = X[j];
troc=j;
}
}
if(menor < select){
X[i]=X[troc];
X[troc] = select;
}
}
printf(“\n\nVetor depois do metodo SelectionSort\n”);
// monstrando o vetor ordenado
for(i=0;i<=4;i++){
printf(“Vetor %d: %d \n”, i, X[i]);
}
}
Script em linguagem C, SelectionSort
Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 157


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Resultado do programa SelectionSort


Fonte: elaborado pelo autor

Este método poderá percorrer toda a estrutura para descobrir que têm algum ele-
mento menor poderá acontecer também que o mesmo percorra toda a estrutura não
encontre um elemento menor, isso faz que aconteça uma processamento desneces-
sário. Este método executa N operações, onde N representa o número de elementos
do a serem analisados. No pior caso, são feitas operações. A complexidade desse al-
goritmo é de ordem quadrática, igualmente ao InsertionSort e BubbleSort, onde temos
os valores de seu resultado são proporcionais ao quadrado do valor do seu argumento.

14.1 Ordenação QuickSort

O método Quicksort aplica uma técnica de ordenação diferente das que vimos nas
aulas anteriores, sendo considerado o algoritmo de ordenação mais utilizado no mun-
do por não diferenciar o tamanho do vetor ou se este está parcialmente ordenado ou
não. O método foi criado em 1960 pelo cientista britânico Sir Charles Antony Richard
Hoare e publicado em 1962 com várias melhorias. Segundo Cormem (2012), a lógica
deste método é dividir a estrutura em partes menores para depois ordenar, também é
conhecido por classificação por troca de partição.

Neste algoritmo de ordenação, o vetor é particionado em dois por


meio de um procedimento recursivo. Essa divisão ocorre até que
o vetor fique com apenas um elemento, enquanto os demais ficam
ordenados à medida que ocorre o particionamento (ASCENCIO;
ARAÚJO, 2010, p.44).

FACULDADE CATÓLICA PAULISTA | 158


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

O método desse algoritmo consiste em escolher um elemento qualquer e deno-


mina-lo pivô, a partir desse ponto o vetor é dividido em sublistas, utiliza a estratégia
de dividir para conquistar, conforme vai organizando o elemento pivô a estrutura é
parcialmente ordenada. Com a escolha do elemento pivô a estrutura será dividida em
três sublistas, uma onde ficará o pivô, uma para os valores menores e outra para os
valores maiores do que o próprio pivô, desta forma é assegurado que os elementos
menores vão sempre estar à esquerda dos maiores e que o pivô esteja na sua correta
posição dentro do vetor.

Nas sublistas é escolhido novamente um novo elemento pivô é efetuada a divisão


novamente, esse processo é realizado até que a estrutura fique com apenas 2 elemen-
tos, posteriormente é realocada os elementos ordenador na estrutura. Vejamos a se-
guir um exemplo desse método na ordenação de 10 elementos, o elemento escolhido
como pivô inicial será o número 4, a partir dele será efetuada a ordenação do vetor.

Exemplo 1: Implementação do método QuickSort


Fonte: (ASCENCIO; ARAÚJO, 2010, p.44)

FACULDADE CATÓLICA PAULISTA | 159


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Exemplo 2: Implementação do método QuickSort


Fonte: elaborado pelo autor

Podemos observar que no segundo exemplo o elemento escolhido foi o 5, após isso
foi sendo separado os elementos até que todo o vetor fique ordenado, a cada lista or-
denada os elementos eram realocados. O processo de ordenação pode ser realizado
toda a esquerda e depois a direita, isso não irá interferir no processo, visto que ambos
os lados vão ter praticamente o mesmo tamanho sempre.
Esse algoritmo tem uma complexidade maior por conta da separação, entretanto,
é mais eficaz do que os já apresentados, nos quais é efetuada a comparação sempre
em dois elementos do vetor, caso o elemento de comparação seja menor se efetua
a troca, nesses métodos, a lista sempre vai ser lida por completo várias vezes. No
método QuickSort, o vetor ou lista já irá ser separada de forma ordenada. Vejamos o
exemplo desse método em linguagem C.

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void quick_sort (int *vet, int total) {
int i, j, p, t;
if(total < 2)
return;

FACULDADE CATÓLICA PAULISTA | 160


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

p = vet [total / 2];


for(i = 0, j = total - 1;; i++, j--){
while (vet[i] < p)
i++;
while(p < vet[j])
j--;
if (i >= j)
break;
t = vet[i];
vet[i] = vet[j];
vet[j] = t;
}
quick_sort(vet, i);
quick_sort(vet + i, total - i);
}
main(){

int X[5], i;

// inserindo os números no vetor


for(i=0; i<=4; i++){
printf(“Digite um numero: “);
scanf(“%d”, &X[i]);
}
printf(“\n\nVetor antes do metodo QuickSort\n”);
for(i=0; i<=4; i++){
printf(“Vetor %d: %d \n”, i, X[i]);
}

// ordenação de forma crescente


quick_sort(X,5);

printf(“\n\nVetor depois do metodo QuickSort\n”);
// mostrando o vetor ordenado
for(i=0; i<=4; i++){
printf(“Vetor %d: %d \n”, i, X[i]);
}
}

Script em linguagem C, QuickSort


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 161


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Resultado do programa QuickSort


Fonte: elaborado pelo autor

Este método é considerado mais eficiente em comparação aos analisados até o


momento, pois o mesmo não é um método que executa uma ordem quadrática. Pode-
mos dizer também que o pior caso da execução do método ocorre quando o elemento
pivô divide a lista de forma desbalanceada, sendo que em cada sublista tem a quanti-
dade de elementos diferentes, o melhor caso é quanto às partes divididas não tem o
tamanho maior que N/2, sendo que N é o tamanho total da estrutura.

FACULDADE CATÓLICA PAULISTA | 162


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 15
TÉCNICAS DE ORDENAÇÃO
SHELLSORT E MERGESORT

Fonte: https://br.freepik.com/vetores-gratis/fundo-de-formas-abstratas-brancas_12628435.htm

Na aula anterior, estudamos dois métodos de ordenação e busca, um destes de


ordem quadrática e outro com uma complexidade maior, entretanto mais eficiente
no processo de ordenação. Veremos agora novos métodos com uma complexidade
maior que os já apresentados, mas com maior eficiência.

15.1 Ordenação ShellSort

O algoritmo de Shellsort foi desenvolvido por Donald Shell e publicado em 1959


pela Universidade de Cincinnat, este é considerado como um dos métodos mais efi-
cazes de ordenação. Um detalhe curioso é que o seu nome não tem relação com uma

FACULDADE CATÓLICA PAULISTA | 163


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

concha (shell, em inglês), mas sendo na verdade o nome de seu criador. Esse algorit-
mo se utiliza da ordenação por inserção. Esta técnica de ordenação seria a junção de
duas técnicas vistas QuickSort e do InsertionSort, pois é dividido o vetor em sublistas,
depois aplica a busca e inserção de elementos na mesma.

O método shellsort pode ser considerado um refinamento do método


de inserção direta, diferindo pelo fato de no lugar de considerar o
vetor a ser ordenado como um único segmento, ele considera vários
segmentos sendo aplicado o método de inserção direta em cada um
deles. Basicamente o algoritmo passa várias vezes pela lista dividindo
o grupo maior em menores (OLIVEIRA; PRADA; SILVA, 2002, p. 140)

O método Shell consiste em trabalhar com um elemento denominado GAP. Esse


GAP determina a distância entre os elementos que são separados do vetor original,
geralmente iniciando pela maior distância de intervalo N-2, após isso aplicado o in-
sertionsort, após ordenada a sublista esta é inserida no vetor original. O valor do GAP
é decrementado conforme as sublistas são criadas e aplicadas ao método do inser-
tionsort, o processo se repete até o gap atingir o valor igual a 1, efetuando uma busca
simples igual ao bubblesort.
Imagine um vetor com 8 posições e o gap inicial sendo 3, a primeira sublista se
inicia da posição 0 do vetor, essa irá conter os seguintes elementos: shell[0], shell[3],
shell[6].
Após efetuar essa separação, teremos uma sublista com 3 elementos no qual
aplicamos o insertionsort, depois retornamos para o vetor original. É efetuada uma
nova separação agora a partir da posição 1 do vetor, contendo os elementos: shell[1],
shell[4], shell[7].
São criadas novas sublistas até que todos os elementos sejam contemplados fina-
lizando a primeira passagem, após isso, o gap é decrementado em -1, sendo, então 2.
Será efetuado o procedimento até que o vetor esteja ordenado.

FACULDADE CATÓLICA PAULISTA | 164


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Método ShellSort
Fonte: Adaptado pelo autor

O descolamento de separação pelo GAP vai sempre seguindo da esquerda para a


direita e nunca passa para fora do vetor, para compreender. Vejamos a implementa-
ção do método em linguagem C.

FACULDADE CATÓLICA PAULISTA | 165


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#include <stdio.h>
#include <conio.h>

main(){
int X[8], j, i, value, gap = 1, size;
// inserindo os números no vetor

for(i=0; i<=7; i++){
printf(“Digite um numero:”);
scanf(“%d”, &X[i]);
}

printf(“\n\nVetor antes do metodo ShellSort\n”);
for(i=0;i<=7;i++){
printf(“Vetor %d: %d\n”, i, X[i]);
}

// ordenando de forma crescente
while(gap < 8) {
gap = 3*gap+1;
}
while ( gap > 1) {
gap /= 3;
for(i = gap; i <=7; i++) {
value = X[i];
j = i - gap;
while (j >= 0 && value < X[j]) {
X[j + gap] = X[j];
j -= gap;
}
X[j + gap] = value;
}
}

printf(“\n\nVetor depois do metodo ShellSort\n”);
// mostrando o vetor ordenado
for(i=0;i<=7;i++){
printf(“Vetor %d: %d\n”, i, X[i]);
}
}

Script em linguagem C, ShellSort

FACULDADE CATÓLICA PAULISTA | 166


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Resultado aplicação do algoritmo ShellSort


Fonte: elaborado pelo autor

O método ShellSort é de complexidade quadrática, sendo o mais eficiente algo-


ritmo de classificação que tem como base este princípio de varreduras de vetor. A
sua complexidade até o momento não foi definida, pois ninguém ainda foi capaz de
analisar a sua lógica algoritmo com precisão, visto que sua análise contém alguns
problemas matemáticos muito complexos, mesmo assim demonstrando um método
muito eficiente.

FACULDADE CATÓLICA PAULISTA | 167


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

15.1 Ordenação MergeSort

Dentre todas as técnicas de ordenação, o método MergeSort é um dos mais conhe-


cido e tem uma derivação do método QuickSort que aplica o conhecido de divisão da
estrutura principal em outras menores, sendo denominado como um algoritmo que di-
vide para conquistar. Tem como princípio que dividir um grande problema em porções
menores poderá ser mais fácil e eficiente de resolver.
O MergeSort aplica o conceito de recursividade onde é a estrutura inicial é dividido
em duas partes, posteriormente é aplicado a divisão nas 2 partes, assim tendo outras
quatro menores, seguindo assim por diante até que não seja possível dividir as partes,
deixando o vetor da forma mais simples possível. Após isso, reagrupam-se novamen-
te essas partes em ordem até que todas estejam reagrupadas.
Mesmo o MergeSort sendo mais complexo do que os demais métodos já apresen-
tados, o esforço computacional é menor, porém, para cada nova divisão é criado um
novo vetor dinamicamente na memória, ao trabalharmos com vetores muitos gran-
des, isso pode consumir muito espaço de alocação.
Para encontrar o meio da estrutura utilizamos um cálculo simples meio=(posição
inicial + posição final) / 2, caso o resultado não for um valor inteiro se arredonda o
valor para cima: Exemplo 4,5 = 5 este é o limite da divisão.

1º parte da ordenação, divisão do vetor


Fonte: Ascencio e Araújo (2010, p.53).

FACULDADE CATÓLICA PAULISTA | 168


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

2º parte da ordenação, divisão do vetor


Fonte: Ascencio e Araújo (2010, p.53).

O algoritmo de MergeSort é considerado uma evolução do BublleSort e do Selec-


tionSort, mesmo sendo dividido até o nível mais baixo, ele é bem parecido com o Qui-
ckSort, pois ambos se utilizam do conceito dividir para conquistar. Com base em As-
cencio e Araújo (2010), apresentaremos o Script em linguagem C, MergeSort

FACULDADE CATÓLICA PAULISTA | 169


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

#include <stdio.h>
#include <conio.h>

void intercala(int X[], int inicio, int fim, int meio){


int posLivre,inicio_vetor1, inicio_vetor2, i;
int aux[10];
inicio_vetor1 = inicio;
inicio_vetor2 = meio+1;
posLivre = inicio;
while(inicio_vetor1 <= meio && inicio_vetor2 <= fim){
if (X[inicio_vetor1] <= X[inicio_vetor2])
{
aux[posLivre] = X[inicio_vetor1];
inicio_vetor1++;
}
else{
aux[posLivre] = X[inicio_vetor2];
inicio_vetor2++;
}
posLivre++;
}
//se ainda existem numeros no primeiro vetor
//que nao foram intercalados
for (int i = inicio_vetor1; i <= meio; ++i)
{
aux[posLivre] = X[i];
posLivre++;
}
//se ainda existem numeros no segundo vetor
//que nao foram intercalados
for (int i = inicio_vetor2; i <= fim; ++i)
{
aux[posLivre] = X[i];
posLivre++;
}
//retorne os valores do vetor aux para o vetor X
for (int i = inicio; i <=fim; ++i)
{
X[i] = aux[i];
}
}
void merge (int X[], int inicio, int fim){
int meio;
if (inicio < fim)

FACULDADE CATÓLICA PAULISTA | 170


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

{
meio = (inicio+fim)/2;
merge (X,inicio, meio);
merge (X,meio+1, fim);
intercala(X,inicio, fim, meio);

}
}

main(){

int X[8], i;

for(i=0; i<=7; i++){
printf(“Digite um numero:”);
scanf(“%d”, &X[i]);
}
printf(“\n\nVetor antes do metodo MergeSort\n”);
for(i=0;i<=7;i++){
printf(“Vetor %d: %d\n”, i, X[i]);
}
// ordenando de forma crescente
merge(X,0,7);

printf(“\n\nVetor depois do metodo MergeSort\n”);
// mostrando o vetor ordenado
for(i=0;i<=7;i++){
printf(“Vetor %d: %d\n”, i, X[i]);
}
}

Script em linguagem C, MergeSort


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 171


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Resultado aplicação do algoritmo MergeSort


Fonte: elaborado pelo autor

O método MergeSort foi criado em 1945 pelo matemático húngaro chamado John.
Von Newmann nome este presente até hoje no mundo da computação ao nos refe-
rirmos sobre a arquitetura computacional de um computador e sobre o processamen-
to de dados. Mesmo este sendo um método com um bom desempenho em vetores
não muito grandes, sua implementação pode ser ineficiente ao compararmos com
outros métodos como o Bubblesort e Selectionsort.

O detalhe principal que devemos observar é que dependendo do tamanho da es-


trutura que vamos lidar não compensa aplicarmos uma estrutura que tenha uma alta
complexidade, este é o caso da utilização da recursividade do MergeSot que poderá
aplicar por muitas vezes a chamada da função.
.

FACULDADE CATÓLICA PAULISTA | 172


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

AULA 16
TEORIA DOS GRAFOS

Fonte: https://br.freepik.com/vetores-gratis/fundo-de-tecnologia-com-linhas-de-conexao-digital-low-poly_12572903.htm

Existem diversas formas de armazenamento de dados e estruturas, conforme visto


em aulas anteriores podemos citar as listas lineares e árvores, mas temos também
uma estrutura muito utilizada no campo computacional, estamos falando de Grafos.
Uma Grafo é uma importante estrutura matemática com aplicação em diversas áreas
do conhecimento na definição e/ou resolução de problemas como o uso do GPS onde
o mesmo encontra a melhor rota, em um sistema de logística para identificação da
melhor rota e a quantidade de viagens necessárias, escoamento de águas de esgoto,
sistema de roteamento de dados redes de computadores, como também na arquite-
tura de alguns Banco de Dados NoSQL atuais.
De acordo com a matéria publicada pelo serviço AWS da Amazon:

Os bancos de dados grafo foram criados especificamente para


possibilitar o armazenamento de relacionamentos e a navegação
por eles. Os relacionamentos são elementos distintos que agregam
a maior parte do valor para os bancos de dados grafo. A quantidade
e os tipos de relacionamentos que um nó pode ter são ilimitados.
https://aws.amazon.com/pt/nosql/graph/. Acesso em: 20 de jul.2021

A utilização da estrutura de um grafo vai muito além do que estes pequenos exem-
plos apresentados, por isso nesta aula vamos conhecer um pouco da estrutura de um

FACULDADE CATÓLICA PAULISTA | 173


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

grafo, qual a sua origem e características, como também a forma da representação


computacional de um grafo.

16.1 O caso das Sete Pontes de Königsberg

Para iniciarmos a nossa conversa sobre a teoria dos Grafos devemos conhecer um
pouco da história de onde surgiu a ideia desta estrutura, que na verdade a Teoria dos
Grafos surgiu por uma acaso em 1736, quando o matemático e físico suíço Leonhard
Paul Euler (1707 - 1783), por meio do seu artigo Solutio problematis ad geometriam
situs pertinentes, apresentou uma proposta como solução de um famoso conto so-
bre as Sete pontes de Königsberg.
Na região de Königsberg (atual Kaliningrado) que é contada pelo Rio Prególia, divi-
dindo partes das cidades em duas grandes ilhas e duas faixas continentais. Na época
havia 7 pontes que interligam toda a cidade, dizia ser possível atravessar todas as sete
pontes de Königsberg sem repetir nenhuma delas no trajeto.

Mapa das 7 pontes de Sete pontes de Königsberg


Fonte: https://en.wikipedia.org/wiki/Seven_Bridges_of_K%C3%B6nigsberg

FACULDADE CATÓLICA PAULISTA | 174


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Diversas pessoas tentaram solucionar este enigma, mas infelizmente sem sucesso
por anos e na verdade até hoje não teve uma solução para isso. Leonhard Paul Euler
provou matematicamente que não era possível chegar em todas as regiões usando
todas as 7 pontes e passando por elas uma única vez. Para seu entendimento e dos
demais Euler elaborou uma figura onde considerava cada ponto da imagem uma por-
ção de terra e as pontes por linhas que interligam os pontos, eis que surgiu a forma
mais antiga de um grafo registrado.

Grafo criado por Euler para representar as sete pontes de Königsberg


Fonte: https://en.wikipedia.org/wiki/Seven_Bridges_of_K%C3%B6nigsberg

Segundo o estudo realizado por Euler, o mesmo notou que o mesmo possui algu-
mas características sobre a quantidade de linhas que interligam cada ponto, chegan-
do a conclusão que só seria possível percorrer todo o trajeto atravessando cada uma
das pontes uma única vez caso houvesse exatamente zero ou dois pontos onde tives-
sem um número ímpar de arestas. Para compreender vejamos o exemplo a seguir da
teoria de Euler:

Exemplo 1 da Técnica de Euler


Fonte: elaborado pelo autor

FACULDADE CATÓLICA PAULISTA | 175


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Com base no Grafo apresentado vamos perceber que temos zero pontos que têm
a ligação por um número ímpar de linhas, todos os pontos tem um número par de co-
nexões. Assim podemos percorrer todo o Grafo em um sentido único e não repetindo
nenhuma linha, saindo do ponto 1:
Início 1 -> 2 -> 3 ->4 -> 1 Chegada.

Exemplo 2 da Técnica de Euler


Fonte: elaborado pelo autor

Neste segundo exemplo notamos que o Grafo apresentado tem no máximo pontos
com interligações que têm um número ímpar de linhas, exatamente os pontos 2 e 4
tem o número ímpar todos os pontos tem um número par de conexões. Com o número
ímpar de arestas conexões é possível entrar e sair usando duas delas, sobrando uma
terceira. Um ponto de observação é que uma dessas conexões será obrigatoriamente
o início e outra o final do trajeto e o ponto de início deve ser uma destas conexões
ímpares.
Início 4 -> 1 -> 2 ->3 -> 4->2 Chegada. Utilizamos todas as conexões apenas 1 única
vez e visitamos todos os pontos.

No grafo originalmente elaborado por Euler, vamos notar que todos os pontos pos-
suem conexões ímpares, por isso é impossível percorrer todos os pontos sem repetir
alguma conexão, Euler conseguiu comprovar isso com a sua teoria e explicações.

FACULDADE CATÓLICA PAULISTA | 176


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

16.3 Teoria dos Grafos

Agora que você já sabe a história de onde surgiu o conceito de Grafos, mas conhe-
cer um pouco mais sobre esta estrutura para a visão computacional. Na teoria dos
grafos teremos a representação Gráfica de um Grafo contendo vértices (ponto ou local
de armazenamento de dados), em geral, representado por meio de um círculo, como
também por arestas que são as linhas de conexão entre dois vértices.
De modo geral, um Grafo é uma estrutura G = (V,A), onde V é um conjunto de vértices
(nós) e A é um conjunto de arestas (arcos). O Conjunto de V são todos os nós do Grafo,
o conjunto de A e interligação de todos os nós A = {(F,H)}. O que devemos compreender
é que uma aresta está contida em um conjunto de Vértices ((F,H) ∈ V) e que cada aresta
está contida em um conjunto de Arestas (A ∈ A). Agora que você já sabe como fazer a
apresentação forma de um grafo, vamos analisar o Grafo elaborado por Euler.

Grafo elaborado por Euler


Fonte: elaborado pelo autor

A partir do Grafo apresentado podemos fazer a sua apresentação formal, lembran-


do que um Vértice não pode ser nulo, ou seja, ele deve ter algum dado ou rótulo no
mesmo.
G = (V, A)
V = {1, 2, 3, 4}
A = {(1,2), (2,3), (3,4), (4,1), (4,2)}

Podemos ter algumas variações dos tipos de Grafo, por exemplo, este pode ter setas
que indiquem a direção das arestas, este é considerado um grafo orientado (ou dígrafo).

FACULDADE CATÓLICA PAULISTA | 177


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Em um grafo dirigido, uma aresta é representada por meio de uma


seta ligando as representações dos dois vértices da aresta no sentido
do primeiro para o segundo vértice. E em um grafo não dirigido, uma
aresta é representada por meio de uma linha (reta ou curva) ligando
as representações dos dois vértices da aresta (VIEIRA, 2007, p.32).

Grafo Orientado
Fonte: elaborado pelo autor

Ao observar o Grafo apresentado notamos que as setas dão o sentido de onde po-
de-se navegar no Grafo, além disso este Grafo apresenta outros aspectos sendo: não
é um Grafo fechado, temos Vértices que ao chegar no mesmo não temos direciona-
mento para nenhum outro como 5 e 4, Vértices que são inacessíveis como o vértice 2,
pois não temos arestas indicando o caminho, por fim o caso do vértice 1 que temos
uma seta que liga a ele mesmo como se representa-se um loop. Vejamos a apresen-
tação formal deste Grafo.
G = (V, A)
V = {1, 2, 3, 4, 5, 6}
A = {(1,1), (1,3), (2,1), (2,3), (3,4), (3,5), (3,6), (6,4)}

O grau de um vértice é definido pela sua quantidade de arestas, mas temos um


ponto de atenção, pois o mesmo vértice poderá ter graus diferentes por conta das
arestas de saída e a de entrada no vértice. No exemplo do grafo orientado, podemos
afirmar que o vértice 3 possui grau 5, sendo grau de saída 3 {(3,4), (3,5), (3,6)} e grau 2
de entrada {(1,3), (2,3)}.

FACULDADE CATÓLICA PAULISTA | 178


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

Podemos ter um Grafo conexo quando é possível partir de um vértice V por meio
de suas arestas incidentes chegar até o mesmo, conforme os já apresentados. En-
tretanto, podemos ter também um grafo é dito desconexo, quando algum vértice é
totalmente inacessível, nenhuma aresta sai ou chega ao mesmo.

Grafo Desconexo
Fonte: elaborado pelo autor

Vimos até agora que é possível desenhar um grafo a partir de um conhecido con-
junto G = (V,A), mas estes só apresentam linhas e setas, além destas estrutura de
Grafos, existem variações. Por exemplo, existem os grafos mistos, que onde o mesmo
pode ter arestas orientadas e não orientadas, podendo ser inclusive desconexo, como
por fim este pode ser ponderado (rotulado), onde as arestas recebem pesos.

FACULDADE CATÓLICA PAULISTA | 179


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

CONCLUSÃO
Prezado(a) aluno(a)! É com muita satisfação que apresentamos neste material alguns
temas sobre estrutura de dados e classificação de dados. O conhecimento sobre estru-
tura de dados e alguns de seus pontos são fundamentais para o desenvolvimento de
softwares e tecnologias em inovação. Esse conhecimento se faz importante em sua vida
acadêmica e profissional.
Com essa abordagem, vamos relembrar o que estudamos e os pontos principais do
material.
Abordamos inicialmente o conceito de linguagem C, vimos que ela é considerada a
mãe de várias outras linguagens de alto nível como o JAVA, PHP, DELPHI, entre outras.
Aprendemos que a linguagem C foi utilizada por muitos anos no desenvolvimento de sof-
twares, por isso, estudamos os seus conceitos básicos e suas principais funcionalidades,
o que dá a você conhecimento necessário para desenvolver seus primeiros scripts em
linguagem C. Vimos também o que são variáveis, funções e expressões, desvios condicio-
nais simples em compostos ( IF e ELSE ) e alguns dos tipos de laços de repetição como o
FOR, WHILE, DO WHILE, entre diversas funcionalidades.
Conhecemos algumas das formas de estrutura de dados mais utilizadas, como as lis-
tas lineares, que podem ser do tipo encadeadas, duplamente encadeadas, circulares, entre
outras. Vimos também as estruturas em árvores binárias, uma das formas mais fáceis de
se acessar uma informação ou encontrar um elemento. Outras duas estruturas de grande
importância são as de Pilha e Fila, também conhecidas como FIFO e LIFO.
Foram trabalhados conceitos mais avançados com a ordenação dos elementos no
vetor, utilizando os métodos do BubbleSort (método bolha), MergeSort, QuickSort, entre di-
versos outros. Apresentamos a você alguns dos mais utilizados, mas ainda temos vários
para explorar. Nossa intenção foi fazer com que você vivenciasse na prática a manipu-
lação dessas estruturas de dados, por isso, sempre buscamos em cada unidade trazer
exemplos de implementações dos conteúdos em linguagem C.
Foi apresentado também como montar uma árvore binária a partir de um vetor, sendo
esse ordenado ou não e também como efetuar a busca em árvores binárias.
Por fim, abordamos as informações relevantes sobre a teoria dos Grafos e suas aplica-
ções, como este conceito surgiu suas características e representação. 
Esperamos ter alcançado nosso objetivo em passar nosso conhecimento a você, ca-
ro(a) aluno(a). Desejamos que você seja muito feliz ao percorrer o mundo profissional.
Muito sucesso e paz!

FACULDADE CATÓLICA PAULISTA | 180


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

ELEMENTOS COMPLEMENTARES

LIVRO

C Completo e Total
Autor: Herbert Schildt
Edição: São Paulo, Makron Books, 1996
Resumo: Herb Schildt, cujos livros sobre C e C++
venderam mais de um milhão de cópias em todo
mundo, revisou e atualizou a melhor referência
que você pode ter sobre C. Não importa se você é
programador iniciante ou um profissional veterano, as
respostas a todas as suas perguntas sobre C podem
ser encontradas nesta obra.

LIVRO

Linguagem C: Completa e descomplicada


Autor: André Backes
Resumo: Este livro traz um programa de um curso
completo de linguagem C, tratando com simplicidade
dos assuntos mais complicados até os mais básicos.
Livro-texto para estudantes de graduação e pós-
graduação em Computação, também pode ser utilizado
por profissionais que trabalham com programação e
profissionais de áreas não computacionais (biólogos,
engenheiros, entre outros) que precisam utilizar o
programa em alguma tarefa

FACULDADE CATÓLICA PAULISTA | 181


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

WEB

https://csedweek.org/learn
Descrição: É a plataforma da campanha da Semana do Ensino da Ciência da
Programação, lançado em 2016. Nela, estão disponíveis vários tutoriais para todos
gostos e idades, alguns, inclusive, em português. Como os puzzles com Angry Birds.
Há tutoriais para aprender a programar até mesmo sem computadores, usando papel
e caneta para escrever um algoritmo capaz de cumprir determinada tarefa

LIVRO

Algoritmos e lógica de programação 


Ricardo Concílio (Autor), Marcelo Gomes (Autor),
Marcio Soares (Autor), Marco Souza (Autor)

Descrição da obra: Com linguagem simples e didática,


o livro procura tornar a lógica de programação
prática, além de mostrar aos estudantes um caminho
mais adequado na construção dos algoritmos.
A abstração de procedimentos e dados é um dos
maiores problemas para os estudantes nos cursos
introdutórios, e, para tentar escapar das dificuldades,
os autores utilizam uma arquitetura de computador
simples, baseada na arquitetura de Von Neumann,
de maneira a fixar os conceitos relacionados à operação de computadores. Um dos
principais objetivos do livro é fazer que o estudante consiga no futuro relacionar os
aspectos abstratos da computação com sua implementação, e ainda incentivar a
necessidade de escrever os algoritmos antes de sua implementação propriamente
dita. A descrição dos algoritmos no texto é mostrada por meio de fluxogramas

FACULDADE CATÓLICA PAULISTA | 182


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

LIVRO

Aprenda Lógica de Programação e Algoritmos com


Implementações em Portugol, Scratch, C, Java, C#
e Python
Cláudio Luís Vieira Oliveira (Autor)
Descrição: A programação de computadores tem se
tornado cada vez mais fácil, acessível e popular, pois
no mundo atual, o uso da tecnologia está fortemente
inserido no cotidiano das pessoas, criando um universo
de novas possibilidades. Este livro é o resultado d
as experiências adquiridas pelos autores ao longo
de mais de uma década dedicada ao ensino nos
cursos de graduação em Informática. No primeiro
capítulo, o leitor irá encontrar os conceitos empregados para a resolução de problemas
computacionais usando, para isso, técnicas e ferramentas como fluxograma, Portugol
e a Scratch, que é uma linguagem de programação visual que possibilita aprendizado
rápido e lúdico.

LIVRO

Algoritmos: Lógica Para Desenvolvimento de


Programação de Computadores
Jayr Figueiredo de Oliveira e José Augusto N. G.
Manzano 

Descrição: Este livro abrange os principais conceitos


de programação de computadores, incluindo a norma
ISO 5807:1985 (E) e importantes fundamentos, como
entrada, processamento, saída, tipos de dados,
variáveis, constantes, operadores aritméticos e
expressões aritméticas. Explica tomada de decisão,
laços condicional e incondicional, programação com
matrizes, técnicas de ordenação e busca, uso de registros e uma maneira de incorporar
- em uma única matriz - dados de tipos diferentes. A organização de um programa em
sub-rotinas complementa o ensino, abordando procedimentos, funções e passagens
de parâmetro. A obra apresenta, ainda, medidas de complexidade, fundamentos de
otimalidade e backtracking, bem como ações de busca de padrões em strings.

FACULDADE CATÓLICA PAULISTA | 183


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

REFERÊNCIAS
SCHILDT, Herbert. C Completo e Total: 3. edição revisada e atualizada. Pearson Makron
Books, São Paulo, 1997.

SCHILDT, Herbert. Linguagem C: Guia do Usuário. McGraw-Hill, São Paulo, 1986.

LOPES, A.; GARCIA, G. Introdução à Programação. Rio de Janeiro: Elsevier, 2002

MIZRAHI, V. V. Treinamento em linguagem C. Pearson Pretice Hall. São Paulo, 2008.

ALBANO, R. D.; ALBANO, S. G. Programação em Linguagem C. Rio de Janeiro: Editora


Ciência Moderna, 2010

FORBELLONE, A. L. V.; EBERSPACHER, H. F. Lógica de programação: a construção


de algoritmos e estruturas de dados. 3. ed. São Paulo: Pearson Prentice Hall, 2005. 

DEITEL, H. M.; DEITEL, P. J. C: como programar. 6 ed. São Paulo, Pearson Prentice
Hall. 2011.

MANZANO, JA OLIVEIRA; ALGORITMOS, J. F. Lógica para Desenvolvimento de


Programação de Computadores. São Paulo: Érica, 2000.

ASCENCIO, Ana Fernanda Gomes; ARAÚJO, Graziela Santos de. Estrutura de dados:
algoritmos, análise de complexidade e implementações em JAVA e C/C++. Pearson
Prentice Hall. São Paulo 2010.

ASCENCIO, Ana Fernanda Gomes; CAMPOS, Edilene Aparecida Veneruchi de.


Fundamentos da programação de computadores. 2. ed. Pearson Prentice Hall. São
Paulo 2007.

ASCENCIO, Ana Fernanda Gomes; CAMPOS, Edilene Aparecida Veneruchi de.


Fundamentos da programação de computadores: algoritmos, PASCAL, C/C++ (padrão
ANSI) e Java. 3. ed. São Paulo: Pearson Education do Brasil, 2012.

FACULDADE CATÓLICA PAULISTA | 184


ALGORITMOS E LÓGICA DE
PROGRAMAÇÃO I
ESPECIALISTA JOSÉ HENRIQUE HONJOYA

NORTON, Peter. Introdução à informática. Pearson Makron Books. São Paulo 1996 

OLIVEIRA, Álvaro B. de; PRADA, Adriana; SILVA, Reginaldo R. da. Métodos de Ordenação
Interna: Implementação, Análise e Desempenho. Visual Books, 2002

PAPPAS, C. H.; MURRAY, W. H. Turbo C++ Completo e Total. São Paulo: Makron, McGraw-
Hill, 1991.

PUGA, Sandra; RISSETTI, Gerson. Lógica de programação e estrutura de dados, com


aplicações em JAVA. 2. ed. Pearson Prentice Hall. São Paulo 2009.

TENENBAUM, Aaron M. et al. Estrutura de dados usando C. Pearson Makron Books.


São Paulo 1995

RANGEL, W. Celes e J. L. Listas Encadeadas. <http://www.ic.unicamp.br/~ra069320/


PED/MC102/1s2008/Apostilas/Cap10.pdf>

FACULDADE CATÓLICA PAULISTA | 185

Você também pode gostar