Logo Passei Direto
Buscar
Material
páginas com resultados encontrados.
páginas com resultados encontrados.
left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Prévia do material em texto

Rafael Sanches Rocha
Algoritmos e 
programação II 
com C#
AL
GO
RI
TM
OS
 E
 P
RO
GR
AM
AÇ
ÃO
 II
 C
OM
 C
#SÉRIE 
UNIVERSITÁRIA
A Série Universitária foi desenvolvida pelo Senac 
São Paulo com o intuito de preparar profissionais 
para o mercado de trabalho. Os títulos abrangem 
diversas áreas, abordando desde conhecimentos 
teóricos e práticos adequados às exigências 
profissionais até a formação ética e sólida.
Algoritmos e programação II com C# é uma 
obra voltada aos problemas de programação 
envolvendo a manipulação de dados e às soluções 
utilizadas por meio de algoritmos. São discutidas, 
entre outras questões, os problemas de busca e 
ordenação de dados, as diferentes abordagens 
de implementação de um algoritmo por meio 
de iteratividade e recursividade, os vetores, as 
matrizes e a leitura e escrita de arquivos. É feita, 
ainda, uma introdução sobre classes e objetos. 
O objetivo do livro é proporcionar uma visão 
geral da manipulação de dados por algoritmos, 
apresentando ao leitor aspectos essenciais à 
análise e ao desenvolvimento de programas.
e-
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Dados Internacionais de Catalogação na Publicação (CIP)
(Simone M. P. Vieira - CRB 8a/4771)
Rocha, Rafael Sanches
  Algoritmos e programação II com C# / Rafael Sanches Rocha. – São 
