Escolar Documentos
Profissional Documentos
Cultura Documentos
Programação
Prof. Edilson
Rodrigues
Contatos
ejrodrigues@prof.unisa.br
98477-2468
@edilson_fozzy
Ementa
1. Algoritmos de busca
2. Algoritmos de ordenação
3. Algoritmos de ordenação eficientes
4. Estruturas complexas
5. Padrões de projeto
Objetivos
• Linguagem de Programação
• Java, C#
Bibliografia
Complexidade
de Algoritmos
Medida do Tempo de Execução de um
Programa
• O projeto de algoritmos é fortemente influenciado pelo estudo
de seus comportamentos;
• Depois que um problema é analisado e decisões de projeto são
finalizadas, é necessário estudar as várias opções de
algoritmos a serem utilizados, considerando os aspectos de
tempo de execução e espaço ocupado;
• Muitos desses algoritmos são encontrados em áreas como
pesquisa operacional, otimização, teoria dos grafos, estatística,
probabilidades, entre outras.
Tipos de Problemas na Análise de
Algoritmos
• Análise de um algoritmo particular:
• Qual é o custo de usar um dado algoritmo para resolver
um problema específico?
• Características que devem ser investigadas:
• análise do número de vezes que cada parte do
algoritmo deve ser executada,
• estudo da quantidade de memória necessária.
Tipos de Problemas na Análise de
Algoritmos
• Análise de uma classe de algoritmos:
• Qual é o algoritmo de menor custo possível para resolver
um problema particular?
• Toda uma família de algoritmos é investigada;
• Procura-se identificar um que seja o melhor possível;
• Coloca-se limites para a complexidade computacional dos
algoritmos pertencentes à classe;
Custo de um Algoritmo
int maior(Vetor A) {
int i, Temp;
Temp = A[0];
for (i = 1; i < n; i++)
if (Temp < A[i])
Temp = A[i];
return Temp;
}
Exemplo: Maior Elemento
int maior(Vetor A) {
int i, Temp;
Temp = A[0];
for (i = 1; i < n; i++)
if (Temp < A[i]) n–1
Temp = A[i]; comparações
return Temp;
}
Tamanho da Entrada de Dados
• f(n) = O(1)
• Algoritmos de complexidade O(1) são ditos de
complexidade constante;
• Uso do algoritmo independe de n;
• As instruções do algoritmo são executadas um número fixo
de vezes;
Principais classes de problemas
• f(n) = O(log n)
• Um algoritmo de complexidade O(log n) é dito ter
complexidade logarítmica;
• Típico em algoritmos que transformam um problema em
outros menores;
• Pode-se considerar o tempo de execução como menor que
uma constante grande;
• Quando n é mil, log2 n ≈ 10, quando n é 1 milhão, log2 n ≈
20;
• Para dobrar o valor de log n temos de considerar o
quadrado de n;
• A base do logaritmo muda pouco estes valores: quando n é
1 milhão, o log2n é 20 e o log10n é 6.
Principais classes de problemas
• f(n) = O(n)
• Um algoritmo de complexidade O(n) é dito ter
complexidade linear;
• Em geral, um pequeno trabalho é realizado sobre cada
elemento de entrada;
• É a melhor situação possível para um algoritmo que tem
de processar/produzir n elementos de entrada/saída;
• Cada vez que n dobra de tamanho, o tempo de execução
dobra;
Principais classes de problemas
• f(n) = O(n2)
• Um algoritmo de complexidade O(n2) é dito ter
complexidade quadrática;
• Ocorrem quando os itens de dados são processados aos
pares, muitas vezes em um anel dentro de outro;
• Quando n é mil, o número de operações é da ordem de 1
milhão.
• Sempre que n dobra, o tempo de execução é multiplicado
por 4;
• Úteis para resolver problemas de tamanhos relativamente
pequenos;
Principais classes de problemas
• f(n) = O(n3)
• Um algoritmo de complexidade O(n3) é dito ter
complexidade cúbica;
• Úteis apenas para resolver pequenos problemas;
• Quando n é 100, o número de operações é da ordem de 1
milhão;
• Sempre que n dobra, o tempo de execução fica
multiplicado por 8;
Principais classes de problemas
• f(n) = O(2n)
• Um algoritmo de complexidade O(2n) é dito ter
complexidade exponencial;
• Geralmente não são úteis sob o ponto de vista prático;
• Ocorrem na solução de problemas quando se usa força
bruta para resolvê-los;
• Quando n é 20, o tempo de execução é cerca de 1 milhão.
Quando n dobra, o tempo fica elevado ao quadrado;
Principais classes de problemas
• f(n) = O(n!)
• Um algoritmo de complexidade O(n!) é dito ter
complexidade exponencial, apesar de O(n!) ter
comportamento muito pior do que O(2n);
• Geralmente ocorrem quando se usa força bruta na solução
do problema;
• n = 20 → 20! = 2432902008176640000, um número com
19 dígitos;
• n = 40 → um número com 48 dígitos;
Comparação de funções de complexidade
Algoritmos Polinomiais
O percurso <c1; c3; c4; c2; c1> é uma solução para o problema,
cujo percurso total tem distância 24.
Exemplo de Algoritmo Exponencial
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
# Subprogramas
...
escreverResposta(dado, onde)
48
Exemplo (continuação)
# Subprogramas
def preencher(valores):
for ind in range(len(valores)):
valores[ind] = int(input(“Elemento[”+str(ind)+“]=”))
return None
def buscaElemento(valores, procurado):
...
def escreverResposta(valor, pos):
if pos<0:
print(valor,“não foi encontrado”)
else:
print(valor, “foi encontrado na posição”, pos)
return
# Programa Principal de Busca
numeros = [0]*10
preencher(numeros)
dado = int(input(“Escolha valor a ser procurado: ”))
onde = buscaElemento(numeros, dado)
escreverResposta(dado, onde)
49
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: -1
50
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: -1
indice: 0
51
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: -1
indice: 1
52
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: -1
indice: 2
53
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: -1
indice: 3
54
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: 4
indice: 4
55
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: 4
indice: 5
56
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: 4
indice: 6
57
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: 4
indice: 7
58
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: 4
indice: 8
59
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: 4
indice: 9
60
Busca Simples (utilizando for)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 18
local: 4 Resultado
indice: 9
61
# Subprogramas
def preencher(valores):
...
63
Busca Simples (utilizando for com saída rápida)
• Utilizando-se sub-programação, não se considera uma
má prática de programação se realizar um return dentro
de uma repetição.
64
Busca Simples (utilizando while)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 4
local: -1
indice: 0
65
Busca Simples (utilizando while)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 4
local: -1
indice: 1
66
Busca Simples (utilizando while)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 4
local: -1
indice: 2
67
Busca Simples (utilizando while)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 4
local: 2
indice: 2
68
Busca Simples (utilizando while)
7 19 4 10 18 6 8 1 3 12
0 1 2 3 4 5 6 7 8 9
procurado: 4
local: 2 Resultado
indice: 10
69
# Subprogramas
def preencher(valores):
...
def buscaElemento(valores, procurado): # primeira solução
local = -1
indice = 0
while indice<len(valores):
if valores[indice]!=procurado:
indice = indice + 1
else:
local = indice
indice = len(valores)
return local
def escreverResposta(valor, pos):
...
# Programa Principal de Busca
numeros = [0]*10
preencher(numeros)
dado = int(input(“Escolha valor a ser procurado: ”))
onde = buscaElemento(numeros, dado)
escreverResposta(dado, onde)
70
# Subprogramas
def preencher(valores):
...
72
Busca com Sentinela (utilizando while)
• O algoritmo anterior poderia executar menos
comparações, se não houvesse a necessidade de evitar
ultrapassar o fim do vetor, caso o elemento procurado
não se encontre no conjunto.
• Propõe-se então alocar uma posição a mais no vetor e
inserir forçadamente o elemento procurado nesta
posição.
• Desta forma, necessariamente o elemento procurado
será encontrado. Se for encontrado na posição n+1,
significa que o elemento não pertence ao conjunto
original.
• Apesar de executar menos comparações, o algoritmo
avalia, no pior caso, n+1 elementos. Portanto, sua
complexidade também é da ordem de n, representado
por O(n).
73
# Subprogramas
def preencher(valores):
...
def buscaElemento(valores, procurado):
indice = 0
while valores[indice]!=procurado:
indice = indice + 1
if indice==len(valores)-1:
local = -1 # local do sentinela, informa que não achou
else:
local = indice
return local
75
Busca Binária
valores
1 3 4 5 7 8 9 10 12 13 14 15 17 18 19 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
inicio fim
procurado: 14
76
Busca Binária
procurado: 14
14 > 10
valores
1 3 4 5 7 8 9 10 12 13 14 15 17 18 19 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
valores
1 3 4 5 7 8 9 10 12 13 14 15 17 18 19 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
meio fim
inicio
14 < 15
valores
1 3 4 5 7 8 9 10 12 13 14 15 17 18 19 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
valores
1 3 4 5 7 8 9 10 12 13 14 15 17 18 19 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
inicio fim
14 > 13
valores
1 3 4 5 7 8 9 10 12 13 14 15 17 18 19 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
inicio fim
meio
valores
1 3 4 5 7 8 9 10 12 13 14 15 17 18 19 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
inicio fim
14 = 14
valores
1 3 4 5 7 8 9 10 12 13 14 15 17 18 19 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
inicio fim
meio
14 = 14
valores
1 3 4 5 7 8 9 10 12 13 14 15 17 18 19 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
inicio fim
87
Busca do Menor e Maior Elementos
4 19 4 10 18 6 19 1 3 18
0 1 2 3 4 5 6 7 8 9
88
Busca do Menor e Maior Elementos
# Subprogramas
def preencher(valores):
for ind in range(len(valores)):
valores[ind] = int(input(“Elemento[”+str(ind)+“]=”))
return
def buscarMenorMaiorElementos(valores):
...
def escrever(infos):
print(“O menor elemento =”, infos[0], “e o maior elemento =”, infos[1])
return None
89
Busca do Menor e Maior Elementos (continuação)
# Subprogramas
def preencher(valores):
...
def buscarMenorMaiorElementos(valores):
menor = valores[0]
maior = valores[0]
for indice in range(1,len(valores)):
if menor > valores[indice]:
menor = valores[indice]
elif maior < valores[indice]:
maior = valores[indice]
return [menor, maior]
def escrever(infos):
...
# Programa Principal de Busca do Menor e do Maior Elementos
numeros = [0]*10
preencher(numeros)
extremos = buscarMenorMaiorElementos(numeros)
escrever(extremos)
90
Busca do Menor e Maior Elementos
• O algoritmo apresentado encontra o menor e o maior
elementos em um vetor de n elementos.
91
PERGUNTAS?
BOM
DESCANSO
A TODOS!