Escolar Documentos
Profissional Documentos
Cultura Documentos
E1 Coal
E1 Coal
COMPLEXIDADE DE
ALGORITMOS
Ariel Da Silva Dias
Sumário
INTRODUÇÃO������������������������������������������������� 3
CONTAGEM DE INSTRUÇÕES������������������������ 7
Contando as instruções������������������������������������������������������� 8
HABILIDADES MATEMÁTICAS
NECESSÁRIAS��������������������������������������������� 31
CONSIDERAÇÕES FINAIS���������������������������� 36
2
INTRODUÇÃO
Todos os dias nos deparamos com muitos proble-
mas e encontramos uma ou mais soluções para
solucioná-los. Dentre essas possíveis soluções,
algumas podem ser mais eficientes do que outras,
entretanto, sempre buscamos pela solução mais
eficiente.
3
conjuntos de instruções todos os dias. Alguns
exemplos são claramente sinalizados, enquanto
outros são mais subtendidos, por exemplo, manter
o limite de velocidade ao dirigir seu carro, subir
ou descer uma escada ou seguir um código de
conduta em uma empresa.
4
4. Por fim, Ana pode ir a pé pela rodovia dos Ban-
deirantes, no estado de São Paulo, até chegar na
casa de sua amiga;
5
resolver um determinado problema. Ao analisar um
algoritmo, consideramos principalmente a com-
plexidade do tempo e a complexidade do espaço:
6
CONTAGEM DE
INSTRUÇÕES
A complexidade de tempo de um programa é a
quantidade de tempo que o computador precisa
para concluir a execução de determinado progra-
ma. O tempo, T(p), tomado por um programa p, é
a soma do tempo de compilação e do tempo de
execução das instruções. O tempo de compilação
não depende das características da instância.
Além disso, podemos assumir que um programa
compilado será executado várias vezes sem re-
compilação. Logo, não consideraremos o tempo
de compilação, vamos nos preocupar apenas com
o tempo de execução do programa. O tempo de
execução é definido por tp (características da
instância).
7
Mas quanto tempo leva para uma instrução ser
executada? Depende, pois cada arquitetura com-
putacional possui um desempenho diferente. Logo,
uma instrução A em um processador X pode levar
0,01 nanossegundo para executar, enquanto a
mesma instrução A em um processador Y pode
levar 1 milissegundo.
CONTANDO AS INSTRUÇÕES
Agora que o conceito de contagem de instruções
foi definido e que uma instrução leva 1UT para
ser executada, vamos verificar alguns exemplos
práticos de contagem de instruções. O primeiro
exemplo está presente na tabela 1: a linguagem é
parecida com C, porém a mesma análise vale para
qualquer outra linguagem.
8
No código da tabela 1 temos quatro instruções,
sendo que cada linha é uma instrução diferente.
Anteriormente foi definido que cada instrução leva
1UT. Logo, temos que T(p) = 1 + 1 + 1 + = 4. Ou
seja, este algoritmo leva 4UT para ser executado.
9
a instrução da linha 5. Por fim, será executada a
instrução da linha 7.
10
T(p) = 1 * c1 * c2 + 1 * c3 + 1 * c4 + 0 * c5 + 0 + 1 *
c6
Conforme já foi exposto anteriormente, vamos
assumir que o custo computacional é 1 para todos.
Logo temos:
T(p)=1 * 1 + 1 * 1 + 1 * 1 + 1 * 1 + 0 * 1 + 0 + 1 *
1 = 5 UT
Logo, nosso algoritmo leva 5 UT para ser executado.
Apesar de tratar-se de um bom tempo, é possível
melhorar a execução desse algoritmo? Ou seja,
é possível diminuir o número de instruções em
execução? Sim! Assim como no exemplo da Ana
que estava indo para Fortaleza encontrar a amiga,
aqui também temos mais de um caminho. Observe
então o código da tabela 4.
Tabela 4: código com condicional (versão 2)
1 numero = read();
2 if (numero % 2 == 0)
3 console.log(“par”);
4 else
5 console.log(“impar”);
6
7 console.log(numero);
11
existe uma terceira opção. Logo, o else fará com
que reduza o número de instruções. Observe agora
como fica a tabela de contagem de instruções a
seguir.
12
resultado seria o mesmo, afinal, o else não é uma
instrução, portanto, se o número for ímpar, a exe-
cução sairá da linha 2 para a linha 5 diretamente.
13
Agora o código da tabela 6 foi modificado e ele
pode ser observado na tabela 7 a seguir.
14
y a instrução j < 10 será executada 10 vezes.
15
y duas instruções assim que o laço for começar
na linha 2, sendo j = 0 e j < n (como já era antes);
y 60 instruções, sendo 20 instruções para a linha
2, 20 instruções na linha 1 com j < n e 20 instruções
na linha 1 para j++.
16
cípio que n = 10, o nosso laço executará 9 vezes.
De igual modo, se n = 100, o nosso laço executará
99 vezes, sendo assim, não executaremos o laço
n vezes, mas sim, n-1 vezes.
17
y ao iniciar o laço for, teremos duas instruções,
sendo a atribuição e a comparação;
y a instrução da linha 2 executará apenas 1 vez,
pois o valor de j começou com 1;
y a instrução j ++ será executada apenas 1 vez;
y a instrução j < n será executada apenas 1 vez.
18
CONSUMO DE TEMPO
ASSINTÓTICO
Antes de abordar o consumo de tempo assintótico,
cabe relembrar que a complexidade de tempo é o
número de operações que um algoritmo executa
para completar sua tarefa em relação ao tamanho
da entrada (considerando que cada operação
leva o mesmo tempo), por isso o algoritmo que
executa a tarefa no menor número de operações
é considerado o mais eficiente.
19
eficiente, porque o tamanho da entrada é diferente
para ambos os algoritmos.
20
MELHOR CASO, PIOR CASO E CASO
MÉDIO
Considere um vetor arr com n valores inteiros que
estão dispostos aleatoriamente e sem repetição
nesse vetor. Precisamos descobrir se um valor k
está presente nesse vetor arr (essas são as nossas
entradas). O algoritmo para resolver esse problema
deve retornar o número 1 caso encontre o valor k,
e o valor 0 caso não encontre o valor k (essa é a
nossa saída).
21
y A linha 1 não é contada como uma instrução;
y i = 0 será executada 1 vez;
y i < n será executada n+1 vezes;
y i ++ será executado n vezes;
y if(arr[i] == k) será executado n vezes, pois está
dentro do for;
y return 1 será executado 1 vez se o valor k es-
tiver no vetor;
y return 0 será executado 1 vez se o valor k es-
tiver no vetor.
22
elemento 3 na terceira posição. Logo, a condição
if levará 3 UT;
y Caso 3: Se quisermos descobrir se o número
6 está presente na matriz ou não, a condição if da
linha 3 será executada 5 vezes e não encontrará
o elemento e, assim, retornará o valor 0. Logo, a
condição if levará 5 UT;
23
operações seja executado. Em nosso exemplo, no
caso 3, o pior caso pode ser se o array fornecido
for [1,2,3,4,5] e tentarmos descobrir se o elemento
“6” está presente no array ou não. Aqui, a condição
if do nosso loop será executada 5 vezes e então o
algoritmo retornará “0” como saída.
FIQUE
SAIBAATENTO
FIQUE ATENTO
REFLITA
MAIS
24
inferior, uma vez que os termos de ordem inferior
são relativamente insignificantes para grandes
entradas, além disso, usamos uma notação dife-
rente para descrever o comportamento limitante
de uma função.
NOTAÇÃO BIG-O
A notação Big-O (ou simplesmente O) define o
limite superior de qualquer algoritmo, ou seja, seu
algoritmo não pode demorar mais do que esse
tempo. Em outras palavras, podemos dizer que
a notação O denota o tempo máximo gasto por
um algoritmo ou a complexidade de tempo do
pior caso de um algoritmo. Assim, a notação O
é a notação mais usada para a complexidade de
tempo de um algoritmo. Logo, se uma função é
g(n), então a representação O de g(n) é mostrada
como O(g(n)) e a relação é mostrada como:
O(g(n)) = { f(n): existem constantes positivas c e n0
tal que 0≤f(n)≤g(n) para todo n≥0 }
A expressão pode ser lida como Big-O de g(n) é
definido como um conjunto de funções f(n) para
as quais existem algumas constantes c e n0 tais
que f(n) é maior ou igual a 0 e f(n) é menor ou igual
a c*g(n) para todo n maior ou igual a n0.
25
e você vai perceber isso a partir de um exemplo
a seguir, em que teremos dois algoritmos para
encontrar a soma dos n primeiros números.
FIQUE
SAIBAATENTO
FIQUE ATENTO
REFLITA
MAIS
26
No código da tabela 11, há apenas uma instrução
e sabemos que uma instrução leva um tempo
constante para sua execução. A ideia básica é: se a
instrução estiver demorando um tempo constante,
levará a mesma quantidade de tempo para todo o
tamanho de entrada e denotamos isso como O(1).
27
variável chamada “total”. Vamos obter a equação
desse algoritmo contando as instruções:
y Linha 2: apenas uma instrução, que chamare-
mos de c1;
y Linha 3: a atribuição de i=1 e a comparação
serão duas instruções iniciais e, por ser uma cons-
tante, chamaremos de c2;
y Linha 3: a comparação e o incremento serão
executados n vezes. Logo, na linha 3 teremos c2*n;
y Linha 4: será executada n vezes também;
y Linha 5: será executada apenas uma vez e, por
ser uma constante, chamaremos de c3.
28
solução O(1) porque o tempo gasto pelo algoritmo
será constante, independentemente do tamanho
da entrada.
NOTAÇÃO Θ (TETA)
A notação Θ é usada para encontrar o limite médio
de um algoritmo, ou seja, define um limite superior
e um limite inferior, e seu algoritmo ficará entre
esses níveis. Então, se uma função é g(n), então a
representação teta é mostrada como e a relação
é mostrada como Θ(g(n)) a expressão a seguir:
NOTAÇÃO Ω (ÔMEGA)
A notação Ω denota o limite inferior de um algo-
ritmo, ou seja, o tempo gasto pelo algoritmo não
pode ser inferior ao que foi determinado. Em outras
palavras, este é o tempo mais rápido em que o
algoritmo retornará um resultado, é o tempo gasto
pelo algoritmo quando fornecido com sua entrada
29
de melhor caso. Então, se uma função é g(n), então
a representação ômega é mostrada como Ω(g(n))
e a relação é mostrada como:
Ω(g(n)) = { f(n): existem constantes positivas c e n0
tal que 0 ≤ cg(n) ≤ f(n) para todo n ≥ n0 }
A expressão apresentada pode ser lida como ôme-
ga de g(n) é definida como o conjunto de todas
as funções f(n) para as quais existem algumas
constantes c e n0 tais que c*g(n) é menor ou igual
f(n) a , para todo n maior ou igual a n0.
30
HABILIDADES
MATEMÁTICAS
NECESSÁRIAS
Existem muitas habilidades que serão necessárias
para a análise dos algoritmos. Algumas delas
são triviais e serão relembradas durante o estudo
deste tema. Entretanto, uma das habilidades que
mais prende a atenção dos alunos é o estudo dos
logaritmos.
31
A função logarítmica é definida como:
para x>0,a>0 e a≠1,
𝑦𝑦 = log' x se ,somente se, x = a0
32
Regra do produto
logb MN = logb M + logb N
A multiplicação de dois logaritmos de mesma
base é igual à soma desses logaritmos de base
igual. Exemplo:
Regra do quociente
M
log$ = log$ M − log$ N
N
56
log$ 56 − log$ 7 = log$ = log$ 8 = 1
7
33
REVISÃO DOS
ALGORITMOS DE
ORDENAÇÃO E MÉTODOS
DE PESQUISA
Os Algoritmos de Ordenação são métodos de
reorganização de um grande número de itens em
alguma ordem específica, como do maior para o
menor, ou vice-versa, ou mesmo em alguma ordem
alfabética.
BUBBLE SORT
Bubble sort é um algoritmo de ordenação sim-
ples que percorre repetidamente a lista, compara
elementos adjacentes e os troca se estiverem na
ordem errada. Esse é o algoritmo mais simples e
ineficiente ao mesmo tempo. No entanto, é muito
34
necessário aprender sobre isso, pois representa
os fundamentos básicos da classificação.
MERGE SORT
O Merge sort é um dos algoritmos de ordenação
mais eficientes e funciona no princípio da Divisão
e Conquista. O merge sort divide repetidamente
uma lista em várias sublistas até que cada uma
delas consista em um único elemento, além disso,
ele mescla essas sublistas de uma maneira que
resulte em uma lista classificada.
QUICK SORT
O nome “Quick Sort” vem do fato de que ele é ca-
paz de ordenar uma lista de elementos de dados
significativos mais rapidamente (duas ou três vezes
mais rápido) do que qualquer um dos algoritmos
de ordenação. Trata-se de um dos algoritmos de
ordenação mais eficientes e baseia-se na divisão de
um array em outros menores e na troca com base
na comparação com o elemento ‘pivô’ selecionado.
Devido a isso, o quick sort também é chamada de
classificação “Partition Exchange”. Assim como a
ordenação por merge sort, o quick sort também
se enquadra nas categorias de abordagem de
divisão e conquista da metodologia de resolução
de problemas.
35
CONSIDERAÇÕES FINAIS
Neste e-book você pôde compreender o conceito de
algoritmos como uma ferramenta para resolução
de problemas. Conforme foi apresentado, existem
diversos algoritmos para resolver um mesmo pro-
blema, conforme ilustrado no exemplo de Ana que
deseja ir visitar sua amiga em Fortaleza, partindo
de São Paulo.
36
Referências Bibliográficas
& Consultadas
BORIN, V. P. Estrutura de dados. Curitiba:
Contentus, 2020. [Biblioteca Virtual].