Paulo : Editora Senac São Paulo, 2022. (Série Universitária
  Bibliografia.
  e-ISBN 978-85-396-3703-4 (ePub/2022)
  e-ISBN 978-85-396-3704-1 (PDF/2022)
  1. Desenvolvimento de sistemas 2. Linguagem de programação  
3. Algoritmos : Programação 4. Programação recursiva I. Título. II. Série 
22-1696t CDD – 005.13
 003 
 BISAC COM051300 
 COM051230
Índice para catálogo sistemático:
1. Linguagem de programação : Algoritmos 005.13
2. Desenvolvimento de sistemas 003
M
at
er
ia
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
ALGORITMOS E 
PROGRAMAÇÃO II COM C#
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Rafael Sanches Rocha
Administração Regional do Senac no Estado de São Paulo
Presidente do Conselho Regional
Abram Szajman
Diretor do Departamento Regional
Luiz Francisco de A. Salgado
Superintendente Universitário e de Desenvolvimento
Luiz Carlos Dourado
M
at
er
ia
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Editora Senac São Paulo
Conselho Editorial
Luiz Francisco de A. Salgado 
Luiz Carlos Dourado 
Darcio Sayad Maia 
Lucila Mara Sbrana Sciotti 
Luís Américo Tousi Botelho
Gerente/Publisher
Luís Américo Tousi Botelho
Coordenação Editorial/Prospecção
Dolores Crisci Manzano 
Ricardo Diana
Administrativo
grupoedsadministrativo@sp.senac.br
Comercial
comercial@editorasenacsp.com.br
Acompanhamento Pedagógico
Mônica Rodrigues dos Santos
Designer Educacional
Patrícia Pinheiro de Sant’Ana
Revisão Técnica
Gustavo Moreira Calixto
Revisão de Texto
Alexandre Napoli
Projeto Gráfico
Alexandre Lemes da Silva 
Emília Corrêa Abreu
Capa
Antonio Carlos De Angelis
Editoração Eletrônica
Creali Comunicação e Marketing
Ilustrações
Valdemir Nunes da Costa
Imagens
Adobe Stock Photos
E-book
Rodolfo Santana
Proibida a reprodução sem autorização expressa.
Todos os direitos desta edição reservados à
Editora Senac São Paulo
Rua 24 de Maio, 208 – 3o andar 
Centro – CEP 01041-000 – São Paulo – SP
Caixa Postal 1120 – CEP 01032-970 – São Paulo – SP
Tel. (11) 2187-4450 – Fax (11) 2187-4486
E-mail: editora@sp.senac.br 
Home page: http://www.livrariasenac.com.br
© Editora Senac São Paulo, 2022
Sumário
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Capítulo 1
Estrutura de dados linear 
(vetor), 7
1 Preparação do ambiente, 8
2 Declaração e criação de vetores, 11
3 Resolução de problemas utilizando 
vetores, 19
4 Utilização de funções com 
vetores, 23
Considerações finais, 26
Referências, 27
Capítulo 2
Estrutura de dados 
bidimensional (matriz), 29
1 Declaração e criação de 
matrizes, 30
2 Resolução de problemas 
utilizando matrizes, 34
3 Utilização de funções com 
matrizes, 39
Considerações finais, 47
Referência, 47
Capítulo 3
Manipulação de arquivos em 
CSharp, 49
1 Utilização de arquivos em 
CSharp, 50
2 Leitura de dados em um arquivo, 54
3 Escrita de dados em um arquivo, 62
Considerações finais, 64
Referência, 65
Capítulo 4
Algoritmos de busca em 
vetores, 67
1 Busca linear, 68
2 Busca binária, 70
3 Conceitos de análise de 
algoritmos, 74
Considerações finais, 78
Referências, 78
Capítulo 5
Algoritmos de ordenação 
elementares, 79
1 Ordenação pelo método bolha, 80
2 Ordenação por seleção, 83
3 Ordenação por inserção, 85
Considerações finais, 87
Referências, 88
Capítulo 6
Algoritmos recursivos, 89
1 Definição de um problema 
recursivo, 90
2 Estratégia para escrever um 
algoritmo recursivo, 95
3 Teste de mesa para um algoritmo 
recursivo, 99
Considerações finais, 104
Referências, 105
6 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Capítulo 7
Algoritmos de ordenação 
eficientes, 107
4 MergeSort – execução e análise de 
complexidade, 108
5 QuickSort – execução e análise de 
complexidade, 120
Considerações finais, 137
Referências, 138
Capítulo 8
Tipos abstratos de dados, 139
1 Definição e utilização de TAD, 140
2 Definição de classes, atributos, 
métodos e construtores, 142
3 Implementação de TAD utilizando 
classes, 146
Considerações finais, 151
Referência, 152
Sobre o autor, 155
7
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Capítulo 1
Estrutura de dados 
linear (vetor)
Quando é necessário armazenar temporariamente dados durante 
a execução de programas, recorremos a variáveis como espaços em 
memória. Ao longo da execução de um programa, diversas variáveis 
podem estar em uso, muitas das quais podem apresentar relação entre 
si (por exemplo, diferentes variáveis para armazenar a nota ou o nome 
de cada aluno de uma turma). Dependendo da quantidade de alunos a 
ser tratada nesse programa, é necessário criar muitas variáveis.
Essa declaração manual de diversas variáveis, além de ser trabalho-
sa, por se basear em um processo manual repetitivo de criar diferentes 
variáveis com nomes similares (por exemplo, nota1, nota2, etc.), pode 
8 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ado 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
incorrer em erros de digitação ao nomear as variáveis ou atribuir valo-
res, levando a problemas na lógica da execução do programa.
Para minimizar esse problema, há o vetor, que, como vamos conferir 
em mais detalhes ao longo deste capítulo, é uma estrutura muito utiliza-
da para simplificar o processo de criação de diversas variáveis usadas 
para armazenar valores similares. A seguir, aprenderemos a criar esses 
vetores, inserir valores e recuperá-los. Serão abordados alguns proble-
mas em que o uso de vetores é uma boa escolha, além de ser a forma 
mais eficiente de percorrer todas as posições dessa estrutura. Por fim, 
veremos como utilizar vetores como parâmetro e retorno de funções.
A compreensão da utilização de vetores é essencial para o desen-
volvimento de sua habilidade com lógica de programação. Mas não se 
preocupe: esse é um assunto simples que será abordado em detalhes 
a seguir.
1 Preparação do ambiente
Antes de avançar para o novo conteúdo, é preciso definir a ferramen-
ta a ser utilizada no desenvolvimento e na execução dos programas. 
Essas ferramentas são conhecidas como ambientes de desenvol-
vimento integrado ou, em inglês, integrated development environments 
(IDEs). Aqui, adotaremos a linguagem de programação C# (lê-se C sharp) 
para o desenvolvimento dos códigos; portanto, é preciso escolher um IDE 
que suporte essa linguagem. Um IDE muito utilizado, e que recomenda-
mos, é o Microsoft Visual Studio – você pode baixar gratuitamente a ver-
são Comunidade (ou Community), que traz todos os recursos necessários 
para a compilação e execução dos projetos em C# (MICROSOFT, 2022).
Ao iniciar o Microsoft Visual Studio, deve-se criar um novo projeto 
para cada programa que será desenvolvido. A figura 1 indica, primeira-
mente, a utilização do caminho Arquivo > Novo > Projeto... 
9Estrutura de dados linear (vetor)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Figura 1 – Página inicial do Microsoft Visual Studio
Em seguida, é preciso dar um nome para o novo projeto, como indi-
cado na figura 2.
Figura 2 – Janela de novo projeto
Observe a estrutura de código que será criada, exemplificada na fi-
gura 3.
10 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Figura 3 – Código padrão de um projeto recém-criado
Não se deve alterar, apagar ou renomear essa estrutura de códigos. 
Todos os códigos apresentados a seguir deverão ser inseridos entre a 
abertura de chaves ( { ), presente na linha 8, e o fechamento de chaves 
( } ), presente na linha 10. Claramente, conforme for inserida mais de 
uma linha de código, o fechamento das chaves passará para as linhas 
de baixo. Portanto, fique atento para não alterar nenhuma das oito pri-
meiras e não remover nenhuma das três últimas linhas (que são três 
fechamentos de chaves).
Conforme novos códigos são apresentados, deve-se apagar a linha 9 
dessa estrutura, removendo, portanto, a seguinte linha de código:
Console.WriteLine("Hello World!");
 A partir dessa linha, que agora deve estar em branco, é preciso seguir 
inserindo os códigos apresentados na sequência, exceto em algumas si-
tuações, para as quais serão fornecidas outras orientações.
Por fim, para executar o programa, é necessário pressionar CTRL + F5. 
Uma janela aparecerá com o resultado da execução, conforme mostrado 
na figura 4.
Figura 4 – Janela (console) gerada para mostrar o resultado da execução do programa
11Estrutura de dados linear (vetor)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
PARA SABER MAIS 
Você pode utilizar qualquer IDE que já conheça e pelo qual tenha prefe-
rência. Aqui, apenas foi apresentada uma opção de ferramenta para ser 
utilizada na continuidade deste estudo. Também não é necessário baixar 
e instalar um IDE, podendo-se optar por uma execução on-line, direta-
mente em um site, pelo navegador. Entre os diversos sites que permitem 
a digitação e execução de códigos em C# (além de outras linguagens), 
estão o Replit (REPLIT, 2022) e o .NET Fiddle (ENTECH SOLUTIONS, 2022).

2 Declaração e criação de vetores 
Todo programa faz uso de variáveis, que são posições de memória 
com um nome e a capacidade de armazenar determinado tipo de va-
lor. Podemos imaginar uma variável como uma gaveta que recebe uma 
etiqueta chamada “roupas” (o nome da gaveta, por si só, permite supor 
o que há dentro dela, sem necessidade de abri-la). Essa gaveta servirá 
para armazenar somente roupas (o tipo de conteúdo) e, dentro dela, 
será guardada uma quantidade de roupas (o conteúdo, ou seja, o valor 
da gaveta). A figura 5 ilustra esse exemplo.
Figura 5 – Representação de uma variável por meio de uma gaveta
Valor a ser armazenado é o 
conteúdo da gaveta, ou seja, o que 
vai ser guardado dentro da variável.
Tipo de dado é “roupa”, ou 
seja, o formato do valor que é 
armazenado nessa variável.
Nome da variável é “roupas”. 
Indica com facilidade a que se refere 
o valor armazenado na gaveta.
ROUPAS
12 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Quando abstraímos o conceito de uma gaveta do mundo real para 
a programação, utilizamos o conceito de variável. Não temos mais ca-
misas, calçados ou demais itens físicos para armazenar em um pro-
grama; portanto, são outros tipos de conteúdo que armazenamos em 
variáveis, com valores que podem ser processados em código. Esses 
diferentes tipos de valor são chamados de “tipos de dados”. A tabela 1 
indica alguns dos principais tipos de dados primitivos da linguagem de 
programação C#.
Tabela 1 – Tipos de dados em C# 
DESCRIÇÃO REPRESENTAÇÃO EM C# VALORES POSSÍVEIS DE ARMAZENAR
Inteiro int -2.147.483.648 até 2.147.483.647
Inteiro long
-9.223.372.036.854.775.808 até 
9.223.372.036.854.775.807
Decimal double ±5.0 × 10−324 até ±1.7 × 10308
Caractere char Unicode UTF-16 (U+0000 até U+FFFF)
Lógico bool true ou false
A partir dessa tabela, podemos montar um exemplo com variáveis 
para representar os dados de uma pessoa.
Uma variável chamada altura é do tipo double e pode receber o va-
lor 1,80.
Uma variável chamada peso é do tipo int e recebe o valor 75.
Uma variável chamada quitacao_eleitoral é do tipo bool e recebe o 
valor true.
A seguir, são ilustradas, na linguagem C#, a declaração e a atribuição 
dessas três variáveis:
13Estrutura de dados linear (vetor)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
double altura = 1.80;
int peso = 75;
bool quitacao_eleitoral= true;
Porém, em algum momento, um programa poderá ter diversas variá-
veis usadas para a mesma finalidade. Observe, por exemplo, o código a 
seguir, no qual três variáveis possuem a finalidade de armazenar o valor 
da nota de diferentes alunos:
double nota_aluno_1 = 8.7;
double nota_aluno_2 = 5.4;
double nota_aluno_3 = 6.2;
double media = (nota_aluno_1 + nota_aluno_2 + nota_aluno_3) / 3;
Nesse trecho, deseja-se calcular a média das notas de todos os alu-
nos de uma turma. Para isso, é necessário fazer a declaração de uma 
nova variável para armazenar cada nota. Nesse exemplo, temos apenas 
três alunos, mas, pensando em uma sala de aula real, poderia haver 
muitos mais, o que se refletiria em mais linhas de código.
Contudo, podemos observar que todas essas variáveis têm uma re-
lação entre si: elas são utilizadas para armazenar o mesmo tipo de dado 
e para a mesma finalidade. São dados do tipo double que representam 
notas, e cada variável corresponde à nota de um aluno diferente.
Em casos assim, podemos agrupar as variáveis semelhantes em 
uma única estrutura chamada vetor, ou array unidimensional, reduzindo 
o código e ganhando clareza na relação entre as variáveis.
Se uma única variável pode ser comparada a uma gaveta, um vetor 
pode ser comparado a um gaveteiro. A primeira gaveta poderia guar-
dar as roupas de uma pessoa, a segunda gaveta, as roupas de outra, e 
assim por diante, ou seja, cada gaveta corresponderia a uma variável 
diferente. A figura 6 ilustra esse exemplo.
14 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Figura 6 – Representação de um vetor por meio de um gaveteiro
ROUPAS PAI
ROUPAS FILHO
ROUPAS MÃE
Tipo de dado é “roupa” 
para todas as gavetas.
Cada gaveta é equivalente a 
uma variável distinta e pode ter 
um valor (conteúdo) diferente.
Em um vetor, cada uma dessas “gavetas” é chamada de posição, e 
cada posição é indicada por um índice. A primeira posição do vetor é 
indicada pelo índice zero (0), e a última posição, pelo índice que corres-
ponde ao tamanho do vetor – 1. Na figura 7, é feita uma comparação 
entre três variáveis e um vetor que representa o mesmo conjunto des-
sas variáveis, e que, portanto, poderia ser utilizado para substituir todas 
elas. Na figura, é indicado o conteúdo (valor) de cada variável e, para o 
vetor, são indicados todos os seus valores, as posições e os índices de 
cada posição. Um vetor que armazena três valores possui um tamanho 
3, sendo o valor da primeira posição armazenado no índice 0 e o último 
valor armazenado no índice 2, que corresponde ao tamanho do vetor (3 
menos 1).
15Estrutura de dados linear (vetor)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Figura 7 – Comparação entre variáveis e vetor
VARIÁVEIS VETOR
TIPO: INTEIRO
NOME VALORES NOME
POSIÇÃO
ÍNDICE
TAMANHO: 3
TIPO: INTEIRO
VALORES
 variável 1 variáveis5 5
1 2 3
0 1 2
3
3
9
9
 variável 2
 variável 3
Na linguagem C#, temos algumas alternativas para a criação do vetor.
2.1 Declaração e atribuição dos valores em uma única 
instrução
Neste caso, no momento de criação do vetor, já se possuem todos 
os dados que serão inseridos em todas as suas posições.
Para isso, utiliza-se a regra expressa a seguir:
tipo_de_dado[ ] nome_do_vetor = { valor_pos_0, valor_pos_1, ... , valor_ultima_pos} ;
IMPORTANTE 
A indicação dos colchetes logo após o tipo de dado indica que essa 
estrutura é um vetor, e não mais uma única variável.
 
Exemplo de criação de vetor na linguagem C#:
double[] notas = {8.7,5.4,6.2};
16 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.No código anterior, foi criado um vetor de números racionais (double) 
chamado notas, de tamanho 3, no qual a primeira posição (índice 0) 
armazena o valor 8.7, a segunda posição (índice 1) armazena 5.4 e a 
terceira posição (índice 2) armazena 6.2.
Assim como em qualquer variável, é permitido alterar e recuperar o 
valor armazenado em uma posição do vetor. Isso é feito de maneira 
muito similar a quando usamos uma única variável. O único detalhe adi-
cional é a necessidade de informar o índice no vetor em que se deseja 
inserir ou recuperar o valor.
Assim, para inserir um valor em uma posição específica do vetor, é 
utilizada a seguinte regra:
nome_do_vetor[índice_desejado] = novo_valor;
Em código, um novo valor é atribuído a uma posição específica do 
vetor da seguinte forma:
notas[1] = 6.4;
No exemplo anterior, o valor 6.4 substitui o valor 5.4 que aparecia no 
índice 1 do vetor notas. 
E para recuperar o valor de uma posição específica, basta utili-
zar o nome do vetor acrescido de colchetes, indicando o índice a ser 
acessado:
outra_variavel = nome_do_vetor[índice_desejado];
Em C#, o acesso e o uso do valor armazenado em uma posição do 
vetor são feitos como demonstrado a seguir:
double nota_do_jose = notas[1];
17Estrutura de dados linear (vetor)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Nesse exemplo, se supomos que a segunda posição do vetor 
(índice 1) representa a nota do aluno José, podemos criar uma variável 
exclusiva para receber o valor da sua nota armazenada no vetor, assim 
como copiar o valor de uma variável para outra.
IMPORTANTE 
O vetor sempre começa com sua primeira posição apontada pelo índice 
0. A segunda posição, portanto, é indicada pelo número 1, e assim por 
diante. Outro detalhe importante é que, em todas as posições do vetor, 
só pode haver o mesmo tipo de dado.
 
2.2 Declaração do vetor com o tamanho definido para 
posteriormente receber os valores
Nesta abordagem, primeiramente é declarado o vetor e posteriormen-
te são atribuídos os valores de cada posição. Esse procedimento é bas-
tante comum em um programa interativo, no qual o usuário insere o valor 
de cada uma das posições, não cabendo ao programador definir esses 
valores diretamente no código. O método também é muito utilizado quan-
do os dados são obtidos em um momento posterior à criação do vetor.
Para essa abordagem, primeiro é preciso declarar o vetor da seguin-
te forma:
tipo_de_dado[ ] nome_do_vetor = new tipo_de_dado[tamanho_do_vetor];
Depois, deve-se atribuir o valor de cada uma das posições, como de-
monstrado no item anterior.
Em código, a declaração do vetor pode ser feita da seguinte forma:
double[] notas = new double[3];
18 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.Perceba que, nesse caso, o número 3 representa o tamanho do vetor. 
Assim, está sendo criado um vetor de três posições, começando no índi-
ce 0 e terminando no índice 2. É precisoatenção para repetir o mesmo 
tipo de dado nos dois lados do operador de atribuição.
2.3 Declaração do vetor sem predefinição do tamanho
Dessa forma, primeiramente declara-se o vetor, depois define-se o ta-
manho do vetor e, por fim, o valor de cada posição. Esse método é utili-
zado quando o programador sabe que será necessário um vetor (pois o 
programa lidará com uma sequência de dados do mesmo tipo), mas não 
sabe qual será a quantidade, ou seja, qual deverá ser o tamanho do vetor.
O método divide a declaração do vetor em duas partes. Na primeira, 
define-se apenas o nome do vetor:
tipo_de_dado[ ] nome_do_vetor;
Na segunda, após a definição do tamanho do vetor, é concluída sua 
criação:
nome_do_vetor = new tipo_de_dado[tamanho_do_vetor];
Em código, essa criação seria feita da seguinte forma:
double[] notas;
notas = new double[3];
Contudo, é mais comum que a declaração do vetor não seja concluí-
da com um número explícito. Usualmente, após a declaração parcial do 
vetor, uma variável recebe um valor que indica qual deve ser o tamanho 
do vetor. Essa variável é, então, utilizada para finalizar a declaração do 
vetor, como no exemplo a seguir:
19Estrutura de dados linear (vetor)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
double[] notas;
int tamanho_vetor = valor_digitado_pelo_usuario;
notas = new double[tamanho_vetor];
PARA PENSAR 
Uma variável representa um único valor; portanto, seu nome tende a 
ser apresentado no singular. Um vetor, por outro lado, representa um 
conjunto de valores; por isso, seu nome costuma ser apresentado no 
plural.
 
3 Resolução de problemas utilizando vetores
A utilização de vetores é muito comum quando é necessário acessar 
os dados de todas as posições para realizar alguma operação com es-
ses valores em conjunto.
Tomemos como exemplo o vetor de notas criado no subcapítulo 2:
double[] notas = {8.7,5.4,6.2};
Uma operação comum seria calcular a média de todos esses dados 
para obter a média da turma, como no exemplo a seguir:
double media = (notas[0] + notas[1] + notas[2]) / 3;
Assim, estaríamos somando todos os valores de cada posição e di-
vidindo-os por 3, que é a quantidade total de valores do vetor ou, ainda, 
o seu tamanho.
Porém, essa é uma abordagem que adotamos para calcular a mé-
dia de variáveis isoladas. Pense na dificuldade que seria calcular essa 
média conforme a quantidade de variáveis aumenta para dezenas ou 
20 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.mesmo centenas... Nesse caso, seria necessário adicionar cada uma 
delas na fórmula da média!
Como todos os valores de notas estão em um mesmo vetor, há uma 
forma mais prática de fazer esse cálculo. Para isso, vamos utilizar a 
estrutura de repetição para ou, em código, o comando for:
double soma = 0;
for (int i = 0; i < 3; i++)
soma += notas[i];
double media = soma / 3;
Nesse código, é criada uma variável para armazenar a soma de todas 
as notas. Em seguida, é utilizado o comando for para percorrer todas as 
posições do vetor. Observe que, para isso, a variável de controle começa 
no índice 0 e vai até o índice anterior ao tamanho do vetor (que corres-
ponde à sua última posição). Dentro do for, a cada iteração, é acessada 
uma nova posição do vetor (começando em 0 e indo até a última), e 
o valor nessa posição é acrescentado à variável soma. Encerradas as 
repetições do for, a variável soma é dividida por 3, que equivale à quanti-
dade de notas. O valor resultante é atribuído à variável media.
Um último ajuste pode ser feito nesse algoritmo para deixá-lo ainda 
mais versátil:
double soma = 0;
for (int i = 0; i < notas.Length; i++)
soma += notas[i];
double media = soma / notas.Length;
Perceba que o valor 3, que indicava o tamanho do vetor, foi substitu-
ído por notas.Length (acrescentou-se .Length ao nome do vetor). Esse 
comando busca diretamente no vetor notas o seu tamanho ou com-
primento (em inglês, length) e, portanto, equivale exatamente ao valor 
3. A vantagem de usá-lo é que, se você alterar a declaração do vetor, 
aumentando seu tamanho e acrescentando mais um valor, não será 
21Estrutura de dados linear (vetor)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
necessário ajustar o valor numérico (3) usado no algoritmo anterior, tan-
to no for quanto no cálculo da média. Portanto, o algoritmo mostrado 
no exemplo anterior conseguirá calcular a média dos dados de um vetor 
independentemente do tamanho.
IMPORTANTE 
Podemos nos referir a cada espaço de armazenamento em um vetor 
como “posição”, indicando o primeiro espaço como 1 (primeira posição) 
e o último espaço com o valor do tamanho do vetor. Porém, em códi-
go, precisamos utilizar o “índice”, que conceitualmente tem a mesma 
finalidade de indicar um espaço específico do vetor. O primeiro espaço, 
no entanto, é representado pelo valor 0 (índice zero), e o último índice 
corresponde ao tamanho do vetor – 1.
 
Assim como utilizamos o comando for para percorrer um vetor, re-
cuperando o valor de cada posição a fim de realizar alguma operação, 
podemos usá-lo também para auxiliar no preenchimento do vetor, per-
mitindo que um usuário escolha os valores que serão inseridos em cada 
posição. Confira o exemplo a seguir:
Console.WriteLine("Defina quantos alunos há na turma:");
int tamanho = int.Parse(Console.ReadLine());
double[] notas = new double[tamanho];
//Armazenando as notas
for (int i = 0; i < notas.Length; i++) {
 Console.WriteLine("Digite a nota do aluno " + (i + 1) + 
":");
 notas[i] = double.Parse(Console.ReadLine(), 
CultureInfo.InvariantCulture);
}
//Recuperando as notas para calcular a média
double soma = 0;
for (int i = 0; i < notas.Length; i++) {
 Console.WriteLine("Nota do aluno " + (i + 1) + 
": "+notas[i]);
soma += notas[i];
22 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
}
double media = soma / notas.Length;
Console.WriteLine("Média das notas na turma é: "+media);
Nesse algoritmo, o usuário é solicitado a digitar a quantidade de alu-
nos na turma; esse valor será armazenado na variável tamanho. Em se-
guida, um vetor chamado notas será criado com esse tamanho.
Depois, é utilizado um for para percorrer todos os índices do vetor 
(de 0 até o índice anterior ao tamanho do vetor, ou seja, seu último ín-
dice). Para cada iteração, o usuário será solicitado a digitar a nota do 
aluno correspondente àquele índice. Nesse ponto, foi feito um ajuste 
na impressão em tela para mostrar o primeiro aluno começando pelo 
valor 1 em vez de 0 (apenas por uma questão de convenção visual). O 
valor digitado pelo usuário é armazenado no respectivo índice do vetor 
e, assim, é repetido para todos os índices.
Ao finalizar o preenchimento de todas as notas no vetor, realiza-se 
a impressão dessas notas armazenadas. Para isso, novamente é utili-
zada a estrutura for. Todos os índices são acessados, um em cada ite-
ração, imprimindo o valor armazenado naqueleíndice. Também a cada 
iteração, o valor armazenado é adicionado à variável soma. Assim, ao 
terminar de acessar todos os índices, todos os valores terão sido adi-
cionados a essa variável. Depois de encerrado o for, a variável soma é 
dividida pelo tamanho do vetor, de modo a obter a média das notas da 
turma. A figura 8 mostra a tela de interação desse programa.
Figura 8 – Janela (console) gerada para mostrar o resultado da execução do programa
23Estrutura de dados linear (vetor)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Portanto, o for é muito utilizado junto de vetores, pois facilita bastante 
a manipulação dessa estrutura e aumenta as possibilidades de seu uso.
4 Utilização de funções com vetores
Vetores podem ser manipulados como outras variáveis e, inclusive, 
utilizados como argumentos e retornos de funções.
No exemplo a seguir, há uma demonstração do uso de função com 
um vetor como parâmetro. Nesse caso, um vetor contendo as notas 
dos alunos será passado como argumento de uma função responsável 
por calcular a média e retornar esse valor, que será então armazenado 
e impresso em tela.
A seguir, o código que pode ser inserido no método main da classe 
principal:
double[] notas = { 8.7, 5.4, 6.2 };
double media = calcularMedia(notas);
Console.WriteLine("A média da turma é: "+media);
Perceba que o nome do vetor foi usado como argumento da função 
chamada calcularMedia, como se faria com um tipo de dado primitivo.
A seguir, o código da função calcularMedia, que pode ser criada na 
classe principal, abaixo do método main:
static double calcularMedia(double[] notas)
{
double soma = 0;
for (int i = 0; i < notas.Length; i++)
soma += notas[i];
return soma / notas.Length;
}
Nessa função, há o retorno de um valor do tipo double que represen-
ta a média das notas. Na assinatura da função, o parâmetro de entrada 
24 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.é um vetor, que é representado de forma semelhante aos demais tipos 
de dados. É necessário indicar seu tipo, acrescido de colchetes, para 
expressar que se trata de um vetor, e adicionar o nome da variável que 
será utilizada dentro do corpo da função para representar esse vetor de 
entrada. Dentro da função, ocorre algo já visto no subcapítulo anterior: 
o vetor tem todas as suas posições acessadas, os valores de cada uma 
são somados e, no final, obtém-se a média desses valores, sendo a mé-
dia retornada pela função.
Outra forma de utilizar vetores em funções é como o retorno de uma 
função. O exemplo a seguir é de uma função que recebe um vetor de 
entrada e inverte os valores de todas as posições (o valor da primeira 
posição é trocado com o valor da última posição, o valor da segunda po-
sição é trocado com o valor da penúltima posição, e assim por diante).
A seguir, o código a ser inserido no método main:
double[] notas = { 8.7, 5.4, 6.2 };
inverterVetor(notas);
for (int i=0;i<notas.Length;i++)
Console.Write(notas[i]+"|");
Console.WriteLine();
No trecho anterior, o vetor de notas é passado como argumento da 
função inverterVetor. Essa função inverte os dados do vetor original, por 
isso não há necessidade de um retorno. Por fim, são impressos todos 
os novos valores desse vetor para atestar que os valores originais foram 
realmente invertidos.
Resta criar a função inverterVetor. Para isso, logo abaixo do método 
main, insira o seguinte código:
static void inverterVetor(double[] vetor)
{
25Estrutura de dados linear (vetor)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
double temp;
for (int i = 0; i < vetor.Length/2; i++){
temp = vetor[i];
vetor[i] = vetor[vetor.Length - 1 - i];
vetor[vetor.Length - 1 - i] = temp;
}
}
Na assinatura dessa função, seu retorno corresponde a um vetor de 
double. No corpo da função, são percorridas as posições do vetor de en-
trada até a posição intermediária, pois, quando a execução do algoritmo 
alcançar essa posição, já terão sido invertidos todos os valores. 
O processo de inversão equivale a armazenar o valor da posição atu-
al em uma variável temporária; obter o valor da posição equivalente no 
final do vetor e armazená-lo na posição atual; e, por último, armazenar 
o valor da variável temporária na posição final equivalente. Esse vetor 
com as posições invertidas é, então, retornado pela função.
Quando um vetor for passado como argumento de uma função e 
alterações de dados forem realizadas nesse vetor, dentro da função, na 
verdade será alterado o vetor original fora da função. Observe o trecho 
de código abaixo:
double[] n = notas;
Mesmo que seja copiado um vetor para outro, e sejam alterados os 
valores do vetor n, também serão alterados os respectivos valores do 
vetor notas. Dessa forma, está sendo criada uma cópia da referência 
em memória do vetor original, e não dos seus valores. Assim, ambos os 
vetores apontam para o mesmo endereço de memória, sendo, por isso, 
o mesmo vetor (DEITEL, 2003).
Portanto, se quiser criar uma cópia de um vetor, de forma a poder 
alterar os dados nessa cópia sem interferir no original, você terá de criar 
esse novo vetor copiando valor a valor do vetor original, como no código 
a seguir:
26 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
double[] notas = { 8.7, 5.4, 6.2 };
double[] n = new double[notas.Length];
for (int i = 0; i < notas.Length; i++)
 n[i] = notas[i];
Dessa forma, você poderá operar sobre o vetor n sem receio de alte-
rar o vetor notas.
Considerações finais
A utilização de vetores é muito importante para a simplificação e a 
clareza de um código. Além disso, é essencial associar o uso de uma 
estrutura de repetição como o for para facilitar o acesso a todas as 
posições do vetor quando é necessário preencher ou recuperar todos 
os seus valores.
Os vetores podem armazenar qualquer tipo de dado, porém o mes-
mo tipo de dado declarado na criação do vetor tem que ser armaze-
nado em todas as suas posições. Também é importante lembrar que, 
ao acessar uma posição do vetor, indicamos seu índice, e o índice da 
primeira posição começa com o valor zero. Por representarem um 
conjunto de valores, os vetores ainda podem ser usados em funções, 
com argumento ou retorno, assim como é feito com os tipos de dados 
primitivos (variáveis isoladas).
Pratique a criação de vetores com diferentes tipos de dados. 
Manipule seus dados por meio de funções. Faça cópia de vetores para 
se acostumar a não apontar para a mesma referência do vetor origi-
nal. Essa prática é essencial para reforçar sua habilidade com vetores, 
o que será muito útil no avanço do estudo de programação.
27Estrutura de dados linear (vetor)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Referências
DEITEL, H. M. et al.C#: como programar. São Paulo: Pearson Universidades, 
2003.
ENTECH SOLUTIONS. Dot net fiddle. C# online compiler. Dunellen, NJ: ENTech 
Solutions, c2022. Disponível em: https://dotnetfiddle.net/. Acesso em: 12 fev. 
2022.
MICROSOFT. Visual Studio. Versão 17.2. [S. l.]: Microsoft, c2022. Disponível em: 
https://visualstudio.microsoft.com/pt-br/downloads/. Acesso em: 12 fev. 2022.
REPLIT. The collaborative browser based IDE. [S. l.]: Replit, c2022. Disponível 
em: https://replit.com/. Acesso em: 12 fev. 2022.
https://visualstudio.microsoft.com/pt-br/downloads/
29
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Capítulo 2
Estrutura de dados 
bidimensional 
(matriz)
O conceito de matrizes expande a definição de vetores. Enquanto os 
vetores funcionam como uma “lista” unidimensional de diversas posi-
ções, “uma ao lado da outra”, para armazenar diversos valores, as ma-
trizes funcionam como uma “tabela”, permitindo armazenar os valores 
em diversas posições distribuídas por suas linhas e colunas. Por isso, 
recebem a definição de bidimensionais.
Essa estrutura auxilia na representação de problemas que dependem 
da disposição bidimensional dos dados. Exemplos disso são as coorde-
nadas de diferentes elementos em um mapa e as posições de peças em 
um tabuleiro. Podemos até mesmo representar uma imagem por meio 
de uma matriz na qual cada posição guarda um valor que representa a 
cor de um pixel.
30 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
A forma de criação dessas estruturas é muito similar à dos vetores, 
e veremos exemplos práticos delas ao longo deste capítulo, no qual em-
pregaremos matrizes no desenvolvimento da lógica de jogos de tabulei-
ro. Veremos como criar matrizes, acessar seus valores, percorrer todas 
as suas posições, aplicá-las em problemas práticos e usá-las por meio 
de funções.
A depender das necessidades do programa a ser desenvolvido, as 
matrizes são um grande recurso. Ter uma boa compreensão do uso 
dessas estruturas é muito importante para identificar a possibilidade de 
sua aplicação em um problema e de uma implementação bem-sucedi-
da em seu código.
1 Declaração e criação de matrizes
Como já visto, vetores são estruturas que permitem armazenar di-
versos valores em cada posição, sendo todos eles de um mesmo tipo. 
Uma representação do vetor é uma sequência de espaços, um ao lado 
do outro, em que cada um é uma posição a armazenar um valor. Por 
essa representação sequencial, começando no índice 0 e terminando 
no índice que corresponde ao tamanho do vetor – 1, podemos nos re-
ferir ao vetor como uma estrutura de dados linear ou uma estrutura de 
dados unidimensional. Também é comum o termo array unidimensional.
Embora o vetor auxilie muito no agrupamento de valores que pos-
suem alguma relação entre si, em alguns casos é necessária a repre-
sentação de valores em mais de uma dimensão. Para isso, é preciso 
utilizar uma estrutura de dados bidimensional, ou array bidimensional, 
também conhecida simplesmente por matriz.
A figura 1 traz um exemplo da representação de um vetor e de uma 
matriz, indicando, em cada posição, o índice de cada um.
31Estrutura de dados bidimensional (matriz)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Figura 1 – Exemplo de vetor e matriz
VETOR
NOME
POSIÇÃO
ÍNDICE
TAMANHO: 3
TIPO: INTEIRO
VALORES
 variáveis
1 2 3
0 1 2
35 9
MATRIZ
NOME
ÍNDICES
1ª coluna última coluna
TAMANHO: 4x3
TIPO: INTEIRO
VALORES
 variáveis (0,0) (0,1) (0,2)
(1,0) (1,1) (1,2)
(2,0) (2,1) (2,2)
11 8 2
0 15 7
35
(3,0) (3,1) (3,2)
2 9 10
9
1ª
 li
nh
a
úl
tim
a 
lin
ha
Em um vetor, basta um valor para identificar cada posição, pois, con-
forme discutido, ele é uma estrutura de dimensão única. Como a matriz 
possui duas dimensões, são necessários dois valores para indicar cada 
posição: um para a linha e outro para a coluna. A matriz também começa 
pelo índice 0 e, por isso, sua primeira posição é indicada por (0,0), sendo 
o primeiro valor o índice da linha e o segundo valor o índice da coluna.
A forma de declaração de uma matriz segue as mesmas regras da for-
ma de criação de um vetor, como já visto. O único detalhe a atentar é que, 
agora, em vez de haver somente a abertura e o fechamento de colchetes, 
deve-se colocar uma vírgula no meio desse par de colchetes para indicar 
que se trata de uma estrutura de duas dimensões (matriz). 
Para comparação, ao criar um vetor com posições já preenchidas, 
basta declarar:
double[] notas = {8.7,5.4,6.2};
32 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Para criar uma matriz com diversos valores, deve-se indicar uma 
vírgula no meio do par de colchetes ( [,] ) e, na atribuição do conjunto 
de valores, criar diversas linhas com valores. Conforme foi feito para 
o vetor, uma linha com valores está entre chaves, e os valores estão 
separados por vírgula. Para a matriz, diversas dessas linhas devem ser 
criadas (conforme a quantidade de linhas da matriz) e separadas por 
vírgula, e todas devem estar entre outro par de chaves. Observe o exem-
plo a seguir:
double[,] notas = { { 8.7, 5.4, 6.2 },
{ 3.8, 2.7, 8.5 },
{ 9.1, 0.9, 4.2 },
{ 7.1, 1.8, 8.8 } };
Não é necessário representá-la dessa forma; é possível deixar todos 
os valores em uma única linha. No entanto, nessa representação, pode-
mos visualizar facilmente que se trata de uma matriz 4 x 3 (4 linhas x 3 
colunas).
De forma similar ao vetor, podemos alterar o valor de uma posição 
específica na matriz, desde que sejam apontados corretamente os dois 
índices necessários.
IMPORTANTE 
Na matriz, o primeiro índice corresponde à linha e o segundo, à coluna. 
Assim como no vetor, os índices começam por zero.
 
No exemplo a seguir, a nota na linha de índice zero e coluna de índice 
1 (valor de 5.4) receberá o valor de 6.4:
notas[0,1] = 6.4;
33Estrutura de dados bidimensional (matriz)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
A seguir, o valor da última linha e última coluna (8.8) será copiado 
para outra variável:
double nota_do_antonio = notas[3, 2];
Também é possível fazer a declaração de uma matriz vazia para pre-
encher os valores posteriormente. Em código, a declaração do vetor por 
esse método pode ser feita da seguinte forma:
double[] notas = new double[3];
Para declarar uma matriz, basta indicar o tamanho das duas dimen-
sões: primeiro, a quantidade de linhas; depois, a quantidade de colunas 
dentro dos colchetes.
double[,] notas = new double[4,3];
Por fim, pode-se realizar a declaração da matriz sem um tamanho 
predefinido e informá-lo posteriormente. Em código, a criação do vetor 
pode ser feita assim:
double[] notas;
notas = new double[3];
Para criar a matriz, a abordagem equivalenteé:
double[,] notas;
notas = new double[4,3];
Desse modo, podemos declarar e atribuir valores a matrizes de for-
ma muito similar à dos vetores. A única diferença está em que, ao lidar 
com estruturas de duas dimensões, devemos sempre informar dois 
índices para identificar corretamente a posição desejada na matriz.
34 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
PARA SABER MAIS 
Além das estruturas de dados unidimensionais e bidimensionais, po-
demos criar estruturas de dados multidimensionais. É possível formar 
uma estrutura de três dimensões ( [,,] ) ou mais utilizando três índices ou 
mais, seguindo a mesma analogia feita nesta seção.

Para finalizar, esses arrays demonstrados são denominados retangu-
lares, pois possuem o mesmo número de colunas para todas as linhas. 
Já nos arrays irregulares, cada linha pode ter uma quantidade diferente 
de colunas (DEITEL, 2003). Porém, na continuidade deste livro, utilizare-
mos a implementação de arrays retangulares, que, conforme demons-
trado, atendem à maior parte dos problemas de programação.
2 Resolução de problemas utilizando matrizes
As matrizes são estruturas ideais para a representação de situações 
que necessitam de coordenadas, como jogos de tabuleiro. Por serem 
baseados em tabuleiros com linhas e colunas, damas, xadrez e Go são 
alguns exemplos de jogos que podem usar matrizes para a representa-
ção da posição das peças.
Veremos nesta seção uma implementação lógica do jogo de campo 
minado. Assim, teremos um exemplo da utilização de matriz e de como 
interagir com essa estrutura para apoiar a finalidade do jogo.
Primeiramente, devemos definir a regra de representação da área do 
jogo. Vamos utilizar uma matriz de 10 x 10, em que haverá uma bandeira 
e cinco bombas. Essa área pode ser representada por uma matriz de ze-
ros; as bombas, pelo número 1; e a bandeira, pelo número 2. A seguir, são 
apresentados os códigos de criação dessa matriz e do campo minado:
35Estrutura de dados bidimensional (matriz)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
 int[,] campo = new int[10,10];//matriz com posições dos elementos do campo
int[,] jogo = new int[10, 10];//matriz que registra ações do jogador
int qtdLinhas = campo.GetLength(0);
int qtdColunas = campo.GetLength(1);
for (int l = 0; l < qtdLinhas; l++)
{
for (int c = 0; c < qtdColunas; c++)
{
campo[l, c] = 0;
jogo[l, c] = -1;
}
}
//Posicionamento aleatório da bandeira
Random gerador = new Random();
int linha = gerador.Next(qtdLinhas);
int coluna = gerador.Next(qtdColunas);
campo[linha, coluna] = 2;
//Posicionamento aleatório das bombas
int bombasPosicionadas = 0;
do
{
linha = gerador.Next(qtdLinhas);
coluna = gerador.Next(qtdColunas);
if (campo[linha,coluna]==0)
{
campo[linha, coluna] = 1;
bombasPosicionadas++;
}
} while (bombasPosicionadas<5);
Duas matrizes são utilizadas nessa implementação: a matriz campo 
é usada para registrar o posicionamento das bombas (pelo número 1), 
da bandeira (pelo número 2) e das posições vazias (pelo número 0); 
a matriz jogo inicia com –1 em todos os campos e é utilizada para a 
visualização do jogador. Conforme o jogador indica posições, elas são 
preenchidas com 0, até a indicação de uma posição com uma bomba 
ou a bandeira. A variável qtdLinhas armazena o tamanho da matriz na 
36 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
primeira dimensão (número de linhas), e a variável qtdColunas, na se-
gunda dimensão (número de colunas).
Em seguida, a matriz campo é percorrida para ter todas as suas posi-
ções inicializadas com 0, enquanto a matriz jogo é inicializada com –1. 
Observe que esse preenchimento é feito com a utilização de duas estru-
turas for, uma dentro da outra. Esta é a forma padrão de percorrer uma 
matriz: enquanto o for externo alterna entre as linhas, o for interno alter-
na entre as colunas. Dessa forma, é possível acessar todas as posições 
da matriz na sequência apresentada na figura 2, que traz um exemplo 
de matriz 5 x 5, com a indicação dos índices de todas as posições e da 
sequência percorrida para acessá-las.
Figura 2 – Sequência para percorrer uma matriz
(0,0)
(1,0)
(2,0)
(3,0)
(4,0)
(1,1)
(2,1)
(3,1)
(4,1)
(1,2)
(2,2)
(3,2)
(4,2)
(1,3)
(2,3)
(3,3)
(4,3)
(1,4)
(2,4)
(3,4)
(4,4)
(0,1) (0,2) (0,3) (0,4)
Depois de preenchidas as duas matrizes, são gerados dois números 
aleatórios: um de linha (entre 0 e qtdLinhas – 1) e outro de coluna (entre 
0 e qtdColunas – 1). Esses números são usados como índices para posi-
cionar a bandeira (número 2) na matriz campo.
Por fim, são geradas cinco bombas (número 1) para serem posi-
cionadas no campo. Um contador registra quantas bombas já foram 
37Estrutura de dados bidimensional (matriz)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
criadas. Novamente, são gerados números aleatórios de linha e coluna, 
mas desta vez é feita uma verificação para garantir que não haja outra 
bomba ou bandeira na mesma posição. Se a posição estiver vazia (nú-
mero 0), a bomba será posicionada.
Tendo sido preparado o campo do jogo, o próximo passo é criar a 
interface de interação do usuário. Para isso, segue o código:
bool fimJogo = false;
do
{
for (int l = 0; l < qtdLinhas; l++)
{
for (int c = 0; c < qtdColunas; c++)
{
 Console.Write(string.Format("{0} ", 
jogo[l, c]));
}
 Console.Write(Environment.NewLine + 
Environment.NewLine);
}
Console.Write("Selecione uma linha [1-10]: ");
linha = Convert.ToInt32(Console.ReadLine()) -1;
Console.Write("Selecione uma coluna [1-10]: ");
coluna = Convert.ToInt32(Console.ReadLine()) -1;
switch (campo[linha, coluna])
{
case 0:
jogo[linha, coluna] = 0;
Console.Write("Continue tentando.\n\n");
break;
case 1:
jogo[linha, coluna] = 1;
Console.Write("BOOOM. Você perdeu.\n\n");
fimJogo = true;
break;
default:
jogo[linha, coluna] = 2;
38 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Console.Write("Parabéns. Você ganhou!\n\n");
fimJogo = true;
break;
}
} while (!fimJogo);
A variável booleana fimJogo indica quando o usuário venceu ou per-
deu a partida, encerrando a interação. A interação ocorre dentro de uma 
estrutura de repetição do-while. Inicialmente, uma estrutura de dois for 
é utilizada para percorrer a matriz jogo, imprimindo todos os seus valo-
res. São impressas exatamente na disposição da matriz 10 linhas e 10 
colunas. Os valores –1 indicam posições ocultas, e os valores 0 indicam 
posições que o usuário escolheu e que estavam vazias. Em seguida, o 
usuário digita um valor de linha e um valor decoluna entre 1 e 10. Então, 
é realizado um teste na posição indicada, mas na matriz campo. Se nes-
sa posição o valor for 0, a matriz jogo, nessa mesma posição, receberá 
o valor 0, e o laço se repetirá para o jogador continuar tentando. Se o 
valor for 1, o que indica a presença de bomba, será mostrada a men-
sagem de que o jogador perdeu, e a variável fimJogo receberá o valor 
true, fazendo com que o laço se encerre. Se o valor for 2, será exibida a 
mensagem de sucesso, e o laço também se encerrará.
IMPORTANTE 
Para percorrer uma matriz, utiliza-se um for dentro de outro. O for mais 
externo percorre as linhas da matriz, e o for mais interno, as colunas. Ao 
apontar para uma posição da matriz dentro do for interno, utilizam-se a 
variável de controle do for externo como indicação da linha e a variável 
de controle do for interno como indicação da coluna.
 
39Estrutura de dados bidimensional (matriz)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
A figura 3 indica um trecho de interação com o jogo desenvolvido.
Figura 3 – Interação com o campo minado
Com essa demonstração, percebemos como utilizar matrizes em 
jogos que possuem tabuleiros ou dimensões e como empregá-las na 
implementação, tanto para a escrita de valores quanto para a leitura.
Agora, propomos que você altere e personalize esse jogo. Como su-
gestão, você pode incluir um contador de jogadas – se o jogador exceder 
o seu limite, perderá. Além disso, você pode definir o tamanho da matriz e 
a quantidade de bombas como variáveis escolhidas pelo jogador.
3 Utilização de funções com matrizes
Assim como os vetores, as matrizes também podem ser usadas 
como argumentos de funções. Vamos conferir um possível cenário 
para esse uso em uma implementação do jogo da velha.
A seguir, o código inicial do jogo:
40 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
char[,] tabuleiro = new char[3, 3];
int linha;
int coluna;
bool fimJogo = false;
int jogador = 1;
int jogada = 0;
//preenchimento da matriz com espaços em branco
for (int l = 0; l < 3; l++)
for (int c = 0; c < 3; c++)
tabuleiro[l, c] = ' ';
do
{
//impressão do tabuleiro atual
imprimirTabuleiro(tabuleiro);
if (jogador == 1)
Console.Write("JOGADOR 1:\n");
else
Console.Write("JOGADOR 2:\n");
Console.Write("Selecione uma linha [1-3]: ");
linha = Convert.ToInt32(Console.ReadLine()) - 1;
Console.Write("Selecione uma coluna [1-3]: ");
coluna = Convert.ToInt32(Console.ReadLine()) - 1;
jogada++;
 //chamada de função para verificar as consequências da 
//jogada realizada
fimJogo = conferirJogada(tabuleiro,linha,coluna,jogador,
jogada);
//troca de jogador
if (jogador == 1)
jogador = 2;
else
jogador = 1;
} while (!fimJogo);
41Estrutura de dados bidimensional (matriz)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Nesse código, é criada uma matriz chamada tabuleiro, de 3 x 3. As 
variáveis linha e coluna armazenam a posição escolhida pelo jogador; a 
variável fimJogo indica se a partida terminou (para sair do laço); a variável 
jogador informa se é a vez do jogador 1 ou do jogador 2; e a variável joga-
da comunica em qual jogada a partida está (são nove jogadas no total). 
Após a inicialização das variáveis, o tabuleiro é preenchido com es-
paços em branco em todas as posições. Em seguida, a execução en-
tra em um laço enquanto a variável fimJogo for false. Esse laço inicia 
chamando uma função para imprimir o tabuleiro, permitindo ao jogador 
visualizar seu estado atual. Em seguida, informa-se por mensagem qual 
jogador deve realizar a jogada. Os valores inseridos pelo jogador são 
armazenados nas variáveis linha e coluna. A contagem de jogadas é 
incrementada. É chamada a função conferirJogada, que possui como 
argumentos a matriz tabuleiro, o valor de linha e coluna da jogada atual, 
a indicação de qual jogador fez a jogada e em qual jogada a partida está. 
O retorno é um booleano que, quando true, indica que o jogo acabou. 
Após o retorno da função, a indicação do jogador é alternada; enquanto 
o resultado dessa função não for true, o laço se repetirá, agora para o 
outro jogador.
Percebemos o uso de duas funções, o que leva o código a ter mais 
clareza quanto às etapas da lógica do algoritmo, permitindo criar fun-
ções a serem reutilizadas em várias partes do programa. Confira, a se-
guir, a função imprimirTabuleiro:
static void imprimirTabuleiro(char[,] tabuleiro)
{
for (int l = 0; l < 3; l++)
{
for (int c = 0; c < 3; c++)
{
 Console.Write(string.Format("{0}", 
tabuleiro[l, c]));
if (c < 2)
Console.Write("|");
42 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
}
Console.Write(Environment.NewLine);
if (l < 2)
Console.Write("-----");
Console.Write(Environment.NewLine);
}
}
Essa função recebe como argumento a matriz tabuleiro. Todas as 
suas posições serão percorridas conforme demonstrado na seção an-
terior. Nesse trecho, o valor máximo foi fixado em 3 porque esse é o 
tamanho padrão de um tabuleiro de jogo da velha. Para cada posição, é 
impresso seu valor; com exceção da última posição da linha, é impresso 
também o caractere “|” para criar uma representação visual de separa-
ção horizontal entre os elementos, similar à do tabuleiro real. Após cada 
linha, exceto a última, é impressa uma sequência do caractere “–” para 
representar a separação vertical dos elementos do tabuleiro.
Essa função não realiza alterações sobre a matriz recebida, mas a 
próxima função, conferirJogada, efetua alteração na matriz que é re-
cebida como argumento. Essa matriz é passada por referência, assim 
como ocorre para os vetores; portanto, as alterações que forem rea-
lizadas nessa matriz dentro da função se refletirão na matriz original. 
Porém, é exatamente isso que queremos neste caso, como observado 
a seguir:
static bool conferirJogada(char[,] tabuleiro, int linha, int 
coluna, int jogador, int jogada)
{
bool trinca = false;
if (jogador == 1)
tabuleiro[linha, coluna] = 'X';
else
tabuleiro[linha, coluna] = 'O';
//verificar na mesma linha
for (int c = 0; c < 3; c++)
43Estrutura de dados bidimensional (matriz)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
{
if (tabuleiro[linha, c] != tabuleiro[linha, coluna])
break;
if (c == 2)
trinca = true;
}
//verificar na mesma coluna
if (!trinca)
{
for (int l = 0; l < 3; l++)
{
 if (tabuleiro[l, coluna] != tabuleiro[linha, 
coluna])
break;
if (l == 2)
trinca = true;
}
}
//verificar na diagonal principal
if (!trinca)
{
if (linha == coluna)
{
for (int cont = 0; cont < 3; cont++)
{
 if (tabuleiro[cont, cont] != tabuleiro[linha, 
coluna])
break;
if (cont == 2)
trinca = true;
}
}
}
//verificar na diagonal secundária
if (!trinca)
{
if (linha + coluna == 3 - 1)
{
for (int cont = 0; cont< 3; cont++)
{
44 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
 if (tabuleiro[cont, 3-cont-1] != 
tabuleiro[linha, coluna])
break;
if (cont == 2)
trinca = true;
}
}
}
if (trinca)
{
Console.WriteLine();
imprimirTabuleiro(tabuleiro);
Console.Write("JOGADOR "+jogador+" VENCEU!\n\n");
return true;
}
if (jogada == 9)
{
Console.WriteLine();
imprimirTabuleiro(tabuleiro);
Console.Write("EMPATE!\n\n");
return true;
}
else
{
Console.Write("\nPRÓXIMO JOGADOR...\n\n");
return false;
}
}
A variável trinca indica se uma sequência de três valores iguais foi 
formada na horizontal, vertical ou diagonal. De início, os valores dos ar-
gumentos de linha e coluna são marcados na matriz tabuleiro com X, 
caso o argumento jogador seja 1, ou O, caso o jogador seja 2. Esse é 
o ponto em que a função altera a matriz tabuleiro por passagem por 
referência. Essa alteração se reflete na matriz original que foi passada 
como argumento para essa função, de forma semelhante ao que ocorre 
com os vetores.
45Estrutura de dados bidimensional (matriz)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Em seguida, são realizadas quatro verificações para detectar se a 
última marcação na matriz formou uma trinca. Primeiro, é verificada a 
linha da posição marcada. São percorridos os índices de 0 a 2. Nessa 
verificação, apenas o índice da coluna será alterado, uma vez que a li-
nha se mantém. Caso seja encontrado nessa linha um valor diferente 
do recém-preenchido na última posição marcada, a linha não é uma 
trinca; portanto, o comando break encerra essa verificação, saindo ime-
diatamente do for e mantendo a variável trinca com o valor false. Caso 
a verificação alcance a última posição, e não tenha entrado no primeiro 
if, todos os elementos dessa linha são iguais; portanto, a variável trinca 
recebe o valor true. Caso essa primeira verificação seja falsa, são reali-
zadas outras três, somente enquanto o valor de trinca for false. 
A segunda verificação ocorre na coluna da posição marcada, de for-
ma análoga à primeira verificação por linha; a terceira verificação ocorre 
na diagonal principal da matriz. Como nem todas as posições estão na 
diagonal, é preciso identificar se a posição marcada se encontra nessa 
diagonal; para isso, é verificado se o valor de linha é igual ao valor de 
coluna. Caso os valores sejam iguais, é realizada uma verificação simi-
lar às anteriores. A diferença dessa verificação na diagonal em relação 
às anteriores, por linha ou coluna, é que, em vez de fixar uma linha ou 
uma coluna, ambos os índices variam a cada verificação. Por fim, ocor-
re a verificação na diagonal secundária. Para entrar nessa condição, a 
posição marcada precisa corresponder a um valor de soma da linha 
e da coluna igual ao tamanho da matriz menos um. A verificação das 
posições ocorre de forma incremental para a linha e decremental, na 
mesma proporção, para a coluna. 
Encerrando-se as verificações, caso o valor da trinca seja true, é cha-
mada a função imprimirTabuleiro para mostrar a disposição final das 
marcações, junto com a mensagem indicativa de qual jogador venceu. 
O retorno como true fará com que, no ponto original de chamada dessa 
função, encerre-se o laço de repetição, finalizando o jogo.
46 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Caso não tenha se formado uma trinca, mas a jogada seja a final 
(de número nove), também são impressos o tabuleiro atualizado e uma 
mensagem declarando empate. Caso contrário, o jogo continua retor-
nando false, permitindo a repetição do laço. 
A figura 4 indica um trecho de interação com o jogo desenvolvido.
Figura 4 – Interação com o jogo da velha
Após implementar e compreender bem esse código, você pode prati-
car seu entendimento sobre matrizes realizando otimizações nele. Uma 
sugestão é mostrar uma mensagem de erro quando o jogador escolher 
uma posição já marcada anteriormente, permitindo que ele tente es-
colher outra posição. Outra sugestão é otimizar o término da partida, 
de modo que, se não houver mais possibilidade de vitória de nenhum 
jogador, o jogo imediatamente declare empate, eliminando a necessida-
de de preencher todas as posições do tabuleiro. Por fim, observe como 
são realizadas quatro verificações dentro da função conferirJogada 
47Estrutura de dados bidimensional (matriz)
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
para identificar se foi formada uma trinca. Repare como as quatro lógi-
cas são semelhantes. Tente criar uma nova função que, de acordo com 
os argumentos que receber, realize a verificação desejada. Utilize essa 
nova função quatro vezes dentro da função conferirJogada.
Considerações finais
Matrizes são estruturas muito úteis para o armazenamento de da-
dos que dependem de posições bidimensionais; além disso, elas podem 
ter grande aplicação em jogos de tabuleiro.
Essas estruturas são similares aos vetores e compartilham com eles 
diversas regras de uso: a forma como são feitas suas declarações é 
muito semelhante; suas posições somente podem armazenar um tipo 
de dado; os índices (que começam em zero) devem ser apontados para 
acessar uma posição da estrutura; uma forma fácil de percorrer todas 
as suas posições é por meio do for (no caso das matrizes, dois for: um 
para as colunas e um para as linhas).
Siga as sugestões ao final das seções e tente implementar as me-
lhorias indicadas nos jogos. Depois, escolha um jogo de tabuleiro e 
tente implementá-lo você mesmo, utilizando uma matriz. O exercí-
cio com matrizes é fundamental para desenvolver o domínio sobre 
o uso dessas estruturas, o que ajudará muito em sua evolução como 
programador.
Referência
DEITEL, Harvey M. et al. C#: como programar. São Paulo: Pearson Universidades, 
2003.
49
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Capítulo 3
Manipulação de 
arquivos em CSharp
Um aspecto importante no desenvolvimento de qualquer aplicação é 
a implementação de um recurso para a persistência de dados, ou seja, 
a capacidade de o programa salvar e recuperar dados ao ser reinicia-
do. Esse recurso é muito útil para o desenvolvimento de um jogo, pois 
permite a adição de opções de configuração para os jogadores e para 
as partidas, possibilitando salvar preferências e resultados, criando um 
histórico de interação e promovendo maior dinamismo.
O ideal, para aplicações mais sofisticadas, é o uso de um banco de 
dados para o armazenamento de informações, porém, para aplicações 
mais simples ou mesmo com poucos dados gerados, você pode utilizar 
50 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
aRe
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
arquivos para reter os dados gerados pelo programa. Essa é uma abor-
dagem simples, fácil e ideal em seu primeiro contato com alguma for-
ma de persistência de dados.
Neste capítulo, apresentaremos exemplos de implementação dos 
recursos de leitura e escrita no código do jogo do campo minado de-
senvolvido no capítulo anterior. Dessa forma, você aprenderá a editar e 
introduzir essa funcionalidade em qualquer programa.
A utilização de arquivos é um recurso simples que trará uma dinâmi-
ca mais atrativa ao seu jogo. Procure adicionar esse importante recurso 
ao desenvolvimento de seus jogos para transmitir maior qualidade aos 
projetos.
1 Utilização de arquivos em CSharp
A utilização de arquivos por programas remete ao uso de documen-
tos simples, criados e armazenados no diretório de pastas do sistema 
operacional. Esses arquivos são utilizados como uma forma simples 
e eficiente de armazenar alguns dados da aplicação, permitindo que o 
programa seja encerrado sem perdê-los e, quando reiniciado, recorra à 
leitura do arquivo para restaurar os dados salvos na aplicação.
Em um jogo, a utilização desse recurso pode ser essencial para imple-
mentar funcionalidades que necessitem da gravação de dados, como a 
definição de checkpoints, os itens que o jogador possui no momento em 
que salvou o jogo, rankings e scores obtidos em partidas, etc. Neste capí-
tulo, implementaremos o salvamento e a leitura do histórico de vitórias e 
derrotas de um jogador no campo minado, além do carregamento de um 
campo especificado no arquivo de texto. Após compreender como imple-
mentar esse procedimento, você poderá empregar o mesmo recurso em 
outros aspectos desse e de outros jogos.
51Manipulação de arquivos em CSharp
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Antes de iniciar a criação do arquivo e do código, é importante com-
preender o procedimento empregado por trás dessa ação. O processo 
de leitura ou escrita em um arquivo estabelece um fluxo entre o progra-
ma e o arquivo, de forma que o arquivo fica inacessível a outras solici-
tações enquanto é manipulado pelo programa. Isso é feito para evitar 
inconsistências causadas pela alteração de dados por duas fontes dis-
tintas, simultaneamente.
Por isso, um procedimento comum é estabelecer o fluxo, realizar as 
manipulações desejadas e fechar o fluxo, liberando o arquivo para ou-
tros acessos e desalocando o uso de memória. Adotamos essas etapas 
tanto para o processo de leitura quanto para o processo de escrita. Os 
códigos que veremos neste capítulo oferecerão um exemplo da imple-
mentação desses passos na gravação e no carregamento de dados.
PARA SABER MAIS 
Embora estejamos aprendendo a usar arquivos para a persistência de 
dados de um jogo digital, essa implementação é aplicável a qualquer 
tipo de software. Podemos utilizar arquivos para salvar dados de usu-
ários de um cadastro de clientes ou os produtos e as quantidades de 
um registro de estoque.
 
O primeiro passo para trabalhar com a leitura de dados por um pro-
grama é criar um arquivo que será acessado por ele. Para o projeto que 
desenvolveremos neste capítulo, devemos criar um arquivo de texto 
(extensão txt) com o nome “campo”.
O segundo passo é definir onde salvar esse arquivo. É interessante 
que ele esteja junto à pasta do projeto que o utiliza. Caso você utilize 
o Visual Studio para os estudos, recomenda-se colocar esse arquivo 
na pasta principal do projeto, junto ao arquivo de extensão sln. Veja na 
figura 1 onde foi salvo o arquivo mencionado.
52 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Figura 1 – Localização do arquivo campo.txt
PARA SABER MAIS 
O Visual Studio é apenas uma sugestão usada para exemplificar o con-
teúdo deste capítulo, mas você pode utilizar o ambiente de desenvolvi-
mento em que se sentir mais confortável para programar, como o Replit 
ou o .NET Fiddle, entre outros.
 
Perceba que o caminho pode ser diferente em seu computador, de-
pendendo de como instalou o Visual Studio e do destino que definiu 
para salvar os projetos criados. Em nosso exemplo, o local de salva-
mento dos projetos foi definido dentro da pasta repos, que está dentro 
da pasta source, a qual, por sua vez, está dentro da pasta do usuário 
Rafael.
Após posicionar o arquivo no local desejado, é importante definir 
os conceitos de caminho absoluto e caminho relativo. No código que 
implementaremos a seguir, teremos que indicar onde se encontra o ar-
quivo que desejamos acessar; para isso, devemos apontar o caminho 
até ele utilizando uma das duas formas mencionadas.
 O caminho absoluto corresponde à indicação de sequência de pas-
tas, desde a raiz do disco rígido até a pasta em que se encontra o ar-
quivo desejado (incluindo o nome do arquivo e sua extensão).
Portanto, o caminho absoluto para o arquivo posicionado, de acordo 
com a figura 1, é:
53Manipulação de arquivos em CSharp
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
C:\Users\Rafael\source\repos\Capitulo3\campo.txt
Contudo, ao utilizar esse caminho no código, é preciso duplicar as 
barras para evitar que a linguagem interprete que deve executar algum 
comando no meio da string que armazena o caminho, já que esses co-
mandos iniciam com o sinal de barra invertida (\).
IMPORTANTE 
Ao programar para o ambiente do Windows e indicar um caminho de 
arquivo salvo em uma string, temos que duplicar as barras dos diretó-
rios. Para o exemplo deste subcapítulo, o caminho ficaria:
C:\\Users\\Rafael\\source\\repos\\Capitulo3\\campo.txt
 
Outra forma de indicar o arquivo é apontar o caminho relativo. Para 
isso, toma-se como referência o diretório que executa o projeto. No 
caso do Visual Studio, esse diretório é a pasta netcoreapp2.1. A figura 2 
indica sua localização, quatro níveis abaixo da pasta Capitulo3, indicada 
anteriormente, que é onde o arquivo campo.txt se encontra.
Figura 2 – Localização da pasta de referência dos projetos do Visual Studio
Portanto, para apontar para o arquivo campo.txt usando um caminho 
relativo, é necessário retornar quatro níveis. Na construção da string do 
54 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.caminho, uma forma de indicar a volta de um nível de pasta é utilizar 
dois pontos (..). Assim, é necessário realizar esse procedimento qua-
tro vezes para indicar o percurso da pasta netcoreapp2.1 até a pasta 
Capitulo3, onde se encontra o arquivo. O caminho relativo, portanto, é:
..\..\..\..\campo.txt
Assim como no caminho absoluto, ao criar a string com esse cami-
nho, é necessário duplicar as barras. Portanto, em código, o caminho 
relativo é:
..\\..\\..\\..\\campo.txt
IMPORTANTE 
Preste atençãoonde está salvo o projeto que você está criando. Não 
utilize cegamente o caminho apontado nos códigos que veremos a se-
guir. É preciso ajustar as strings para apontar para o repositório onde se 
encontra o arquivo que você criou e que utilizará em seu projeto.
 
2 Leitura de dados em um arquivo
Conforme apresentado anteriormente, realizaremos um ajuste no 
jogo do campo minado, implementado no capítulo 2. Esse ajuste inicial 
permitirá que o programa leia e carregue dados salvos no arquivo cam-
po de extensão txt. Esses dados correspondem aos valores de cada po-
sição de um campo minado de 10 linhas por 10 colunas. Os valores zero 
(0) indicam uma posição vazia; os valores um (1), uma bomba; e o valor 
dois (2), a bandeira. Portanto, para representar esse campo, deve haver 
no arquivo 10 linhas, cada uma com 10 valores separados por vírgula. 
Além disso, no arquivo, logo após a definição da matriz, há uma linha 
em branco, seguida por uma linha com a contagem de vitórias e outra 
55Manipulação de arquivos em CSharp
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
linha com a contagem de derrotas. Essas linhas representam o histó-
rico de partidas do jogador, que será atualizado após a finalização de 
cada partida, como veremos no subcapítulo seguinte.
Assim, o arquivo deve ter a estrutura representada na figura 3.
Figura 3 – Arquivo a ser lido
IMPORTANTE 
Se o arquivo não estiver no molde apresentado na figura 3, a leitura 
poderá não funcionar.
 
Com o arquivo criado e salvo no local apontado no primeiro subcapí-
tulo, podemos prosseguir com o desenvolvimento do código para fazer 
o carregamento desses dados. O programa final é o seguinte:
56 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
 int[,] campo = new int[10, 10];//matriz com posições dos elementos do campo
 int[,] jogo = new int[10, 10];//matriz que registra ações do jogador
int qtdLinhas = campo.GetLength(0);
int qtdColunas = campo.GetLength(1);
bool problemaArquivo = false;
 string caminho_absoluto = 
"C:\\Users\\Rafael\\source\\repos\\Capitulo3\\campo.txt";
string caminho_relativo = "..\\..\\..\\..\\campo.txt";
try
{
//Informando o caminho e nome do arquivo
StreamReader sr = new StreamReader(caminho_absoluto);
//Leitura da primeira linha do arquivo
String linha_arq = sr.ReadLine();
int linha_mtz = 0;
int coluna_mtz = 0;
//Continua lendo até não identificar uma nova linha
while (linha_arq != null || linha_mtz<10)
{
//Separação de cada elemento da string pela vírgula
foreach (var numero in linha_arq.Split(','))
{
int num;
//Conversão de cada elemento separado para um int
if (int.TryParse(numero, out num)) {
//armazenando elemento na matriz campo
57Manipulação de arquivos em CSharp
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
campo[linha_mtz, coluna_mtz] = num;
jogo[linha_mtz, coluna_mtz] = -1;
coluna_mtz++;
}
}
//Leitura da próxima linha
linha_arq = sr.ReadLine();
//Avançando para a leitura da próxima linha,
//começando pelo primeiro valor (primeira coluna)
coluna_mtz = 0;
linha_mtz++;
}
//Encerrando a leitura do arquivo
sr.Close();
}
catch (Exception e)
{
 Console.WriteLine(
"Ocorreu um problema na leitura do arquivo!");
problemaArquivo = true;
}
No código acima, iniciamos com a declaração de duas matrizes: a 
matriz campo armazenará os valores de cada posição do tabuleiro, que 
serão carregados a partir do arquivo txt; a matriz jogo representa os 
valores visíveis ao jogador, indicando o valor –1 para cada posição que 
o jogador ainda não escolheu – após cada escolha de campo vazio, o 
respectivo valor será atualizado na matriz para zero (0). Quando o joga-
dor apontar para uma bomba ou para a bandeira, o jogo se encerrará.
Em seguida, são criadas as variáveis qtdLinhas e qtdColunas, que se-
rão utilizadas na próxima etapa de escrita no arquivo. Perceba que, para 
obter a quantidade de linhas de uma matriz, pode-se utilizar GetLength 
com o valor 0, e, para obter a quantidade de colunas, o mesmo coman-
do com o valor 1.
A variável problemaArquivo indicará se houve problema no carre-
gamento dos dados. Nesse caso, a matriz não poderá ser montada 
e, portanto, o jogo não será iniciado. As strings caminho_absoluto e 
58 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
caminho_relativo são as duas opções para indicar a localização do ar-
quivo, como visto anteriormente.
Em seguida, iniciaremos a leitura do arquivo. Como esse procedi-
mento pode lançar uma exceção (equivalente a um “problema” de exe-
cução do programa), como no caso de não ser identificado o arquivo 
no caminho indicado ou de o formato dos dados não estar na disposi-
ção esperada pelo programa, é necessário realizar um tratamento de 
exceção, que consiste em prever a possibilidade da ocorrência desse 
problema e indicar uma mensagem de erro ou um fluxo de execução 
alternativo, evitando, assim, que o programa simplesmente se encerre 
com erro (evento popularmente conhecido como crash).
Por isso, criamos um bloco try e, dentro dele, realizamos uma tenta-
tiva de acessar o arquivo. Todo o código de acesso e leitura do arquivo 
estará dentro das chaves desse bloco. Perceba que, ao final dele, há 
outro bloco, chamado catch. O parâmetro desse bloco indica o tipo de 
exceção que será capturada para iniciar a exceção do código do bloco. 
Nesse caso, trata-se de uma exceção genérica, indicando que qualquer 
tipo de problema na leitura iniciará a execução desse bloco. Como re-
sultado de alguma exceção gerada, apenas será mostrada uma mensa-
gem de erro, e a variável problemaArquivo receberá o valor true, impedin-
do que o jogo inicie, como veremos adiante.
PARA SABER MAIS 
Compreender a aplicação de tratamento de exceção é importante para 
a criação de programas mais consistentes e seguros. Há vários tipos 
de exceção, e pode ser interessante realizar diferentes procedimentos, 
a depender do tipo lançado em um trecho de código. Uma fonte desse 
assunto para a linguagem C# é a obra C#: como programar (DEITEL, 
2003, p. 375).
 
59Manipulação de arquivos em CSharp
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Dentro do bloco try, a primeira instrução cria um objeto do tipo 
StreamReader, passando como argumento o caminho do arquivo. Esse 
objeto abre um fluxo de comunicação com o arquivo informado, permi-
tindo o uso de métodos para realizar a leitura dos seus dados. O coman-
do seguinte, utilizando o método ReadLine() desse objeto, irá justamente 
ler todo o conteúdo da primeira linha, armazenando-o na string de nome 
linha_arq. Como é necessário dividir cada linha para obter os valores 
de cada posição, são criadas as variáveis linha_mtz e coluna_mtz para 
auxiliar no posicionamento de cada valor.
Em seguida,é utilizado um laço para indicar a repetição do processo 
de leitura de uma linha e de tratamento dos dados lidos, armazenan-
do-os na matriz. Portanto, esse laço se repetirá enquanto a string que 
armazena uma linha do arquivo (linha_arq) for diferente de null. Quando 
se deseja ler todas as linhas de um arquivo, essa é a abordagem padrão, 
mas, neste caso em específico, queremos ler apenas as dez primeiras 
linhas, não sendo necessário ler as últimas (com contagem de vitórias 
e derrotas). Por isso, a eventual contagem de linhas até dez também é 
uma condição limitante para encerrar o laço.
Dentro do laço, é utilizado o comando foreach parar iterar (percorrer) 
entre cada valor das linhas do arquivo. Cada um desses valores, repre-
sentado pela variável numero, é obtido pelo método Split, aplicado na 
string linha_arq, usando como critério de separação a vírgula. 
Para cada valor resultante dessa divisão da string em partes, é rea-
lizada uma tentativa de conversão do valor, que ainda está em formato 
de texto, para um inteiro. A variável numero indica o valor de entrada 
(texto), e num indica a variável int de saída, após essa conversão. Se a 
conversão der certo, o valor em num será armazenado na matriz campo, 
na respectiva posição indicada por linha_mtz e coluna_mtz. Na matriz 
jogo, na mesma posição, é armazenado o valor inicial –1. E o valor de 
coluna_mtz é incrementado para que o próximo valor lido seja armaze-
nado na coluna seguinte. 
60 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Quando o foreach se encerrar, indicando o término da conversão 
dos valores de uma linha, uma próxima linha será lida pelo comando 
ReadLine(). O valor da coluna voltará para zero, e o da linha será incre-
mentado para continuar preenchendo corretamente a matriz com os 
próximos valores a serem convertidos. Assim, o laço se repetirá en-
quanto houver uma nova linha lida. Ao encerrar-se o processo de leitura, 
o fluxo aberto com o arquivo é encerrado pelo método Close().
Observe que a definição dos valores do tabuleiro não é mais reali-
zada de forma estática no código, mas provém de uma fonte externa. 
Assim, quem não entende de programação pode facilmente criar um 
novo campo no arquivo externo para que outro jogador participe.
Se ocorrer algum problema na leitura do arquivo que você está im-
plementando, verifique com atenção os dados digitados. Perceba que o 
código implementado para leitura segue uma sequência predetermina-
da; portanto, os dados no arquivo precisam estar nessa mesma sequên-
cia lógica ou haverá inconsistência de informação e problema na leitura. 
Redobre a atenção, também, para o caminho indicado para o arquivo.
O código do jogo permanece praticamente o mesmo:
if (!problemaArquivo)
{
bool fimJogo = false;
bool vitoria = false;
do
{
for (int l = 0; l < qtdLinhas; l++)
{
for (int c = 0; c < qtdColunas; c++)
{
 Console.Write(string.Format("{0} ",
jogo[l, c]));
61Manipulação de arquivos em CSharp
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
}
 Console.Write(Environment.NewLine + 
Environment.NewLine);
}
Console.Write("Selecione uma linha [1-10]: ");
int linha = Convert.ToInt32(Console.ReadLine()) - 1;
Console.Write("Selecione uma coluna [1-10]: ");
int coluna = Convert.ToInt32(Console.ReadLine()) - 1;
switch (campo[linha, coluna])
{
case 0:
jogo[linha, coluna] = 0;
Console.Write("Continue tentando.\n\n");
break;
case 1:
jogo[linha, coluna] = 1;
Console.Write("BOOOM. Você perdeu.\n\n");
fimJogo = true;
break;
default:
jogo[linha, coluna] = 2;
Console.Write("Parabéns. Você ganhou!\n\n");
fimJogo = true;
vitoria = true;
break;
}
} while (!fimJogo);
}
Esse código deve suceder o código anterior de leitura do arquivo. 
Uma das diferenças desse código em relação à implementação no ca-
pítulo 2 é que ele foi inserido dentro de uma condicional. Essa condição 
verifica se a variável problemaArquivo não é true, ou seja, esse código 
será executado apenas se a leitura do arquivo tiver ocorrido sem proble-
mas. A outra diferença é a criação da variável vitoria, começando com 
valor false. Caso o jogador vença a partida, essa variável recebe o valor 
true. Ela será utilizada para modificar o histórico de vitórias e derrotas 
do jogador no momento de escrita no arquivo, como veremos no sub-
capítulo a seguir.
62 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
3 Escrita de dados em um arquivo
O processo de escrita (ou salvamento) de dados em um arquivo é 
bem semelhante ao de leitura. Agora que conseguimos carregar os da-
dos de um campo para o nosso programa e jogar uma partida, podemos 
implementar um código para salvar algum dado modificando o mesmo 
arquivo utilizado. Já foi apontado que as duas últimas linhas desse ar-
quivo registram a quantidade de vitórias e derrotas do jogador; portanto, 
implementaremos uma lógica em que, logo após o término da partida, 
será identificado se o jogador venceu ou perdeu e será incrementada a 
respectiva contagem no arquivo.
O código abaixo deve ser inserido ao final do comando if que engloba 
a execução do jogo, conforme mostrado no subcapítulo anterior. Assim, 
ele deve ser inserido dentro do bloco if, entre a linha final do while e o 
último fechamento de chaves:
string[] arquivo = File.ReadAllLines(caminho_absoluto);
string msgVitorias = arquivo[arquivo.Length - 2];
string msgDerrotas = arquivo[arquivo.Length - 1];
try
{
StreamWriter sw = new StreamWriter(caminho_absoluto);
int contagem; //de vitorias ou derrotas
int linha_sobrescrever;
string texto;
if (vitoria)
{
 int.TryParse(msgVitorias.Split(':')[1], out contagem);
linha_sobrescrever = 11;
texto = "Vitórias:";
}
else
{
 int.TryParse(msgDerrotas.Split(':')[1], out contagem);
63Manipulação de arquivos em CSharp
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
linha_sobrescrever = 12;
texto = "Derrotas:";
}
contagem++;
for (int i = 0; i < arquivo.Length; i++)
{
if (i == linha_sobrescrever)
sw.WriteLine(texto + contagem);
else
sw.WriteLine(arquivo[i]);
}
sw.Close();
}
catch (Exception e)
{
 Console.WriteLine(
"Ocorreu um problema na escrita do arquivo!");
}
 A primeira instrução indica a leitura de todas as linhas do arquivo 
indicado em caminho_absoluto e a conversão para um vetor de strin-
gs, em que cada posição corresponde ao conteúdo de uma das linhas. 
Abaixo, o valor da penúltima posição desse vetor é armazenado em 
msgVitorias e o valor da última posição, em msgDerrotas.
Em seguida, é iniciado o processo de escrita no arquivo (assim como 
no processo de leitura, ele é inserido dentro de um bloco try). Um objeto 
StreamWriter é criado a partir do caminho do arquivo. Três variáveis são 
utilizadas para compor a mensagem que será sobrescrita no arquivo 
(contagem de vitórias ou derrotas).
Caso a variável booleana vitoria seja true, indicando que o jogador 
venceu a partida, a string msgVitorias é dividida a partir do sinalde dois 
pontos (:). Assim, será gerado um vetor de strings com duas posições: 
a primeira armazena o texto "Vitórias" e a segunda, a contagem de vitó-
rias. Portanto, msgVitorias.Split(':')[1] indica a segunda posição 
desse vetor, que é a contagem. Essa string será convertida em um valor 
64 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.do tipo int, representado pela variável contagem. A variável linha_sobres-
crever armazena 11, que é a indicação da linha do arquivo em que se en-
contra essa contagem de vitórias. Já a variável texto recebe "Vitórias:". 
Caso o usuário tenha perdido a partida, a variável contagem armazena 
o valor da contagem de derrotas atual, a variável linha_sobrescrever re-
cebe o valor 12 e a variável texto recebe "Derrotas:". Em seguida, a variá-
vel contagem é incrementada para indicar a vitória ou derrota na última 
partida finalizada.
Por fim, o vetor que inicialmente continha todas as linhas do arquivo 
é percorrido, e cada linha é sobrescrita com o método WriteLine, usando 
o conteúdo de uma nova posição do vetor. A maioria das linhas do arqui-
vo é reescrita com o mesmo conteúdo anterior, porém a linha indicada 
em linha_sobrescrever, que representa a contagem de vitórias ou derro-
tas do jogador, é alterada. O que é reescrito é a mensagem armazenada 
em texto ("Vitórias:" ou "Derrotas:"), concatenada com o valor atualizado 
em contagem.
O procedimento demonstrado é suficiente para modificar o arquivo 
e gravar os dados atualizados gerados por uma nova partida. Essa é 
uma forma simples de manter um registro dos resultados de um jogo 
ou das configurações de uma aplicação qualquer.
Considerações finais
A manipulação de arquivos é um recurso muito útil e simples para 
permitir a persistência de dados de uma aplicação, ou seja, a possibili-
dade de um programa salvar dados gerados durante a sua execução e 
recuperá-los quando voltar a ser executado.
No desenvolvimento de jogos, essa técnica pode ser empregada 
para salvar e recuperar diversas informações, como configurações de 
jogo, preferências do jogador, resultados de partidas, pontuações obti-
das e estatísticas acumuladas.
65Manipulação de arquivos em CSharp
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Neste capítulo, demonstramos como realizar a leitura (carregamen-
to) de dados salvos e a escrita (salvamento) de dados em um arquivo. É 
importante salientar que existem diversas abordagens e recursos para 
implementar essas operações. A abordagem apresentada neste capí-
tulo é um exemplo aplicado a um problema, e você deve compreender 
como utilizar os recursos demonstrados para adequar o seu código 
às necessidades específicas de cada novo programa que desenvolver. 
Uma boa referência para encontrar mais técnicas e exemplos que aju-
dem a aumentar seu domínio sobre essa implementação é a obra C#: 
como programar (DEITEL, 2003, p. 649).
A partir de agora, você pode praticar e implementar recursos de 
salvamento e carregamento por meio de arquivos em seus jogos já 
desenvolvidos.
Referência
DEITEL, Harvey M. et al. C#: como programar. São Paulo: Pearson Universidades, 
2003.
67
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Capítulo 4
Algoritmos de busca 
em vetores
Existem problemas de computação comuns a diversos programas 
cuja resolução exige uma estratégia específica. Alguns deles, por serem 
muito recorrentes, possuem algoritmos consagrados para resolvê-los. 
Entre esses problemas, encontra-se o da busca de um elemento em um 
conjunto linear de dados — ou, mais especificamente, a busca em vetores.
Veremos neste capítulo duas abordagens para a tarefa de encontrar 
um valor em um vetor. A busca linear representa a abordagem mais 
simples e objetiva, sem nenhuma estratégia específica, apenas recor-
rendo ao uso de iterações, pesquisando posição por posição do vetor. 
A busca binária, por sua vez, apresenta uma estratégia baseada no 
68 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
método de divisão e conquista, no qual, para um caso genérico, o valor 
pode ser identificado com menos iterações do que pela busca linear. 
Nos próximos subcapítulos, serão apresentadas as implementações de 
ambos os algoritmos, bem como observações e restrições importantes 
a considerar.
No último subcapítulo, há uma introdução à análise de algoritmos 
na qual serão apresentados os fundamentos para compará-los, deter-
minar sua eficiência e expressar sua complexidade em uma notação 
adequada.
Esse assunto é muito importante, pois se trata da base inicial do 
aprendizado de diversos outros algoritmos que ainda serão apresenta-
dos. Compreender os conceitos fundamentais que norteiam o desen-
volvimento de algoritmos consagrados é essencial para que você possa 
desenvolver e analisar seus próprios algoritmos no futuro.
1 Busca linear
O algoritmo de busca linear (ou sequencial) em um vetor recorre a 
uma abordagem simples e intuitiva: percorrer todas as posições do ve-
tor, iniciando-se pela primeira, até encontrar o valor procurado. Dessa 
forma, sua implementação necessita apenas do uso de um for, sendo 
que, em cada iteração, o valor da posição consultada será comparado 
com o valor procurado.
A seguir, um exemplo de implementação:
int[] dados = { 52, 17, 69, 84, 3, 26, 83, 54, 19, 50 };
int valor_procurado = 54;
bool valor_encontrado = false;
for(int i = 0; i < dados.Length; i++)
{
if (dados[i]==valor_procurado)
{
69Algoritmos de busca em vetores
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Console.WriteLine("Valor encontrado no índice "+i);
valor_encontrado = true;
break;
}
}
if (!valor_encontrado)
{
Console.WriteLine("Valor não encontrado");
}
Nesse código, o vetor dados é percorrido a partir do índice 0. Quando 
o valor na posição consultada for igual ao valor procurado, uma mensa-
gem será impressa informando que o valor foi encontrado junto com o 
respectivo valor do índice. Além disso, a variável valor_encontrado passa 
a valer true, e o comando break encerra as iterações, pois, se o valor já 
foi encontrado, não é necessário percorrer o restante do vetor. Por fim, 
após encerrar o for, caso não tenha sido encontrado o valor, uma men-
sagem é impressa informando que o valor não foi encontrado.
Essa é a abordagem mais simples para percorrer um vetor em busca 
de um valor, pois consulta todas as posições até encontrá-lo. Na melhor 
das hipóteses (melhor caso), em que o valor procurado está na primeira 
posição, a busca se encerra mais rapidamente; na pior das hipóteses 
(pior caso), em que o valor procurado está na última posição, todas as 
posições do vetor devem ser consultadas até encontrá-lo. Se essa bus-
ca for realizada em um vetor que tem os valores aleatoriamentedistri-
buídos em suas posições, podemos dizer que, na média (caso médio), 
será necessária uma quantidade de consultas equivalente à metade do 
tamanho do vetor.
Essa é somente uma das formas — e a mais simples — de realizar 
uma busca em um vetor. Veremos a seguir outra abordagem de busca.
70 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
2 Busca binária
A busca binária apresenta uma nova estratégia de busca de um valor 
em um vetor. Trata-se de um algoritmo que representa um aperfeiçoa-
mento em relação à busca linear, de forma que, para um caso médio, 
menos posições são consultadas para encontrar o valor procurado. 
Contudo, há uma importante condição para que esse algoritmo funcio-
ne: todos os valores precisam estar ordenados no vetor.
A lógica de implementação segue o método de divisão e conquis-
ta: separar um problema maior em pequenas partes, de modo a resol-
ver cada uma delas, juntando suas soluções para resolver o problema 
como um todo. No caso da busca binária, essa estratégia consiste em 
dividir o vetor em duas partes e olhar para o meio: caso o valor do meio 
seja menor que o valor procurado, é analisada a segunda parte do ve-
tor, repetindo-se a estratégia de dividi-lo em duas partes. Caso o valor 
do meio seja maior que o valor procurado, é analisada a primeira parte 
do vetor, repetindo-se a estratégia. Quando o valor do meio for igual ao 
valor procurado, a busca será encerrada.
A figura 1 demonstra o passo a passo da execução desse algoritmo 
em um vetor até encontrar o valor procurado. Na primeira iteração, o 
valor verificado (meio) aponta para o índice 4, de valor 50. Como esse é 
um valor menor do que o buscado (54), a variável início passa a apontar 
para a posição seguinte do meio, o qual, por sua vez, é recalculado. Na 
segunda iteração, o meio aponta para o índice 7 (valor 69), que é maior 
do que o valor procurado. Desta vez, a variável fim passa a apontar para 
a posição anterior do meio, que é recalculado. Perceba que o meio apon-
tará para o mesmo índice do início. Na terceira iteração, o meio aponta 
para o índice 5 (valor 52), que é menor do que o buscado. Por fim, na 
quarta iteração, a variável início passa a apontar para o mesmo índice do 
fim. Ao recalcular o meio, este aponta para o mesmo índice. Ao verificar 
o valor, este corresponde ao buscado, e o laço de busca se encerra.
71Algoritmos de busca em vetores
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Figura 1 – Exemplo de passo a passo da busca binária
VALOR PROCURADO = 54ITERAÇÃO
VALOR PROCURADO > MEIO
VALOR PROCURADO > MEIO
INÍCIO FIM
FIM
FIM
FIM
MEIO
INÍCIO
INÍCIO
INÍCIO
MEIO
MEIO
MEIO
VALOR PROCURADO = MEIO (ENCONTRADO)
VALOR PROCURADO < MEIO
3 17 19 26 50 52 54 69 83 84
3 17 19 26 50 52 54 69 83 84
3
1
2
3
4
17 19 26 50 52 54 69 83 84
3 17 19 26 50 52 54 69 83 84
A implementação da busca binária é apresentada a seguir:
int[] dados = { 3, 17, 19, 26, 50, 52, 54, 69, 83, 84 };
int valor_procurado = 54;
bool valor_encontrado = false;
int inicio = 0;
72 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
int fim = dados.Length-1;
int meio;
do
{
meio = inicio + (fim - inicio) / 2;
if (dados[meio] == valor_procurado)
{
 Console.WriteLine("Valor encontrado no índice " + 
meio);
valor_encontrado = true;
break;
}
else if (dados[meio] > valor_procurado)
{
fim = meio - 1;
}
else
{
inicio = meio + 1;
}
} while (inicio<=fim);
if (!valor_encontrado)
{
Console.WriteLine("Valor não encontrado");
}
Primeiramente, observe que o vetor contém os mesmos valores do 
exemplo criado para a busca linear, porém todos eles estão agora orde-
nados no vetor. Portanto, caso deseje aplicar uma busca binária em um 
vetor não ordenado, é necessário primeiro aplicar um algoritmo de orde-
nação. Veremos alguns desses algoritmos no próximo capítulo.
IMPORTANTE 
Diferentemente da busca linear, na busca binária o vetor precisa estar 
com todos os seus elementos ordenados de forma crescente.
 
73Algoritmos de busca em vetores
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Para a aplicação desse algoritmo, são utilizadas três variáveis: uma 
para indicar o índice de início do trecho do vetor analisado, uma para 
indicar o fim e outra para indicar o meio (caso haja um valor par de índi-
ces, o índice central é arredondado para o menor valor).
Um laço inicia calculando o índice da posição do meio. Primeiro, é 
verificado se o valor nessa posição é o buscado. Caso seja o valor bus-
cado, uma mensagem de confirmação é impressa, o valor da variável 
que indica que o valor foi encontrado recebe true e o laço é encerrado 
com o comando break. Caso o valor nessa posição central seja maior 
que o valor procurado, a posição final do vetor passa para o índice ante-
rior ao verificado.
Dessa forma, na próxima iteração, será verificada a primeira parte 
do vetor atual, reduzindo assim o escopo de busca ou, ainda, dividindo 
o problema (de encontrar um valor em um vetor) em uma parte menor. 
Caso o vetor não esteja ordenado, é inválido presumir que, se o valor 
na posição central for maior do que o valor procurado, este estará na 
primeira parte do vetor. Por fim, caso o valor procurado seja maior 
que o valor na posição do meio, a posição inicial passa para o índice 
imediatamente posterior ao da posição do meio; assim, na próxima 
iteração, é verificada a segunda parte do vetor. O laço fará com que 
essa abordagem se repita, dividindo (divisão) o vetor em duas partes, 
sucessivamente (por isso o nome busca binária), até encontrar ou não 
o valor procurado (conquista).
O algoritmo de busca binária apresenta uma estratégia própria e 
comparativamente mais complexa do que o algoritmo de busca linear. 
Ao comparar os exemplos de ambos os algoritmos, temos que, pelo 
algoritmo de busca linear, foram realizadas oito verificações até encon-
trar o valor procurado (pois este se localiza na oitava posição do vetor), 
enquanto, pela busca binária, foram necessárias apenas quatro verifi-
cações. Mesmo se o vetor utilizado pela busca linear fosse ordenado, 
seriam necessárias 7 verificações para encontrar o valor 54.
74 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Com essa observação, intuímos que o algoritmo de busca binária 
é melhor (mais eficiente) do que o algoritmo de busca linear. De todo 
modo, precisamos analisar melhor ambos os algoritmos e expressar 
essa análise de maneira mais formal para apresentar um argumento 
sólido nesse sentido, o que faremos a seguir.
3 Conceitos deanálise de algoritmos
Em computação, é comum que haja diferentes estratégias para re-
solver um mesmo problema, ou seja, diferentes algoritmos para realizar 
uma mesma tarefa. Embora esses algoritmos tenham que alcançar o 
mesmo resultado, a fim de cumprir a tarefa a que se propõem, a forma 
como a executarão será diferente e, em consequência, um algoritmo 
poderá ser mais eficiente do que o outro.
Vimos até aqui dois algoritmos de busca que resolvem o mesmo 
problema de encontrar um elemento em um vetor. No entanto, devido 
às suas estratégias (implementações) diferentes, um pode ser mais efi-
ciente do que o outro. O conceito de eficiência pode variar, mas normal-
mente se refere a um algoritmo de execução mais rápida ou com menor 
utilização de recursos (memória). Em nosso caso, estamos analisando 
a eficiência em relação à quantidade de passos (ou verificações) que os 
algoritmos têm que executar até cumprir seu objetivo. Na prática, isso 
se refletirá no tempo de execução dos algoritmos.
É comum analisarmos um algoritmo sob o pior caso, ou seja, a quan-
tidade máxima de verificações necessárias. Contudo, essa análise tem 
que ser feita em função de uma entrada. Um algoritmo de busca atua 
sobre uma quantidade de elementos; portanto, seu tempo de execu-
ção varia conforme a quantidade de elementos que ele precisa anali-
sar. Assim, podemos fazer uma projeção de quantas verificações serão 
necessárias (no pior caso) em função de cada possível entrada (nesse 
caso, uma quantidade de elementos).
75Algoritmos de busca em vetores
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Para o algoritmo de busca linear, o pior caso é quando o elemen-
to buscado se encontra na última posição do vetor. Então, o algoritmo 
precisa percorrer todas as posições até encontrá-lo. Assim, se o vetor 
possui 10 elementos, são necessárias 10 verificações; se possui 25 ele-
mentos, 25 verificações. De forma mais genérica, se o vetor possui n 
elementos, são necessárias n verificações.
Para expressar essa análise do algoritmo, visando a uma maior 
formalidade, utiliza-se uma notação. A notação O, também chamada 
de grande O, indica o limite assintótico superior da função, que basica-
mente representa a quantidade máxima de execuções do algoritmo. No 
caso do algoritmo de busca linear, já identificamos que, dada uma en-
trada com n elementos, serão executadas, no pior caso, n verificações. 
Uma simples função linear expressa essa relação:
f(n) = n
A notação O indica essa função, sendo expressa da seguinte maneira:
O(f(n))
Logo, costuma-se simplificar, deixando a notação expressa como:
O(n)
IMPORTANTE 
A notação “O(n)” deve ser lida como “Ó de n”.
 
Essa notação indica que, dado um valor de entrada, a quantidade de 
verificações executadas pelo algoritmo será, no máximo, igual ao valor 
apontado pela função (indicado pela notação). Ela define uma maneira 
de expressar a taxa de crescimento dos passos realizados pelo algorit-
mo conforme o aumento da entrada.
76 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Para a busca linear, O(n) indica que o algoritmo pode executar até n 
passos para uma entrada de tamanho n.
Agora, analisemos o algoritmo da busca binária: para um vetor com 
4 elementos, são executadas, no máximo, 2 verificações até encontrar o 
elemento procurado; para um vetor com 8 elementos, são executadas, 
no máximo, 3 verificações; para um vetor com 16 elementos, 4 verifica-
ções. Perceba que a taxa de crescimento (saída da função) é menor do 
que seu valor de entrada; logo, ela cresce mais devagar do que a função 
linear que representa o algoritmo da busca linear. Esse crescimento, em 
que a saída aumenta uma unidade somente quando se dobra o valor da 
entrada, é expresso pela função do logaritmo na base 2.
De forma análoga ao processo indicado para a busca linear, pode-
mos apontar que a complexidade da busca binária é assim expressa na 
notação O:
O(log2n)
Uma forma mais evidente de visualizar as taxas de crescimento de 
ambas as funções é representá-las no plano cartesiano. Observe a fi-
gura 2, que indica os gráficos de ambas as funções. Quanto maior a 
entrada (quantidade de elementos do vetor), maior a diferença do valor 
da função (quantidade de passos) entre os dois algoritmos.
Figura 2 – Funções da busca linear (função linear) e da busca binária (função logarítmica)
5
5
10
15
10 15 20 25 30
77Algoritmos de busca em vetores
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
PARA SABER MAIS 
Embora seja muito comum o uso da notação O, existem outras nota-
ções relevantes e interessantes, como a notação θ (Theta) e a notação 
Ω (Ômega), utilizadas para analisar algoritmos sob outras perspecti-
vas. Para conhecer melhor essas notações, indicamos a obra Estrutu-
ras de dados e seus algoritmos (SZWARCFITER; MARKENZON, 2010).
 
Desse modo, constatamos formalmente que o algoritmo da busca 
binária é mais eficiente (rápido) do que o algoritmo da busca linear. 
Cabem, porém, algumas observações. Essa conclusão considera um 
caso geral, ou seja, a ideia de que, na maioria das vezes, para entradas 
de tamanhos aleatórios, com o elemento buscado em uma posição ale-
atória, a busca binária é mais eficiente do que a busca linear. Isso não 
quer dizer que a busca binária será mais eficiente em todos os casos. 
Se você estiver realizando buscas em diferentes vetores, de diferentes 
tamanhos, na maioria das vezes, a busca binária será mais eficiente do 
que a busca linear, mas se em um desses vetores o elemento buscado 
estiver na primeira posição, a busca linear será mais eficiente.
Além do mais, não se esqueça: para a busca binária funcionar, o 
vetor deve estar com os elementos ordenados em ordem crescente. 
Veremos como fazer isso no próximo capítulo.
NA PRÁTICA 
Uma forma interessante de comparar cada passo da execução de dife-
rentes algoritmos é por meio de simulações animadas. Você pode uti-
lizar a página disponibilizada pela University of San Francisco (GALLES, 
2022) para executar algumas buscas pelos algoritmos de busca linear e 
busca binária, verificando cada etapa de execução.
 
78 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Considerações finais
Algoritmos de busca representam importantes estratégias para a 
resolução de problemas em programação. Saber empregá-los e dife-
renciar seus graus de eficiência é essencial no processo de escolha do 
algoritmo a implementar.
O algoritmo de busca linear é a abordagem mais simples e intuitiva 
para buscar um valor em um vetor. Sua complexidade, porém, aumenta 
consideravelmente na proporção do aumento da entrada. Aprendemos 
que, na notação O, sua complexidade é representada por O(n). 
Por outro lado, o algoritmo de busca binária utiliza uma estratégia de 
busca baseada no método de divisão e conquista, apresentando uma 
complexidade de O(log2n). Em comparação com a busca linear, a buscabinária apresenta uma grande melhora em um cenário genérico, obten-
do maior eficiência. Contudo, há um requisito fundamental para a busca 
binária funcionar: o vetor deve estar ordenado. Isso acarreta outro pro-
blema, cuja solução demanda a implementação de outros algoritmos: 
a ordenação. No próximo capítulo, vamos conhecer e aprender a imple-
mentar alguns algoritmos de ordenação que resolverão esse problema.
Referências
GALLES, D. Searching sorted list. Disponível em: https://www.cs.usfca.
edu/~galles/visualization/Search.html. Acesso em: 12 mar. 2022.
SZWARCFITER, J. L.; MARKENZON, L. Estruturas de dados e seus algoritmos. 
Rio de Janeiro: LTC, 2010.
https://www.cs.usfca.edu/~galles/visualization/Search.html
https://www.cs.usfca.edu/~galles/visualization/Search.html
79
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Capítulo 5
Algoritmos 
de ordenação 
elementares
Problemas de ordenação são comuns no desenvolvimento de 
softwares. Um programa pode gerar ou receber diversos dados ao lon-
go do tempo, precisando constantemente fazer uma consulta em busca 
de alguns desses. Para facilitar a tarefa da consulta, manter esse con-
junto de dados ordenado é uma abordagem comum.
 Por isso, existe uma série de algoritmos de ordenação, alguns mais 
simples, como veremos adiante, e outros mais complexos, mas com 
eficiência superior. Além da importância desses algoritmos para a fina-
lidade a que se propõem, esse tema de estudo é interessante por intro-
duzir o leitor na análise e compreensão de algoritmos mais elaborados, 
80 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
de modo a amadurecer seu raciocínio e sua percepção ao abordar um 
problema, convertendo-o em um algoritmo e usando as estruturas bási-
cas de programação que já conhece.
Veremos como um mesmo problema – neste caso, o de ordenação 
– pode ser abordado de diferentes formas: a ordenação pelo método 
bolha procura posicionar os maiores elementos ao final do vetor; a or-
denação por seleção troca um elemento na parte inicial pelo menor ele-
mento que há no restante do vetor a cada iteração; e a ordenação por 
inserção busca os menores elementos no restante do vetor para posi-
cioná-los ordenadamente no início. Veremos em detalhes esses algorit-
mos, mas já podemos observar que cada um deles tem uma estratégia 
distinta para uma mesma função.
Assim, é fundamental que o programador conheça as principais 
alternativas para resolver um mesmo problema. Desse modo, ele terá 
discernimento para compreender o funcionamento das estruturas do 
programa e para fazer escolhas conscientes ao cumprir as tarefas ne-
cessárias ao seu desenvolvimento.
1 Ordenação pelo método bolha
A ordenação pelo método bolha, por vezes chamada apenas de or-
denação bolha ou, ainda, bubble sort, é um dos métodos mais simples e 
intuitivos para ordenar elementos em uma lista ou vetor.
A lógica empregada neste método é representada pelo seguinte 
pseudocódigo:
para i = 1 até n faça
para j = 0 até n – 2 faça
se vetor[ j ] > vetor[ j + 1] então
trocar(vetor[ j ], vetor[ j + 1])
81Algoritmos de ordenação elementares
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
fim-se
fim-para
fim-para
A estratégia consiste em comparar um elemento do vetor com o pró-
ximo, iniciando da primeira posição e chegando até a penúltima. Se o 
próximo elemento for menor, ambos trocarão de posição. O algoritmo 
repetirá a mesma verificação para todas as próximas posições. Assim, 
em uma passada pelo vetor (n operações), o maior elemento será alo-
cado na última posição. Essa ação corresponde ao laço interno. Porém 
é necessário repeti-la n vezes para posicionar corretamente todos os 
elementos do vetor. Essa ação corresponde ao laço externo.
Como é possível observar, repetir n operações n vezes corresponde 
a um total de n² operações. Assim, a complexidade desse algoritmo é 
O(n2). No entanto, é possível otimizar dois aspectos:
1. Uma passada pelo vetor sem nenhuma ocorrência de alteração 
de posição dos elementos indica que ele já está ordenado e, por-
tanto, não é mais necessário repetir essas passadas até um total 
de n, podendo-se encerrar o algoritmo.
2. Cada passada não precisa percorrer todo o vetor, pois, garanti-
damente, os últimos elementos estão ordenados; assim, a cada 
passada, é necessário ir até o elemento anterior ao último orde-
nado na passada anterior.
A seguir, a implementação, incluindo as duas otimizações apontadas:
int[] vetor = { 99, 82, 50, 67, 90, 20, 71, 8, 21, 18 };
bool mudou = true;//1a otimização
int ultimo = vetor.Length-1;//2a otimização
int ultimo_temp = vetor.Length-1;
while (mudou)
{
int pos = 0;
mudou = false;
82 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
int temp = 0;
while(pos<ultimo)
{
if (vetor[pos] > vetor[pos+1])
{
temp = vetor[pos]; //
vetor[pos] = vetor[pos+1]; // troca
vetor[pos + 1] = temp; //
mudou = true;
ultimo_temp = pos;
}
pos++;
}
ultimo = ultimo_temp;
}
Nesse código, é criado um exemplo de vetor desordenado. A variável 
mudou será utilizada para indicar que houve uma troca de elementos 
em alguma passada pelo vetor (implementando a primeira otimização), 
e a variável ultimo armazenará a posição do último elemento posiciona-
do pela passada anterior (implementando a segunda otimização).
O algoritmo será executado (repete-se a passada) enquanto a vari-
ável mudou for true, ou seja, se na passada anterior tiver ocorrido uma 
troca de posições. A cada nova passada, começa-se pela posição inicial 
(pos = 0), e mudou inicia como false. Um novo laço controla o avanço da 
passada enquanto a posição verificada for menor que a última posição 
organizada do vetor. Caso o elemento da posição atualmente verificada 
seja maior do que o da próxima posição, ambos os valores são trocados 
(utilizando a variável temp como auxiliar na troca). Além disso, a variá-
vel mudou passa a receber valor verdadeiro, indicando que haverá uma 
nova passada ao final da atual, e a variável ultimo_temp receberá mo-
mentaneamente o valor da posição atual onde houve troca (caso ocorra 
uma nova troca nessa mesma passada, essa variável é atualizada). Ao 
final dessa passada, a variável ultimo receberá o valor armazenado em 
ultimo_temp, e, assim, a quantidade de passadas a serem executadas 
pelo laço em sua verificação (pos<ultimo) será reduzida.
83Algoritmos de ordenação elementares
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
IMPORTANTE 
Após a execução do algoritmo, recomendamos que você implemente 
uma impressão dos valores para constatar sua ordenação.
 
NA PRÁTICA
É interessante consultar algum recurso visual que demonstre passo a 
passo como os elementos são reposicionados dentro dovetor até sua 
completa ordenação. Uma indicação é a ferramenta disponibilizada 
pela University of San Francisco (GALLES, 2022).
 
2 Ordenação por seleção
A ordenação por seleção, ou selection sort, é outro método elementar 
de ordenação. Sua proposta é bem simples e de fácil implementação.
O algoritmo procurará o menor elemento a partir da posição inicial 
(0) e o trocará com o da posição 0. Em seguida, buscará o menor ele-
mento a partir da posição 1 e o trocará com o da posição 1 – repetindo 
o processo até ordenar todo o vetor.
O pseudocódigo desse algoritmo está expresso a seguir:
para i = 0 até n-1 faça
minimo := i
para j = i+1 até n faça
se vetor[j] < vetor[minimo] então
minimo := j
fim-se
84 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
fim-para
temp := vetor[i]
vetor[i] := vetor[minimo]
vetor[minimo] := temp
fim-para
Embora a complexidade desse algoritmo resulte em uma expressão 
quadrática mais a soma de outros fatores, como n e uma constante, 
costuma-se resumir a complexidade ao maior expoente, o que nos per-
mite simplificar esse cálculo para uma complexidade O(n²). De forma 
intuitiva, podemos estimar essa complexidade como uma estrutura de 
repetição dentro da outra, percorrendo todo o vetor durante as itera-
ções. Normalmente, essa estrutura de algoritmo indica uma possível 
complexidade de execução na ordem quadrática.
A implementação é realizada conforme o código a seguir:
int[] vetor = { 99, 82, 50, 67, 90, 20, 71, 8, 21, 18 };
int min, temp;
for (int i = 0; i < vetor.Length - 1; i++)
{
min = i;
for (int pos = (i + 1); pos < vetor.Length; pos++)
{
if (vetor[pos] < vetor[min])
{
min = pos;
}
}
if (vetor[i] != vetor[min])
{
temp = vetor[i];
vetor[i] = vetor[min];
vetor[min] = temp;
}
}
85Algoritmos de ordenação elementares
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
O algoritmo percorrerá todas as posições do vetor. Para cada posi-
ção, serão percorridas todas as restantes, armazenando-se o índice de 
menor valor. Ao final dessa passada, o valor do índice será trocado com 
o da posição inicialmente selecionada (se o valor de ambas for diferen-
te). O algoritmo repetirá essa ação até a última posição.
NA PRÁTICA
Para visualizar melhor a execução desse algoritmo, consulte Galles (2022).
 
3 Ordenação por inserção
Por fim, um dos últimos algoritmos de ordenação elementar é o de 
ordenação por inserção – ou insertion sort. 
A proposta desse algoritmo é comparar um elemento com todos os 
anteriores (que estarão ordenados), buscando colocá-lo na posição cor-
reta. Portanto, a cada passada, avançará a posição verificada e aumen-
tará a parte ordenada (inicial) do vetor.
Assim, a complexidade desse algoritmo corresponde a uma somató-
ria de n-1 repetições, e em cada repetição há uma inversão a mais a ser 
realizada (SZWARCFITER; MARKENZON, 2010). De forma simplificada, 
a complexidade corresponde a O(n2).
O pseudocódigo a seguir representa essa estratégia:
para i = 1 até n-1 faça
valor := vetor[i]
j := i – 1
enquanto j≥0 e valor < vetor[ j ] faça
vetor[ j + 1] := vetor[ j ]
86 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
j := j – 1
fim-enquanto
vetor[ j + 1] := valor
fim-para
O algoritmo inicia verificando e comparando a segunda posição com 
as anteriores – nesse caso inicial, somente com a primeira. Caso o va-
lor em sua posição atual (definido pela variável i) seja menor do que na 
posição comparada (definido pela variável j), a posição seguinte à com-
parada recebe o valor da posição em comparação (momentaneamente, 
ficam dois valores iguais em posições subsequentes). A repetição des-
sa ação serve para identificar o local em que o valor da posição i será 
colocado. Uma vez identificado o local, essa posição receberá o valor 
da posição i armazenado em valor, e o procedimento se repetirá até o 
último elemento do vetor.
A seguir, a implementação em código:
int[] vetor = { 99, 82, 50, 67, 90, 20, 71, 8, 21, 18 };
int num, pos_verificada;
for (int pos = 1; pos < vetor.Length; pos++)
{
num = vetor[pos];
pos_verificada = pos-1;
while (pos_verificada >= 0 && num<vetor[pos_verificada])
{
vetor[pos_verificada + 1] = vetor[pos_verificada];
pos_verificada--;
}
vetor[pos_verificada + 1] = num;
}
Essa implementação segue o proposto em pseudocódigo. Em có-
digo, a variável num corresponde a i; em pseudocódigo, a variável pos_
verificada corresponde a j. Um for repete a passada pelo vetor da se-
gunda até a última posição. Em cada passada, num armazena o valor 
da posição atual do elemento a ser deslocado, e pos_verificada inicia 
87Algoritmos de ordenação elementares
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
armazenando a posição anterior à posição do elemento (a cada repeti-
ção, essa posição é diminuída, procurando a posição adequada na qual 
incluir o elemento, até alcançar a posição inicial do vetor). 
Assim, enquanto não se alcançar um índice menor do que zero e o 
valor do elemento for menor do que o da posição verificada, a posição 
seguinte receberá o mesmo valor da verificada, e o índice da posição 
verificada diminuirá até que um valor seja maior do que o do elemento. 
Quando se encerrar essa passada, a posição seguinte à verificada rece-
berá o valor do elemento, posicionando-o no local correto, e uma nova 
passada será iniciada para o próximo elemento.
NA PRÁTICA
Confira, em Galles (2022), a execução em tempo real desse algoritmo.
 
Considerações finais
Existem diversos algoritmos para ordenar uma sequência de dados, 
e os de ordenação bolha, ordenação por seleção e ordenação por inser-
ção são os mais elementares. Eles apresentam uma complexidade na 
ordem de O(n2), o que revela uma eficiência relativamentre baixa. Mais 
adiante, abordaremos algoritmos que apresentam maior eficiência na 
ordenação, fazendo uso de outras técnicas, como a recursão, que será 
introduzida no próximo capítulo.
A ordenação de elementos é uma tarefa recorrente na programação; 
portanto, é essencial ter uma compreensão efetiva de suas técnicas e 
implementações. Se o pseudocódigo, a implementação e a descrição 
não forem suficientes para compreender a lógica da estratégia dos al-
goritmos, consulte Galles (2022) e simule diferentes ordenações para 
88 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.cada um deles, de modo a visualizar, passo a passo, como o algoritmo 
manipula cada valor da sequência.
Referências
GALLES, D. Comparison Sorting Algorithms. Disponível em: https://www.
cs.usfca.edu/~galles/visualization/ComparisonSort.html.Acesso em: 20 mar. 
2022.
SZWARCFITER, J. L.; MARKENZON, L. Estruturas de dados e seus algoritmos. 
Rio de Janeiro: LTC, 2010.
https://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html
https://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html
89
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Capítulo 6
Algoritmos 
recursivos
A recursividade é muito importante no desenvolvimento de algorit-
mos, constituindo uma alternativa às implementações iterativas e, por 
vezes, abrindo novas possibilidades para a solução de problemas.
Uma função iterativa é aquela que realiza uma série de repetições de 
uma mesma operação por meio de uma estrutura de repetição. As funções 
recursivas também repetem uma operação, mas com outra abordagem.
As funções podem naturalmente chamar outras para apoiar um tre-
cho da lógica. Contudo, as funções recursivas apresentam a caracte-
rística de chamar a si mesmas em algum ponto de seu algoritmo. Essa 
característica pode causar estranhamento, levando o iniciante a pensar 
que tais funções podem gerar um loop infinito. No entanto, para uma 
função recursiva funcionar, ela precisa ter um critério de parada bem 
definido, no qual as chamadas sucessivas a si mesma se encerrarão.
90 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
A seguir, você aprenderá a definir com cautela uma função recursi-
va. Serão mostrados os elementos que a função deve ter para funcio-
nar corretamente, o modo de visualizar essa sequência de chamadas 
e a maneira como isso auxilia na resolução do problema tratado pela 
função. Será apresentada a forma de testar uma função recursiva e 
serão discutidas as vantagens e desvantagens de seu uso em compa-
ração ao de uma função iterativa.
Esta é uma abordagem nova a problemas iterativos e, a princípio, 
pode soar um pouco confusa. No entanto, ao atentar ao conteúdo, im-
plementar as soluções indicadas e recorrer às fontes de referência para 
mais exemplos e prática, você dominará esse assunto, que é muito im-
portante na área de programação.
1 Definição de um problema recursivo
Normalmente, são criadas funções ou métodos para resolver um 
problema específico em um programa. Essa função corresponde a um 
algoritmo bem definido, que processa um valor de entrada, fornecendo 
um resultado. Até aqui, discutimos como abordar esses problemas de 
forma iterativa, o que envolve diversas instruções sucessivas, normal-
mente formadas por conjuntos de comandos como if, for e while, que 
desenvolvem a lógica necessária para tratar o problema.
Contudo, muitas vezes esses problemas podem ser tratados de ou-
tra forma. Quando um problema tem como característica repetir uma 
operação, pode-se buscar a construção de uma abordagem recursiva. 
Essa abordagem é caracterizada por inserir, dentro da função, uma cha-
mada a si mesma. Para ela funcionar, são necessários:
 • Um valor de entrada (parâmetro) para a função.
 • Uma operação sobre esse valor de entrada, para produzir outro 
valor (às vezes implícito).
91Algoritmos recursivos
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
 • Uma chamada para a própria função, passando como argumento 
um valor distinto ao que recebeu (normalmente, o valor resultante 
da operação anterior).
 • Um critério de parada, pelo qual a função encerrará as chamadas 
a si mesma.
Esses requisitos são necessários para que a função tenha êxito. Sem 
esses itens bem definidos, a função poderá incorrer em um loop infinito, 
chamando a si mesma indefinidamente. 
A fim de entender melhor como codificar a solução para um proble-
ma de forma recursiva, vamos conferir a solução iterativa para o conhe-
cido problema do cálculo de fatorial:
public static int fatIterativo(int numero)
{
int resultado = 1;
while (numero >= 1)
{
resultado = resultado * numero;
numero = numero - 1;
}
return resultado;
}
A função recebe um número, para o qual vai calcular o fatorial. O fa-
torial é a multiplicação de um número por todos os seus antecessores 
até o valor 1. Dessa forma, um laço será executado enquanto o número 
for maior ou igual a 1; dentro desse laço, uma variável que armazena o 
resultado temporário guardará a multiplicação do resultado atual pela 
variável numero e, em seguida, decrementará o valor do número. Esse 
loop continuará até o número valer 1.
Podemos identificar um padrão nessa solução: a multiplicação cons-
tante por um valor que, a cada repetição, vale uma unidade a menos. 
Também observamos que um critério de parada para a multiplicação é 
quando esse valor corresponder a 1. Com essas informações, podemos 
criar a solução recursiva para o problema:
92 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
public static int fatRecursivo(int numero)
{
if (numero == 1 || numero == 0)
return 1;
else
return numero * fatRecursivo(numero - 1);
}
Identificamos essa função como recursiva porque dentro de seu 
escopo há uma chamada para si mesma. Observamos que o primeiro 
critério é atendido: a função possui um valor de entrada. O segundo cri-
tério nessa função é implícito: a chamada recursiva passa como valor 
a variável numero subtraído 1 (como se tivesse ocorrido uma operação 
sobre esse valor, alterando o valor a ser passado como entrada para a 
chamada recursiva). O terceiro critério também é atendido: na chamada 
recursiva (a chamada da função a si mesma dentro do seu escopo), 
é passado um valor diferente do recebido (a função recebe um valor 
armazenado pelo parâmetro numero, e, na chamada recursiva, o argu-
mento é o valor dessa variável subtraído 1). O quarto critério está dentro 
do bloco if: caso a variável seja 1 ou 0, é retornado um valor, e a função 
não é mais chamada, encerrando-se assim as chamadas recursivas.
Até aqui, analisamos estruturalmente a função; agora, vamos pros-
seguir para o entendimento da lógica. Suponhamos que seja passado o 
valor 3 para essa função. A execução prossegue para o bloco else. Na 
linha de return, é chamada novamente a mesma função; portanto, só é 
possível retornar algum valor após concluída a execução dessa chama-
da. A nova chamada será feita com o valor de numero – 1; logo, com o 
valor 2. A mesma lógica se repetirá e, na chamada da função, será pas-
sado o valor 1. Agora, dentro dessa segunda chamada recursiva, o crité-
rio de parada será atingido: o bloco if será executado, retornando o valor 
1, que encerra a execução da segunda chamada recursiva. O resultado 
1 tem que ser multiplicado pelo valor de numero da chamada recursiva 
anterior (2). 2 × 1 = 2 – esse valor será o retorno da primeira chamada 
recursiva, retornando assim para a execução original dessa função. No 
ponto inicial, ainda temos que fazer uma multiplicação antes de retornar 
93Algoritmos recursivos
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução eo com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
o valor final. Essa multiplicação é 3 (valor de numero nesse ponto) × 2 
(retorno da chamada recursiva), que equivale a 6. Este é o resultado da 
função: o fatorial de 3, de fato, é 6.
NA PRÁTICA 
Confira em Galles (2022) a implantação recursiva do algoritmo de Fi-
bonacci em tempo real, com a indicação dos valores de cada variável a 
cada passo da execução.
 
Vamos a outro exemplo: o cálculo do n-ésimo termo da sequência de 
Fibonacci. Essa sequência começa com os dois primeiros termos valendo 
1; a partir do terceiro, os termos correspondem à soma dos dois anteriores. 
Esta é a solução iterativa:
public static int fibIterativo(int numero)
{
int num1 = 1;
int num2 = 1;
int proxNum = 0;
for (int i = 3; i <= numero; i++)
{
proxNum = num1 + num2;
num1 = num2;
num2 = proxNum;
}
return proxNum;
}
Nessa função, passado o número do termo desejado na sequência 
de Fibonacci, inicialmente são definidos os dois primeiros termos com o 
valor 1. Em seguida, um for começa percorrendo do terceiro termo até o 
valor do termo desejado. Para cada iteração, o próximo número é deter-
minado como a soma dos dois anteriores; o primeiro número é atualiza-
do com o valor do segundo; e o segundo número é atualizado com o va-
lor da soma. Ao final das iterações, é retornado o último valor calculado.
94 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.A solução recursiva é mais resumida, porém tem algumas 
peculiaridades:
 public static int fibRecursivo(int numero1, int numero2, int 
numeroSequencia)
{
if (numeroSequencia > 1)
 return fibRecursivo(numero2, numero1 + numero2, 
--numeroSequencia);
else
return numero1;
}
Perceba que, em comparação com a solução iterativa, há mais pa-
râmetros de entrada. A proposta é que, a cada chamada recursiva, o 
valor do termo informado seja subtraído; assim, as chamadas cessa-
rão quando esse valor for 0. Enquanto o valor for maior que 1, uma 
nova chamada será realizada com os parâmetros atualizados: o que 
era numero1 passa a ser numero2; o que era numero2 passa a ser a 
soma de numero1 com numero2; e do número do termo é subtraído 1. 
Essas chamadas se repetirão até que o número do termo (numeroSe-
quencia) seja 0, executando, assim, o bloco else e atingindo o critério 
de parada: é retornado o valor de numero1 (termo desejado). Esse va-
lor é retornado, então, para a chamada anterior (dentro de um if), que 
também retornará o valor para a chamada anterior, e assim sucessiva-
mente, até a chamada inicial.
Com esses exemplos, percebemos que não existe uma estrutura exa-
ta para construir uma função recursiva: cada problema pode exigir uma 
abordagem diferente. Contudo, os seguintes elementos devem estar pre-
sentes para que essa função tenha sucesso: 
 • Uma chamada recursiva a si mesma com parâmetros sempre 
diferentes.
 • Um critério de parada para evitar o loop infinito.
95Algoritmos recursivos
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
PARA SABER MAIS 
Uma função iterativa normalmente é mais rápida do que uma função re-
cursiva. A função recursiva cria, a cada nova chamada a si mesma, uma 
cópia de suas variáveis e, portanto, utiliza mais memória, onerando mais o 
sistema durante sua execução. A função recursiva costuma ser mais su-
cinta do que a iterativa, apresentando mais clareza no algoritmo e maior 
proximidade com a notação matemática dos problemas que representa.
 
2 Estratégia para escrever um algoritmo 
recursivo
Um problema recursivo é representado pelo princípio matemático da 
indução, por meio do qual partimos da observação de diversos casos 
particulares para estabelecer uma conclusão. A demonstração da solu-
ção pelo método da indução contém duas partes:
1. Passo base: solução para o caso mais básico.
2. Passo indutivo: solução para os demais casos, sendo cada um 
expresso em função do anterior.
Por exemplo, vamos demonstrar por indução que todo número ím-
par somado a um número par resulta em um número ímpar.
O passo base inicial é identificar o menor número natural ímpar, que, 
por definição, é 1. Podemos, então, fazer uma série de observações: 1 + 
2 = 3 (ímpar); 3 + 2 = 5 (ímpar); 5 + 2 = 7 (ímpar), e assim sucessivamen-
te. Dessa forma, podemos concluir, por indução, que um número ímpar 
somado a um número par resulta em um número ímpar. 
É possível expressar essa observação de modo mais formal: um nú-
mero ímpar (fora o passo base) é representado pelo número ímpar 
96 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.anterior mais 2. Primeiro, vamos representar todos os números ímpares 
em uma sequência:
3 17 19 26 50 52
Podemos, agora, expressar que um número n+1 nessa sequência 
equivale a n + 2.
Por fim, podemos representar matematicamente nossa solução 
completa como:
PASSO BASE: para n = 1, n é ímpar.
PASSO INDUTIVO: para n+1 = n + 2, n+1 é ímpar.
Esse processo matemático pode ser aplicado na prática para resol-
ver um problema de computação e é a essência da recursividade.
Outro exemplo: definir a multiplicação de dois números inteiros não 
negativos, m e n, em termos da operação de adição. Observe a solução 
iterativa:
public static int multIterativa(int m, int n)
{
int r = 0;
for (int i=1; i<= n; i++)
{
r += m;
}
return r;
}
Basicamente, o que a função executa é uma repetição por n vezes, 
somando o valor de m a uma variável do resultado. Logo, isso equivale 
a uma multiplicação de m por n.
97Algoritmos recursivos
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Agora, vamos pensar na solução indutiva para esse problema. Primeiro, 
temos que identificar o passo base. Qual seria um valor para m ou n que 
nos permitiria apontar com certeza o resultado da multiplicação, indepen-
dentemente do outro termo? A resposta é zero, pois o valor zero multipli-
cado por qualquer outro termo resulta em zero.
Passo base: se n ou m é igual a 0, a multiplicação é 0.
Agora, vamos pensar em uma expressão para indicar de forma ge-
nérica (independentemente dos valores de m ou n) qual é o resultado 
de uma multiplicação, em função do valor anterior de um dos termos. 
Como discutido anteriormente, a multiplicação de n por m é igual à 
soma do valor de m, por n vezes. Logo, poderíamos dizer que isso equi-
vale à soma de m com m multiplicada por n – 1.
Passo indutivo: m × n = m + ( m × (n – 1) )
Esses dois passos, em conjunto, expressam a solução indutiva para 
o problema. Observe o exemplo da figura 1 para a multiplicação 3 × 4.
Figura 1 – Passos indutivos até alcançar o caso base
3 × 4 = ? 
3 × 4 = 3 + (3 × (4 – 1))
 3 × 3 = 3 + (3 × (3 – 1))
 3 × 2 = 3 + (3 × (2 – 1))
 
 3 × 1 = 3 + (3 × (1 – 1))3 × 0 = 0 CASO BASE
98 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Perceba como uma sequência indutiva acaba alcançando o caso 
base, no qual encerra sua sequência. Contudo, um valor foi alcançado 
e, com isso, pode-se encerrar cada um dos passos indutivos anteriores. 
Confira como isso ocorre, passo a passo, na figura 2.
Figura 2 – Retorno de cada passo indutivo até a obtenção do resultado final
3 × 4 = 3 + 3 + 3 + 3 = 12
 
 3 + 3 + 3 + 3 + 0 
3 × 4 = 3 + (3 × (4 – 1) ) 3 + 3 + 3 + 0
 3 × 3 = 3 + (3 × (3 – 1) )
 3 × 2 = 3 + ( 3 × (2 – 1 )) 
 3 × 1 = 3 + 3 × (1 – 1)) 
 
 3 × 0 = 0
 3 + 3 + 0
3 + 0 
Perceba como uma solução encontrada no quarto passo (alcançan-
do o passo base) serve para identificar uma solução no terceiro passo, a 
qual, por sua vez, fornece uma solução para o segundo passo. Finalmente, 
a solução para o segundo passo devolve um valor para o passo inicial, 
podendo-se, assim, encontrar a solução geral para o problema.
Esse procedimento matemático é muito similar ao que ocorre quan-
do programamos um algoritmo recursivo. Note como ficaria a imple-
mentação dessa solução em código:
99Algoritmos recursivos
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
public static int multRecursiva(int m, int n)
{
if (n==0)
{
return 0;
}
else
{
return m + multRecursiva(m, n - 1);
}
}
A função recursiva contém exatamente os dois passos da demons-
tração por indução matemática: o passo base, dentro do bloco if; e o 
passo indutivo, dentro do bloco else. Seguir essa abordagem matemá-
tica, dividindo o problema nesses dois passos, pode ajudar muito na 
codificação de um algoritmo recursivo.
3 Teste de mesa para um algoritmo recursivo
Talvez você já tenha percebido que expressar claramente a sequên-
cia de passos executados, como no subcapítulo anterior, pode auxiliar 
na compreensão da execução do algoritmo e, quando a lógica estiver 
falha, na identificação dos erros para prosseguir com as correções 
necessárias.
A seguir, demonstramos como realizar um teste de mesa para verifi-
car a alteração de variáveis e a sequência lógica do algoritmo recursivo. 
Vamos adotar o mesmo algoritmo do subcapítulo anterior e realizar a 
multiplicação 3 × 2.
100 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
PASSO 1
No primeiro passo, há a execução da primeira instância da função, 
ou seja, sua primeira chamada. Em memória, ocorre a criação da vari-
ável m com valor 3 e da variável n com valor 2, mas ainda não há um 
resultado, pois uma nova chamada foi realizada.
PASSO 2
101Algoritmos recursivos
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Uma nova chamada é realizada, gerando uma segunda instância da 
função. É dobrado o espaço em memória, criando novas variáveis m e n.
PASSO 3
Mais uma chamada à função é realizada, e mais variáveis são cria-
das em memória.
PASSO 4
102 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.Desta vez, pelo valor de n ser 0, a execução alcançou o bloco if, o qual 
contém o passo base, encerrando assim a sequência recursiva, com o 
valor 0 retornado como resultado dessa última chamada.
PASSO 5
Como a última função retornou um valor repassado para a chama-
da anterior, os valores das variáveis de sua instância podem ser retira-
dos da pilha de execução (que estava ocupando espaço em memória). 
Como havia sido retornado 0, esse valor foi somado ao valor de m (3); o 
resultado foi retornado para a chamada anterior.
103Algoritmos recursivos
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
PASSO 6
Novamente, as variáveis da chamada recursiva que se encerrou fo-
ram desalocadas da memória, e o resultado retornado (3) foi somado 
com m (valor 3) para retornar, assim, o valor 6.
PASSO 7
104 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
O resultado de 6 é o retorno da primeira instância, da chamada ori-
ginal da função. Suas variáveis são retiradas da memória, pois toda a 
chamada recursiva se encerrou, retornando como resultado final o valor 
6, que, de fato, corresponde à multiplicação 2 × 3.
Esta é uma estratégia interessante para testar a lógica de sua função: 
criar um teste de mesa por meio de uma tabela que armazena todas as va-
riáveis ao longo da execução, empilhar os valores de acordo com o avanço 
da chamada recursiva e, então, ao alcançar o caso base, ir retirando esses 
valores de acordo com o encerramento de cada chamada recursiva.
Perceba também como uma função recursiva pode levar a um alto 
consumo de memória. Por isso, seu uso deve ser sempre bem pondera-
do e comparado com o da solução iterativa equivalente. Porém, em al-
guns casos, o uso de recursividade traz grandes vantagens, como será 
explorado no próximo capítulo.
Considerações finais
O primeiro contato com algoritmos recursivos pode dar a impressão 
de que esse é um tópico mais difícil do que a implementação iterativa. 
Porém, com a prática, a experiência, o estudo e, claro, a implementação 
desses algoritmos, o método se tornará mais claro e de uso natural em 
seus programas.
Lembre-se: qualquer problema que pode ser resolvido recursivamen-
te também pode ser resolvido iterativamente. Uma abordagem recursi-
va, em geral, é preferida em relação a uma abordagem iterativa quando 
espelha mais naturalmente o problema e resulta em um programa de 
compreensão mais fácil. A abordagem recursiva pode ser implemen-
tada com menos linhas de código, sendo, portanto, uma opção mais 
concisa, apresentando um programa mais simples (SZWARCFITER; 
MARKENZON, 2010). Contudo, a cópia dos parâmetros a cadachamada 
recursiva é um custo adicional para as soluções desse tipo. Evite utilizar 
105Algoritmos recursivos
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
a recursão em situações que requerem alto desempenho do programa: 
chamadas recursivas levam tempo e consomem memória adicional.
A recursividade é um conceito importante na computação e será es-
sencial para a sequência do nosso estudo, em que trabalharemos com 
algoritmos de ordenação mais avançados, que utilizam a recursão para 
serem mais eficientes do que os estudados anteriormente.
Referências
GALLES, D. Recursive Factorial. Disponível em: https://www.cs.usfca.
edu/~galles/visualization/RecFact.html. Acesso em: 26 mar. 2022.
SZWARCFITER, J. L.; MARKENZON, L. Estruturas de dados e seus algoritmos. 
Rio de Janeiro: LTC, 2010.
https://www.cs.usfca.edu/~galles/visualization/RecFact.html
https://www.cs.usfca.edu/~galles/visualization/RecFact.html
107
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Capítulo 7
Algoritmos de 
ordenação 
eficientes
Dando continuidade aos algoritmos de ordenação elementares apre-
sentados no capítulo 5, aqui serão abordados dois algoritmos mais efi-
cientes, o MergeSort e o QuickSort.
Ambos se utilizam da recursão para executar suas estratégias. O 
MergeSort e o QuickSort empregam o princípio da divisão e conquis-
ta para dividir o vetor original em partes menores e, assim, facilitar a 
ordenação em partes localizadas. Cada parte dessa divisão executa 
uma nova chamada ao mesmo método de ordenação, e por isso ocor-
re a recursão.
O algoritmo MergeSort realiza duas chamadas recursivas (dividindo 
o vetor em duas partes) e, em seguida, faz uma intercalação (ordenação 
dos elementos dessas duas partes). Já o QuickSort inicia com um parti-
cionamento (procurando um ponto de divisão chamado "pivô", elemen-
to considerado ordenado em definitivo no vetor), que será utilizado para 
108 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
dividir o vetor em duas partes e, em seguida, realiza duas chamadas re-
cursivas para cada uma das partes. São estratégias parecidas, mas que 
têm suas peculiaridades, as quais conferiremos em detalhes adiante.
Esse tema representa o ponto derradeiro da trajetória de aprendiza-
do que se iniciou no primeiro capítulo. Neste capítulo, vemos os temas 
de vetor, ordenação em vetor e recursão, todos previamente abordados, 
unidos em um conhecimento completo, que atestará seu domínio sobre 
todo o conteúdo apresentado até o momento.
Se ainda restar alguma dúvida sobre os temas anteriores, este é um 
bom momento para fazer uma revisão antes de prosseguir. Iniciaremos 
a abordagem de um tema desafiador, mas muito interessante e en-
grandecedor para o seu progresso como programador. Cada algoritmo 
é apresentado em um exemplo com detalhes; portanto, concentre-se, 
tenha paciência: sua compreensão é fundamental para coroar o apren-
dizado obtido neste livro.
1 MergeSort – execução e análise de 
complexidade
O algoritmo de ordenação MergeSort se baseia na estratégia de divi-
são e conquista, abordada no capítulo 4. Nessa estratégia, um problema 
maior é dividido em partes menores, mais fáceis de ser solucionadas, 
e a junção de todas essas soluções leva à solução do problema maior 
(original). Para a ordenação, a estratégia é dividir o vetor sucessivamente 
pela metade até a menor divisão possível (um elemento em cada parte), 
sendo este o caso mais simples de ser ordenado.
Porém, mais um recurso deve ser empregado nesse algoritmo: a re-
cursão. Ao obter a menor solução, é necessário retornar esse resultado 
para a divisão anterior, onde ele será unido com o resultado da outra 
parte da divisão (essa é uma característica da recursão). Portanto, esse 
algoritmo se baseia em duas chamadas recursivas: uma para a primeira 
109Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
metade e outra para a segunda metade do vetor. Cada chamada, por 
sua vez, iniciará outras duas chamadas para as metades do vetor que 
recebeu, e assim sucessivamente, até alcançar a menor divisão pos-
sível e conseguir ordenar dois elementos (caso base). A partir desse 
ponto, os resultados começarão a retornar para a chamada original.
Antes de visualizar a implementação do código, veremos um exem-
plo passo a passo do funcionamento da lógica desse algoritmo.
Inicialmente, temos um vetor não ordenado, no qual é calculado o 
ponto central:
meio
5 3 91 7 2 54 38
A primeira chamada recursiva do primeiro nível é realizada para a pri-
meira metade desse vetor, e é verificado se a posição do início do vetor 
é menor do que a posição do fim:
meio
5 3 91 7 2 54 38
meio
5 3 91 7
A primeira chamada recursiva do segundo nível é realizada, dividindo 
novamente o vetor:
meio
5 3 91 7 2 54 38
meio
5 3 91 7
meio
5 3 1
110 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
A primeira chamada recursiva do terceiro nível é realizada:
meio
5 3
meio
5 3 91 7 2 54 38
meio
5 3 91 7
meio
5 3 1
A primeira chamada recursiva do quarto nível é executada, pois ainda 
é possível dividir esse vetor:
fim
5
meio
5 3
meio
5 3 91 7 2 54 38
meio
5 3 91 7
meio
5 3 1
Agora foi alcançado o critério de parada (início igual ao fim); assim, 
não há mais chamadas recursivas dentro da primeira chamada. Porém, 
encerrando essa chamada e retornando para o nível anterior, a segunda 
chamada recursiva do quarto nível é executada para a segunda parte do 
vetor (nesse caso, somente o elemento 3):
111Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
fim
5
fim
Ordenar
3
meio
5 3
meio
5 3 91 7 2 54 38
meio
5 3 91 7
meio
5 3 1
Novamente, como foi alcançado o critério de parada, a chamada re-
cursiva é encerrada. Retornando para o nível anterior, logo após as duas 
chamadas recursivas, há uma chamada para um método de intercalar 
as duas partes do vetor, no qual, basicamente, elas serão ordenadas. A 
estratégia é comparar elemento a elemento a partir das duas primeiras 
posições das duas partes do vetor. O elemento que for menor ficará 
mais à esquerda, e assim sucessivamente. Esse método pode se encer-
rar sem ter varrido todos os elementos de um dos dois vetores; nesse 
caso, os elementos restantes de um dos vetores podem simplesmente 
ser copiados para a parte do vetor anterior. Por enquanto, isso pode 
não ficar muito claro, pois só há um elemento em cada vetor, mas esse 
ponto voltará a ser comentado mais adiante.
112 Algoritmos e programação II comC# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
fim
5
fim
3
meio
5 3
meio
5 3 91 7 2 54 38
meio
5 3 91 7
meio
5 3 1
3,5
O método intercalar reordenou os elementos, e assim se encerrará 
esse nível da chamada recursiva, voltando para o terceiro nível, com a 
solução de sua primeira chamada recursiva:
3 5
meio
5 3 91 7 2 54 38
meio
5 3 91 7
meio
5 3 1
Encerrada a ordenação da primeira parte do vetor, essa chamada 
recursiva pode prosseguir para a segunda chamada recursiva (apenas 
o elemento 1):
113Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
fim
13 5
meio
5 3 91 7 2 54 38
meio
5 3 91 7
meio
5 3 1
Como já alcançou o ponto de parada, essa chamada é encerrada e 
retornada. Agora, o método intercalar pode ser chamado para organizar 
as duas metades:
13 5
meio
5 3 91 7 2 54 38
meio
5 3 91 7
meio
5 3 1
1,?,?
1,3,5
Nesse caso, o primeiro elemento da primeira metade (3) é compa-
rado com o primeiro elemento da segunda metade (1). O 1 é menor e, 
portanto, fica na primeira posição da ordenação. A segunda metade já 
foi toda verificada; logo, todo o restante da primeira metade (elementos 
3 e 5) pode ser colocado diretamente no final da ordenação, pois, asse-
guradamente, está ordenado e é maior do que os valores já ordenados:
114 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
meio
5 3 91 7 2 54 38
meio
5 3 91 7
1 3 5
Encerrado o terceiro nível, há o retorno da primeira chamada do se-
gundo nível. Agora, é executada a segunda chamada recursiva para os 
elementos 9 e 7:
meio
5 3 91 7 2 54 38
meio
meio
5 3 91 7
1 3 5 9 7
Ainda é possível avançar mais um nível:
Ordenar
meio
fim fim
5 3 91 7 2 54 38
meio
meio
5 3 91 7
1 3 5 9 7
9 7
115Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Inicialmente, é realizada a primeira chamada recursiva para o ele-
mento 9, na qual se alcançará o critério de parada. Logo em seguida, é 
executada a segunda chamada recursiva, que também encontrará o cri-
tério de parada. Então, o algoritmo prossegue para o método de interca-
lar as duas metades:
7,9
meio
fim fim
5 3 91 7 2 54 38
meio
meio
5 3 91 7
1 3 5 9 7
9 7
O resultado ordenado é atualizado no vetor:
1,?,?,?,?
1,3,?,?,?
1,3,5,?,?
1,3,5,7,9
meio
5 3 91 7 2 54 38
meio
5 3 91 7
1 3 5 9 7
Organizadas as duas metades, o método intercalar do segundo ní-
vel é executado. Perceba que, após definir a ordenação 1, 3, 5, toda a 
primeira metade terá sido ordenada; logo, toda a segunda metade (ele-
mentos 7 e 9) poderá, de uma vez só, ser inserida ao final da ordenação:
116 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
meio
5 3 91 7 2 54 38
1 3 75 9
Com a primeira metade do vetor original ordenada, é executada a se-
gunda chamada recursiva do primeiro nível, e todo o processo visto acima 
é repetido. Ao final, as duas metades são organizadas:
meio
5 3 91 7 2 54 38
1 3 75 9 2 3 54 8
Então, o método intercalar é chamado para organizar as duas 
metades:
1,?,?,?,?,?,?,?,?,?
1,2,?,?,?,?,?,?,?,?
1,2,3,?,?,?,?,?,?,?
1,2,3,3,?,?,?,?,?,?
1,2,3,3,4,?,?,?,?,?
1,2,3,3,4,5,?,?,?,?
1,2,3,3,4,5,5,?,?,?
1,2,3,3,4,5,5,7,?,?
1,2,3,3,4,5,5,7,8,?
1,2,3,3,4,5,5,7,8,9
meio
5 3 91 7 2 54 38
1 3 75 9 2 3 54 8
E assim é obtido o vetor ordenado:
1 2 33 4 5 75 98
117Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Agora que conferimos um exemplo da lógica de funcionamento do 
MergeSort, temos a seguir o código de implementação:
static void Main(string[] args)
{
int[] vetor = { 5, 3, 1, 9, 7, 2, 4, 5, 8, 3 };
merge(vetor,0,vetor.Length-1);
for (int i=0; i<vetor.Length; i++)
Console.Write(vetor[i]+" ");
}
No método main, você pode iniciar criando um vetor não ordenado, 
chamando o método recursivo merge (informando o vetor a ser ordena-
do e o início e o final da parte a ser ordenada, que, inicialmente, é o vetor 
todo). O for, ao final, imprimirá os valores ordenados:
public static void merge(int[] vetor, int inicio, int fim)
{
int meio;
if (inicio < fim)
{
meio = (inicio + fim) / 2;
merge(vetor,inicio,meio);
merge(vetor,meio+1,fim);
intercalar(vetor,inicio,fim,meio);
}
}
O método merge, como descrito anteriormente, realiza outras duas 
chamadas a si mesmo. A primeira é realizada para a primeira metade 
do vetor recebido, e a segunda, para a segunda metade. Após as duas 
chamadas, é chamado o método intercalar, que organizará os elemen-
tos das suas partes. Quando o início for igual ao fim do vetor, ou seja, 
quando houver só um elemento da metade, não serão mais realizadas 
chamadas recursivas:
118 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
 public static void intercalar(int[] vetor, int inicio, int
fim, int meio)
{
int[] vetor_aux = new int[vetor.Length];
int inicio_vetor1 = inicio;
int inicio_vetor2 = meio + 1;
int pos_livre = inicio;
while (inicio_vetor1 <= meio && inicio_vetor2 <= fim)
{
if (vetor[inicio_vetor1] <= vetor[inicio_vetor2])
{
vetor_aux[pos_livre] = vetor[inicio_vetor1];
inicio_vetor1++;
}
else
{
vetor_aux[pos_livre] = vetor[inicio_vetor2];
inicio_vetor2++;
}
pos_livre++;
}
 //se ainda existem números no final do primeiro vetor que 
//não foram intercalados
for (int i=inicio_vetor1; i<=meio; i++)
{
vetor_aux[pos_livre] = vetor[i];
pos_livre++;
}
 //se ainda existem números no final do segundo vetor que 
//não foram intercalados
for (int i = inicio_vetor2; i <= fim; i++)
{
vetor_aux[pos_livre] = vetor[i];
pos_livre++;
}
 //substitui os valores ordenados do "vetor_aux" para o 
//"vetor"
for (int i = inicio; i <= fim; i++)
vetor[i] = vetor_aux[i];
}
119Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Para armazenar os resultados temporários da ordenação, o método 
intercalarutiliza um vetor auxiliar de tamanho equivalente ao vetor a 
ser organizado. A implementação desse método deve ser muito bem 
analisada, pois ele pode onerar mais o sistema se for executado para 
um conjunto de dados muito grande e com pouca memória disponível.
Dentro do laço while, as duas metades do vetor são varridas e com-
paradas posição a posição, e, conforme identificados os menores ele-
mentos, estes são copiados no vetor auxiliar. Perceba que esse laço 
se encerra quando terminar a verificação de uma ou outra metade. Por 
isso, os dois próximos for servem para verificar se há elementos que 
não foram verificados em alguma das metades e, assim, devidamente 
copiados ao final do vetor auxiliar. Então, o último for copia as posições 
organizadas no vetor auxiliar de volta para o vetor original.
IMPORTANTE 
Conforme discutido no primeiro capítulo, a alteração dos elementos em 
um vetor passado por uma função (por exemplo, uma chamada recur-
siva) vai alterar os valores do vetor original, pois este é passado por 
referência. Por isso, a ordenação do vetor nas chamadas recursivas 
provoca a ordenação do vetor original no primeiro nível.
 
Quanto à eficiência do MergeSort, podemos observar que o tempo 
de trabalho executado corresponde à equação:
T(n) = 2 × T(n/2) + n
Em que: n é a quantidade de elementos a serem ordenados; T(n/2) 
se refere ao trabalho de execução das chamadas recursivas, que cor-
respondem à ordenação das metades do vetor (por isso a multiplica-
ção por 2); e n é o tempo para criar os subproblemas (novas divisões). 
Logo, a complexidade final corresponde a uma soma dessa equação, 
120 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.sucessivamente dividida pela metade (SZWARCFITER; MARKENZON, 
2010). A complexidade final é representada a seguir:
O(n log n)
NA PRÁTICA
Confira a execução em tempo real do funcionamento do MergeSort 
(GALLES, 2022).
 
2 QuickSort – execução e análise de 
complexidade
De modo semelhante ao MergeSort, o algoritmo de ordenação 
QuickSort também se baseia na estratégia de divisão e conquista e na 
recursão. Porém, primeiramente, é executado um método para definir 
o ponto do vetor em que ocorrerá a divisão (chamado de "pivô"). Para 
relembrar: no MergeSort essa divisão ocorre sempre no meio, porém o 
pivô nem sempre será no meio do vetor. Definido o pivô, ocorrem duas 
chamadas recursivas: uma para a metade anterior e outra para a meta-
de posterior do pivô.
Uma característica interessante desse algoritmo é que, ao definir um 
pivô, esse elemento já está, em definitivo, posicionado no vetor. Ou seja, 
todos os elementos à sua esquerda serão menores ou iguais a si, e os 
elementos à direita, maiores.
A estratégia consiste em, dado um conjunto de elementos, iniciar o 
pivô como sendo o primeiro elemento (há outras estratégias de defini-
ção do pivô, mas adotaremos esta), o primeiro elemento como sendo a 
variável esq e o último elemento como dir. Enquanto o elemento esq for 
menor ou igual ao pivô, este terá seu valor atualizado com o elemento à 
121Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
direita; enquanto o elemento dir for maior que o pivô, este terá seu valor 
atualizado com o elemento à esquerda. Quando ambos pararem de alte-
rar seus valores, o valor de esq será trocado com o de dir, mas suas po-
sições no vetor serão mantidas. Então, esse ciclo se repetirá até que o 
valor de dir seja menor ou igual a esq. Quando isso ocorrer, o valor de dir 
será trocado com o do pivô, e a posição em que se encontra dir será um 
novo pivô, que encadeará uma nova divisão, com duas novas chamadas 
recursivas. Esse processo será repetido até que ocorram divisões com 
um elemento, caso base para encerrar a recursão.
Assim como foi feito para o subcapítulo anterior, veremos primeira-
mente um exemplo de aplicação do QuickSort em um passo a passo 
que evidenciará o funcionamento da lógica do algoritmo.
Inicialmente, temos um vetor não ordenado, com pivo e esq defini-
dos para o primeiro elemento, e dir para o último:
5 3 91 7 2 54 38
pivo
esq dir
A variável esq altera seu índice para a direita até encontrar um valor 
maior do que o pivo:
5 3 91 7 2 54 38
pivo
esq dir
Terminada a alteração da variável esq, a variável dir começa a decre-
mentar seu índice até encontrar um valor menor do que o pivo. Nesse 
caso, como o elemento atual apontado por dir já é menor do que o pivo, 
essa variável permanece como dir:
5 3 91 7 2 54 38
pivo
esq dir
122 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
O próximo passo é trocar o valor apontado pelas duas variáveis: 
5 3 91 7 2 54 38
pivo
esq dir
Como esq ainda é menor do que dir, o processo recomeça. A variável 
esq continua avançando até apontar para um valor maior do que o pivo:
5 3 31 7 2 54 98
pivo
esq dir
E a variável dir decrementa até apontar para um valor menor ou 
igual ao pivo:
5 3 31 7 2 54 98
pivo
esq dir
Ambas as posições trocam de valor:
5 3 31 5 2 74 98
pivo
esq dir
Como esq continua sendo menor do que dir, o processo se reinicia, 
com a variável esq incrementando até apontar para um elemento maior 
do que o pivo:
5 3 31 5 2 74 98
pivo
esq
dir
123Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
E a variável dir decrementa até apontar para um elemento menor ou 
igual ao pivo:
5 3 31 5 2 74 98
pivo
esqdir
Finalmente, foi atingido o caso em que dir é menor ou igual a esq. 
Desta vez, serão trocados os valores apontados por pivo e dir:
pivo
5 3 31 5 2 74 98
esqdir
Agora, o novo valor na posição dir corresponde a um novo pivô. Todo 
esse processo para a definição de um novo pivô é o método particionar. 
O valor apontado pelo pivô corresponde a um valor posicionado em de-
finitivo no vetor. Ou seja, ele não será mais retirado dessa posição. Logo, 
todos os elementos anteriores ao pivô são menores ou iguais a ele, e os 
elementos à direita são maiores:
4 3 31 5 2 75 98
pivo
Terminada a execução do método particionar, são realizadas duas 
chamadas recursivas, uma para a parte do vetor à esquerda e outra 
para a parte do vetor à direita do pivô. Assim como no MergeSort, ini-
cia-se a primeira chamada, e assim sucessivamente, até encontrar o 
critério de parada, que retornará à chamada anterior, e somente assim 
poderá prosseguir para a segunda chamada recursiva. Portanto, nesse 
ponto, é realizada a primeira chamada recursiva para os seis elementos 
à esquerda do pivô:
124 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
dito
ra
 S
en
ac
 S
ão
 P
au
lo
.
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
4 3 31 5 2
dir
pivo
esq
Nessa nova chamada, primeiramente será executado o método 
particionar; portanto, todo o processo anterior de troca dos valores de 
esq e dir será executado até a definição de um novo pivô. A variável 
esq incrementará até apontar para o elemento 5, e a variável dir per-
manecerá com o mesmo valor:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
4 3 31 5 2
dir
pivo
esq
Ambas trocarão de valor:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
4 3 31 2 5
dir
pivo
esq
125Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
A variável esq incrementará até apontar para o 5, e a variável dir de-
crementará até apontar para o 2:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
4 3 31 2 5
esq
pivo
dir
A variável dir é menor do que esq; logo, dir trocará de valor com pivo:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
4 3 31 2 5
dirpivo esq
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
pivo
Um novo pivô foi identificado. Mais um vez, isso indica que, nessa 
posição do vetor original, tal valor está definido e não será mais alte-
rado. Novamente, é realizada a primeira chamada recursiva desse nível 
para os quatro elementos à esquerda do pivô:
126 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
2 3 31
pivo
pivo
esq dir
A variável esq avança até encontrar um valor maior do que o pivo, e a 
dir recua até encontrar um valor menor:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
2 3 31
pivo
pivo
esq dir
Ambas trocam de valor:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
2 1 33
pivo
pivo
esq dir
127Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
A variável esq continua a avançar até encontrar um valor maior do 
que o pivo, e a dir recua até encontrar um valor menor:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
2 1 33
pivo
pivo
dir esq
A variável dir é menor do que esq; logo, dir troca de valor com pivo, e 
um novo pivo é definido na posição de dir:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
1 2 33
pivo
pivo
Na próxima primeira chamada recursiva para o vetor da esquerda, 
por haver apenas um elemento (valor 1), será alcançado o critério de pa-
rada; logo, nenhuma ação será realizada, e esse elemento permanecerá 
em definitivo nessa posição do vetor (primeira posição):
128 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
1 2 33
pivo
pivo
Agora, será realizada a segunda chamada recursiva para os elemen-
tos 2 e 3.
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
1 2 33
33
pivo
pivo
pivo
esq dir
129Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
A variável esq avançará, e a variável dir ficará na mesma posição:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
1 2 33
33
pivo
pivo
pivo
esq
dir
O valor de pivo será trocado com o de dir (neste caso, o valor é o 
mesmo), e dir será definido como um novo pivo.
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
1 2 33
33
pivo
pivo
pivo
130 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Uma nova primeira chamada recursiva será feita. Como há apenas 
um elemento, será atingido o critério de parada; logo, esse elemento 
será considerado ordenado. Uma segunda chamada recursiva chegará a 
ser efetuada, mas rapidamente encerrada por não haver elementos a 
ordenar:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
1 2 33
33
pivo
pivo
pivo
Dessa forma, todos os elementos do terceiro nível da primeira cha-
mada recursiva estão ordenados:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
2 3 31 4 5
1 2 33
pivo
O algoritmo retorna para o segundo nível, onde ainda falta executar a 
segunda chamada recursiva:
131Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
1 2 33 4 5
pivo
Como há apenas um elemento, este é considerado ordenado:
Números menores do que o pivô Números maiores do que o pivô
4 3 31 5 2 75 98
pivo
1 2 33 4 5
pivo
Encerra-se a chamada recursiva em segundo nível, retornando para 
a chamada original:
Números maiores do que o pivô
1 2 33 4 5 75 98
pivo
Todos os elementos à esquerda do primeiro pivô estão ordenados 
(destacados em vermelho), faltando apenas ordenar os elementos à di-
reita. Nesse ponto, encerra-se a primeira chamada recursiva e inicia-se a 
segunda chamada recursiva para os elementos 7, 8 e 9:
Números maiores do que o pivô
1 2 33 4 5 75 98
pivo
7 8 9
pivo
esq dir
132 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
A variável esq incrementará até apontar para o 8, e a variável dir de-
crementará até atingir um valor menor ou igual ao pivo:
Números maiores do que o pivô
1 2 33 4 5 75 98
pivo
7 8 9
pivo
esqdir
Asvariáveis dir e pivo trocarão de valor, mas, como apontam para o 
mesmo elemento, não ocorrerá mudança de valor. O primeiro elemento 
será definido como pivo. A primeira chamada recursiva será feita, porém, 
como não há elementos, logo será encerrada. Então, a segunda chama-
da recursiva será efetuada para os valores 8 e 9:
Números maiores do que o pivô
1 2 33 4 5 75 98
pivo
7 8 9
8 9
pivo
esq dir
A variável esq incrementará, e a variável dir decrementará:
Números maiores do que o pivô
1 2 33 4 5 75 98
pivo
7 8 9
8 9
pivo
esqdir
133Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
A variável pivo trocará de valor com dir, e dir será definida como novo 
pivo:
Números maiores do que o pivô
1 2 33 4 5 75 98
pivo
7 8 9
8 9
pivo
A primeira chamada recursiva não retornará nada, pois não há ele-
mentos à esquerda do último pivo. A segunda chamada recursiva atingi-
rá o critério de parada e definirá o elemento 9 como definitivamente 
posicionado no vetor:
Números maiores do que o pivô
1 2 33 4 5 75 98
pivo
7 8 9
8 9
pivo
Encerrado o terceiro nível, retorna-se ao nível anterior:
Números maiores do que o pivô
1 2 33 4 5 75 98
pivo
7 8 9
134 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Encerrado o segundo nível, retorna-se ao nível anterior. Como se tra-
tava da segunda chamada recursiva, não há mais nada a ser executado, 
encerrando-se a ordenação:
1 2 33 4 5 75 98
Vejamos a seguir o código de implementação desse algoritmo:
static void Main(string[] args)
{
int[] vetor = { 5, 3, 1, 9, 7, 2, 4, 5, 8, 3 };
quick(vetor, 0, vetor.Length - 1);
for (int i=0; i<vetor.Length; i++)
Console.Write(vetor[i]+" ");
}
No método main, de modo semelhante ao MergeSort, inicie criando 
um vetor não ordenado, chamando o método recursivo quick (informan-
do o vetor a ser ordenado, e o início e o final da parte a ser ordenada, 
que, inicialmente, é o vetor todo). O for, ao final, imprimirá os valores 
ordenados:
static public void quick(int[] vetor, int inicio, int fim)
{
if (inicio < fim)
{
int pivo = particionar(vetor, inicio, fim);
quick(vetor, inicio, pivo - 1);
quick(vetor, pivo + 1, fim);
}
}
O método quick inicia chamando o método particionar. Este método 
define um novo pivô no trecho do vetor informado, que será usado como 
ponto de divisão para as duas chamadas recursivas que ocorrem logo 
em seguida. A primeira chamada recursiva é realizada para os elementos 
135Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
à esquerda do vetor, e a segunda chamada recursiva, para os elementos 
à direita. Quando há somente um elemento em uma das partes — ou nos 
casos em que o pivô fica na primeira ou na última posição e, portanto, 
uma das metades não possui elemento algum —, é atingido o critério de 
parada (o índice do início do vetor não é menor do que o índice do fim), e 
não são executadas mais chamadas recursivas para essa parte do vetor:
 static public int particionar(int[] vetor, int inicio, int 
fim)
{
int esq = inicio;
int dir = fim;
int pivo = vetor[inicio];
while (esq < dir)
{
while (esq<=fim && vetor[esq] <= pivo)
{
esq++;
}
while (dir>=0 && vetor[dir] > pivo)
{
dir--;
}
if(esq < dir)
{
int aux = vetor[esq];
vetor[esq] = vetor[dir];
vetor[dir] = aux;
}
}
vetor[inicio] = vetor[dir];
vetor[dir] = pivo;
return dir;
}
O método particionar começa definindo esq como o primeiro índice e 
dir como o último índice do vetor recebido, e pivo aponta para o valor do 
primeiro índice. Em seguida, um laço executa a definição de um novo pivô 
enquanto o índice apontado por esq for menor que o apontado por dir. 
136 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.Dentro do laço while, são executados outros dois laços: o primeiro 
incrementa a variável esq enquanto o valor apontado por ela for menor 
ou igual ao atual pivô; o segundo decrementa a variável dir enquanto o 
valor apontado por ela for maior que o pivô. Se esq permanecer menor 
do que dir, ambas trocarão de valor. Esse laço permanecerá enquanto, 
ao final dos ajustes de posição, a variável esq for menor do que dir. 
Quando não mais o for, o laço se encerrará e será realizada a troca de 
valor entre o pivô (que estava na primeira posição) e o índice apontado 
por dir. Então, será retornado o valor de dir, que aponta para o novo pivô, 
o qual será utilizado no ponto do algoritmo que chamou essa função 
a fim de definir um novo ponto de divisão do vetor. Em seguida, serão 
realizadas as duas chamadas recursivas.
Podemos classificar a eficiência do QuickSort em caso médio (ou 
melhor caso) e pior caso (SZWARCFITER; MARKENZON, 2010). No caso 
médio, a divisão do vetor ocorre de forma balanceada (com o pivô sempre 
próximo à metade do vetor). Nesse caso, utilizamos a mesma análise 
empregada no MergeSort, em que o tempo é calculado por:
T(n) = 2 × T(n/2) + n
Levando a uma complexidade final de:
O(n log n)
Para o pior caso, a divisão ocorre de forma desbalanceada, com o 
pivô sempre próximo às extremidades dos subvetores. O tempo é cal-
culado por:
T(n) = T(n – 1) + T(0) + n
Pois 0 se refere a uma divisão vazia; n – 1 se refere a uma divisão do 
vetor com quase todos os elementos (considerando o pivô em uma das 
extremidades); e n é o tempo para criar os subproblemas. A complexi-
dade final corresponde à soma das sucessivas divisões desse tempo, 
logo, resultando em:
O(n2)
137Algoritmos de ordenação eficientes
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
NA PRÁTICA
Confira a execução em tempo real do funcionamento do QuickSort 
(GALLES, 2022).
 
Considerações finais
Neste capítulo, conhecemos novos algoritmos de ordenação que, 
baseados na técnica da recursividade, conseguem ser mais eficientes 
que os algoritmos de ordenação elementares abordados no capítulo 5.
A complexidade de O(n log n) alcançada pelo MergeSort e pelo caso 
médio do QuickSort representa uma melhora considerável em relação 
aos algoritmos de ordenação elementares, que apresentavam uma 
complexidade de O(n2).
Embora sejam os mais comuns entre os mais eficientes, esses algo-
ritmos de ordenação não são os únicos mais sofisticados que existem; 
há ainda o HeapSort, o ShellSort e dezenas de outros.
Perceba como os temas dos capítulos deste livro têm formado uma 
trilha de conhecimento cumulativo e sucessivo. A partir do entendimen-
to de vetores, pudemos analisar alguns algoritmos de busca e, em se-
guida, algoritmos de ordenação; depois, vimos como analisar a eficiên-
cia de algoritmos e compreender o que é recursividade para, finalmente, 
conhecer algoritmos de ordenação mais avançados (que se utilizam de 
vetores e recursividade) e entenderem que magnitude eles são mais 
eficientes que os anteriores.
O livro está terminando e, no próximo capítulo, veremos outra forma 
de armazenar e tratar dados, um assunto um pouco diferente da trilha 
percorrida até aqui. É preciso ter em mente, no entanto, que este capítu-
lo é o ápice da evolução e junção de diversos temas e, portanto, essen-
cial para o seu desenvolvimento em lógica de programação.
138 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
Referências
GALLES, D. Comparison sorting algorithms. Disponível em: https://www.
cs.usfca.edu/~galles/visualization/ComparisonSort.html. Acesso em: 2 abr. 
2022.
SZWARCFITER, J. L.; MARKENZON, L. Estruturas de dados e seus algoritmos. 
Rio de Janeiro: LTC, 2010.
https://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html
https://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html
139
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Capítulo 8
Tipos abstratos 
de dados
Para o desenvolvimento de jogos digitais e softwares em geral, de-
ve-se fazer um planejamento cuidadoso antes de iniciar a codificação. 
É importante identificar elementos que englobam certas variáveis e fun-
ções e modularizá-los em um código à parte. Se em seu jogo houver um 
dragão, por exemplo, algumas variáveis irão caracterizá-lo, como força 
e vida, e outras funções determinarão suas ações, como atacar e sofrer 
dano. Todo esse código pode ser modularizado em um código à parte, 
que diz respeito somente ao dragão.
A vantagem de modularizar trechos do código é a possibilidade de 
reduzir a extensão do seu código principal, deixando-o mais legível. A 
140 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
modularização também facilita a localização e a reutilização de todo o 
código referente ao dragão. Imagine que você queira criar três dragões 
em seu jogo. Sem modularizar, você teria que replicar mais duas vezes o 
mesmo código. Isso é uma péssima prática, que induz a erros, dificulta 
ajustes futuros e aumenta desnecessariamente o tamanho do código. 
Com o código já modularizado, é muito mais fácil criar três dragões a 
partir de um mesmo código, como veremos adiante.
Essa modularização envolve uma outra forma de enxergar o código 
e programar. Em C#, esse paradigma de programação se chama orien-
tação a objetos, e o código separado do código principal é denominado 
classe. Mas antes de entrarmos nos detalhes da implementação, vamos 
entender melhor o que é esse código “separado”. De forma mais gené-
rica, ele é referenciado como tipo abstrato de dado (TAD). No próximo 
subcapítulo, vamos entender o que é um TAD e o que ele deve conter.
1 Definição e utilização de TAD
Temos utilizado muitas variáveis nos algoritmos estudados até aqui. 
Essas variáveis são tipos de dados que correspondem a tipos primitivos, 
ou seja, representam um único valor. Esse valor pode ser um tipo de 
número racional, inteiro ou lógico (booleano), e assim por diante.
Porém, para a construção de um programa mais sofisticado, nor-
malmente é útil agrupar algumas dessas variáveis que correspondem 
a uma mesma entidade no programa. Suponha que você deseje criar 
um programa para gerir uma instituição de ensino. Os alunos podem ter 
nome, telefone de contato, número de documento pessoal, número de 
matrícula, curso no qual estão matriculados, entre outras informações. 
Com diversas variáveis pertencendo a cada aluno, para uma quantidade 
indefinida de alunos que podem ser cadastrados, é necessário um me-
canismo para organizar todas essas informações.
141Tipos abstratos de dados
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
 Portanto, é importante que haja uma estrutura para englobar, dentro 
do programa, todas essas características de um único aluno. Pense que, 
se uma variável é uma caixa que armazena um único tipo de dado, essa 
estrutura é um baú, que pode armazenar diversas caixas, como exem-
plificado na figura 1.
Figura 1 – Relação de um TAD com tipos primitivos de dados
String nomeCompleto
long numeroMatricula String curso
Aluno
Além disso, a estrutura permite definir ações que envolvem essa en-
tidade. Assim, ações como registrar a falta ou a nota de um aluno e 
mudar o telefone de contato, entre outras que afetem esse determina-
do aluno, podem ser definidas dentro dessa estrutura única. Essa é a 
definição de um TAD, que é a especificação de um conjunto de dados 
relacionados e de operações executadas sobre esses dados. Em C#, 
essa definição é feita por meio de classes, que nada mais são do que 
um código à parte do código principal do projeto. Veremos no último 
subcapítulo como criar e utilizar essas classes.
142 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
2 Definição de classes, atributos, métodos e 
construtores
Para prosseguirmos com a definição dos conceitos associados ao 
TAD, vamos estabelecer um exemplo para relacionar cada um deles.
Imagine que você deseje criar um jogo de plataforma em duas di-
mensões (2D) cujo personagem controlado pelo jogador é um cavaleiro 
que percorre fases enfrentando inimigos. Suas armas são uma espada 
e um arco e flecha: a primeira é utilizada para desferir golpes mais fortes 
próximo aos inimigos e a segunda, para acertá-los de longe, com me-
nor dano. As flechas podem acabar, e o jogador precisa encontrar mais 
delas ao longo das fases. O cavaleiro possui uma barra de vida – assim 
como os inimigos – e um contador de moedas, que são coletadas ao 
eliminar cada inimigo. Em determinado momento do jogo, o persona-
gem encontra um dragão, como ilustrado na figura 2.
Figura 2 – Jogo de plataforma 2D
Imagine que você vá desenvolver esse jogo com os recursos vistos 
até aqui e atendendo aos requisitos descritos. O código do jogo estaria 
143Tipos abstratos de dados
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
todo em um único arquivo, com dezenas – ou mesmo centenas – de 
variáveis declaradas em sequência, pertencentes a diferentes inimigos, 
itens, fases, entre outros recursos. Desse modo, utilizando um paradig-
ma de programação estruturada, o código ficaria extenso, ilegível e, a 
longo prazo, muito difícil de manter e editar. Uma abordagem que auxilia 
na organização de um código é o paradigma de programação de orien-
tação a objetos. Com ele, o código é modularizado em partes que serão 
utilizadas aos poucos,de forma organizada, conforme o programa pre-
cisa criar e utilizar esses recursos específicos. No exemplo do jogo do 
cavaleiro, seria o equivalente ao programa utilizar, no cenário da figura 
2, as classes relacionadas ao dragão, ao cavaleiro e aos demais itens 
em uso no momento.
PARA SABER MAIS 
Orientação a objetos é um paradigma de programação muito importante 
para o desenvolvimento não apenas de jogos, mas também de softwares 
em geral (DEITEL, 2003). É essencial dominar conceitos associados a 
esse paradigma, como herança e polimorfismo, entre muitos outros; 
portanto, dedique tempo à pesquisa e à compreensão desse assunto.
 
Com o paradigma de orientação a objetos, cada entidade do progra-
ma é definida por uma classe. O herói (um cavaleiro, mago ou outro 
personagem), o dragão (verde, vermelho ou azul, cada um com poderes 
e características diferentes) e uma espada (de ouro, diamante ou outro 
material que lhe desse poder diferente) podem ser, cada um deles, uma 
classe. Perceba que essas entidades podem ser classes, pois a defini-
ção do que será uma classe em seu programa dependerá da modela-
gem do desenvolvedor.
Uma classe é, portanto, um código separado do código principal do 
seu projeto. Nesse código à parte, são definidas as variáveis pertinen-
tes e as operações a serem executadas por essa entidade. Podemos 
144 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
enxergar uma entidade como um componente que será recriado várias 
vezes no programa. É possível, por exemplo, ter vários heróis no jogo, de 
forma que, se um deles morrer, o jogador assumirá o controle de outro. 
Também podemos ter diversos dragões como inimigos. Nesse exem-
plo, Herói e Dragão são classes. A classe é uma estrutura de código que 
dita o que faz parte dessa entidade e quais ações ela pode executar. 
Portanto, a classe herói é um modelo para indicar o que é e o que faz um 
herói no jogo.
A partir da classe, podem-se criar diversas instâncias, cada uma cons-
tituindo um novo elemento do jogo. Ou seja, a partir da classe herói, é pos-
sível criar um cavaleiro, um mago, um elfo e diversas outras instâncias de 
heróis. Essas instâncias são conhecidas como objetos.
Assim, a classe define as variáveis que caracterizam a entidade e as 
ações que podem ser executadas com essa entidade. Uma classe pode 
conter vários objetos, cada um com valores diferentes (preenchidos nas 
variáveis definidas na classe) e executando as ações que foram defini-
das na respectiva classe.
Essas variáveis definidas na classe, que correspondem a caracte-
rísticas da entidade, são denominadas atributos. Já as ações definidas 
na classe, que alteram os valores dessas variáveis ou executam outras 
ações sobre a entidade, nada mais são do que funções dentro do códi-
go da classe, as quais são especificamente denominadas métodos. 
Por fim, a partir da compreensão de que os objetos são criados a 
partir de uma classe e que cada objeto pode ter um valor diferente, é 
necessário um mecanismo para preencher esses valores. Isso pode ser 
feito por meio de construtores. Um construtor é uma função dentro da 
classe que define o recebimento de valores no momento da criação do 
objeto e a passagem desses valores para os atributos correspondentes. 
Assim, com uma única linha de comando, é possível criar um novo herói, 
chamado Cavaleiro, e informar todas as suas características (atributos).
145Tipos abstratos de dados
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
A figura 3 resume de forma ilustrativa todos os conceitos tratados 
neste subcapítulo. A partir da classe herói (que define o atributo força e 
o método atacar), podem ser criados os objetos Cavaleiro e Mago, cada 
um com um nível de força e uma forma de ataque diferentes. Esse é 
um exemplo bem resumido, pois poderia haver diversos outros objetos, 
atributos e métodos definidos na classe.
 Figura 3 – Criação de objetos a partir da classe herói 
força: 80
atacar: golpeEspada
força: 60
atacar: lançarMagia
Objeto Cavaleiro
Herói
força: inteiro
atacar()
Nome da classe
Atributos
Métodos
Objeto Mago
PARA SABER MAIS 
A representação da classe herói no exemplo da figura 3 é feita, de forma 
adaptada, por meio do diagrama de classes do padrão unified modeling 
language (UML). Essa forma de representação é muito utilizada para 
projetos de software, permitindo uma fácil visualização da relação en-
tre diferentes partes do código; logo, é muito útil para projetos desen-
volvidos no paradigma de orientação a objetos. 
 
146 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
3 Implementação de TAD utilizando classes
A implementação de uma nova classe em seu projeto depende do 
ambiente de desenvolvimento integrado (IDE) que esteja utilizando. 
Caso seja o Microsoft Visual Studio, basta clicar com o botão direito 
sobre o nome do projeto, em Gerenciador de Soluções, e seguir pela 
opções Adicionar e Classe, conforme ilustra a figura 4. Crie uma classe 
chamada Heroi.cs e outra chamada Dragao.cs.
Figura 4 – Criação de classe 
 
Na classe Heroi, adicione o seguinte código:
public class Heroi
{
int forca;
int life;
int moedas;
int tipo; //1 para cavaleiro; 2 para mago
public Heroi(int f, int l, int m, int t)
{
forca = f;
life = l;
moedas = m;
tipo = t;
147Tipos abstratos de dados
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
}
public void atacar()
{
if(tipo==1)
Console.WriteLine("Ataque com espada!");
else
Console.WriteLine("Ataque com magia!");
}
public void sofrerDano(int dano)
{
life -= dano;
if (life <= 0)
Console.WriteLine("Herói morreu!");
}
}
A variável forca indica a intensidade do golpe; life indica o nível de 
energia; moedas indica a quantidade adquirida; e tipo indica o tipo de 
herói. Esses são os atributos dessa classe. O método atacar() executa a 
ação de ataque do personagem, de acordo com o tipo de herói (cavalei-
ro ou mago); o método sofrerDano(dano) registra um ataque do inimigo; 
e o método Heroi é o construtor dessa classe, permitindo que, durante a 
criação do objeto, sejam passados quatro valores como argumentos – 
pelo corpo desse método, cada um desses valores é registrado em um 
dos quatro atributos. Portanto, é importante seguir a sequência definida 
no construtor: forca, life, moedas e tipo. Nesse exemplo, os métodos 
executam uma ação muito simples, mostrando apenas uma mensa-
gem que representa a ação realizada; em um jogo completo, no entanto, 
eles poderiam acionar sprites de animação de ataque e dano.
Na classe Dragao, adicione o código a seguir:
148 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ital, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
public class Dragao
{
int mordida;
int bolaFogo;
int life;
int recompensa;
public Dragao(int m, int b, int l, int r)
{
mordida = m;
bolaFogo = b;
life = l;
recompensa = r;
}
public void morder()
{
Console.WriteLine("Mordida!");
}
public void lancarFogo()
{
Console.WriteLine("Lançar bola de fogo!");
}
public void sofrerDano(int dano)
{
life -= dano;
if (life <= 0)
Console.WriteLine("Dragão derrotado!");
}
}
As variáveis mordida e bolaFogo indicam a intensidade dos respecti-
vos golpes; a variável life indica o nível de energia; e a variável recompen-
sa indica a quantidade de moedas que o inimigo libera ao ser derrotado. 
Os métodos morder() e lancarFogo() executam cada qual um golpe espe-
cífico; o método sofrerDano(dano) registra um ataque do inimigo; e o mé-
todo Dragao é o construtor dessa classe, de forma similar à classe Heroi.
149Tipos abstratos de dados
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Na classe principal, são definidas a criação dos objetos dessas clas-
ses e a interação entre eles, por meio de seus métodos. Confira o exem-
plo a seguir:
class Program
{
static void Main(string[] args)
{
//Criação dos objetos
Heroi Cavaleiro = new Heroi(80,100,0,1);
Heroi Mago = new Heroi(60,100,0,2);
Dragao DragaoVermelho = new Dragao(70,110,100,30);
//Cavaleiro ataca Dragão
Cavaleiro.atacar();
//Dragão sofre dano do Cavaleiro
DragaoVermelho.sofrerDano(80);
//Dragão ataca Cavaleiro
DragaoVermelho.lancarFogo();
//Cavaleiro sofre dano do Dragão (morre)
Cavaleiro.sofrerDano(110);
//Mago ataca Dragão
Mago.atacar();
//Dragão sofre dano do Mago (morre)
DragaoVermelho.sofrerDano(60);
}
}
A criação de um objeto de uma classe é feita pela seguinte sintaxe:
nome_classe nome_objeto = new nome_classe(valores_dos_atributos)
O nome da classe é definido no momento de sua criação. O nome do 
objeto pode ser qualquer um (cavaleiro, cavaleiroDourado, cavaleiro1, 
etc.), mas é importante utilizar um nome representativo para o objeto 
criado a partir dessa classe. Já os valores dos atributos correspondem 
aos valores na mesma sequência em que foram definidos no construtor, 
separados por vírgula.
150 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.Após criar os objetos com seus respectivos valores, podem-se utili-
zar os métodos para iniciar uma interação entre eles. Para chamar um 
método de um objeto, utiliza-se a seguinte sintaxe:
nome_objeto <ponto> nome_método
Assim, será executada a ação definida pelo método do referido 
objeto.
A execução do código principal gera a saída ilustrada na figura 5.
Figura 5 – Resultado da execução do programa 
 
O cavaleiro realizou um ataque com espada, diminuindo a vida do 
dragão de 100 para 20 (pois a força do ataque é de 80). Em seguida, o 
dragão lançou uma bola de fogo no cavaleiro; por ter um poder de 110, 
o ataque o matou instantaneamente. Depois, o mago atacou o dragão 
com um valor de 60; como o dragão possuía 20 de vida, foi derrotado.
Obviamente, esse é um roteiro de interação fixo, no qual toda exe-
cução resultará na mesma sequência de ações. Também se trata de 
uma representação lógica de ações. Em um jogo real, a ordem de inte-
ração entre personagens e inimigos é definida por escolhas do jogador 
em tempo real, levando a resultados distintos a cada jogada, com in-
terações normalmente representadas por elementos visuais, e não so-
mente por textos. Porém, o intuito desse exemplo é demonstrar como 
são criados classes e objetos e como são chamados os seus métodos, 
151Tipos abstratos de dados
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
gerando interações no programa. Principalmente, o objetivo é mostrar 
como tudo isso pode ser utilizado no ambiente de um jogo.
Considerações finais
Aqui, encerramos nosso estudo. Nos últimos capítulos, tratamos de 
uma série de algoritmos e conceitos fundamentais de programação, 
que serão utilizados em diferentes contextos ao longo de sua experiên-
cia como programador. Neste último capítulo, cobrimos as bases de um 
novo paradigma de programação: orientação a objetos. Ter familiarida-
de com esse paradigma é essencial para a carreira de um programador.
Orientação a objetos utiliza o conceito de modularização para frag-
mentar o código em diferentes partes, aumentando sua legibilidade e 
facilitando o reúso dessas partes. A base desse paradigma é o concei-
to de tipo abstrato de dado (TAD), um trecho de código que engloba di-
versas variáveis relacionadas a um mesmo elemento do código, além 
de funções que especificam ações a serem executadas com essas va-
riáveis. Em programação orientada a objetos (POO), essas estruturas 
são chamadas de classes. Suas variáveis são chamadas de atributos, 
e as funções, de métodos. A classe é o modelo usado para a criação 
de objetos. Os objetos são os elementos que carregam valores e que 
são utilizados nas interações do programa.
Com a utilização de classes, o projeto fica mais organizado, facilitan-
do muito a instanciação de elementos semelhantes (objetos) e evitando 
a replicação de códigos iguais. Portanto, apoiar-se em um paradigma 
como esse é fundamental para facilitar o desenvolvimento do projeto.
Até aqui, você deve ter adquirido conhecimentos essenciais para sua 
evolução como programador – mas não se dê por satisfeito: procure 
se aprofundar nesses conceitos. Há muitos outros algoritmos de orde-
nação para conhecer e muito mais a estudar a respeito de orientação a 
objetos. Utilize as referências indicadas, pesquise outras, mantenha-se 
152 Algoritmos e programação II com C# Ma
te
ria
l p
ar
a 
us
o 
ex
cl
us
ivo
 d
e 
al
un
o 
m
at
ric
ul
ad
o 
em
 c
ur
so
 d
e 
Ed
uc
aç
ão
 a
 D
is
tâ
nc
ia
 d
a 
Re
de
 S
en
ac
 E
AD
, d
a 
di
sc
ip
lin
a 
co
rre
sp
on
de
nt
e.
 P
ro
ib
id
a 
a 
re
pr
od
uç
ão
 e
 o
 c
om
pa
rti
lh
am
en
to
 d
ig
ita
l, s
ob
 a
s 
pe
na
s 
da
 L
ei
. ©
 E
di
to
ra
 S
en
ac
 S
ão
 P
au
lo
.
curioso e ávido por se aprofundar nos assuntos e aprender mais: esse 
é o caminho do sucesso profissional que você almeja, e no qual já se 
encontra.
Referência
DEITEL, H. M. C#: como programar. São Paulo: Pearson, 2003.
155
M
aterial para uso exclusivo de aluno m
atriculado em
 curso de Educação a Distância da Rede Senac EAD, da disciplina correspondente. Proibida a reprodução e o com
partilham
ento digital, sob as penas da Lei. ©
 Editora Senac São Paulo.
Sobre o autor
Rafael Sanches Rocha é mestre em tecnologia pela Universidade 
Estadual de Campinas (Unicamp) (2020), especialista em desen-
volvimento de sistemas para dispositivos móveis pelo Instituto 
Federal de Educação, Ciência e Tecnologia de São Paulo (IFSP) 
(2016), bacharel em sistemas de informação pela Universidade 
de São Paulo (USP) (2013), tecnólogo em segurança da informa-
ção pela Faculdade de Tecnologia do Estado de São Paulo (Fatec) 
(2020) e licenciado em computação pelo Claretiano (2021). Tem 
experiência em docência na área de informática e interesse pelos 
temas de tecnologia móvel, desenvolvimento de sistemas, seguran-
ça da informação e aprendizado de máquina.
	ALG_PRO_01_IND_2022
	ALG_PRO_02_IND_2022
	ALG_PRO_03_IND_2022
	ALG_PRO_04_IND_2022ALG_PRO_05_IND_2022
	ALG_PRO_06_IND_2022
	ALG_PRO_07_IND_2022
	ALG_PRO_08_IND_2022

Mais conteúdos dessa disciplina