PARADIGMAS DE PROJETOS
DE ALGORITMOS
LUCIANO D. ISAIAS
THAÍS F. VICENTIN
6766746
7547420
O QUE É UM PARADIGMA?
• Um paradigma é um modelo que fornece e
determina a visão que o programador
possui sobre a estruturação e execução do
programa.
PROJETO DE ALGORITMO
O projeto de algoritmo requer abordagens
adequadas:
• A forma como um algoritmo aborda o problema
pode levar a um desempenho ineficiente.
• Em certos casos, o algoritmo pode não conseguir
resolver o problema em tempo viável.
Não existe um paradigma que seja o melhor
dentre todos.
TIPOS DE PARADIGMAS
•
•
•
•
•
•
Recursividade.
Tentativa e erro.
Divisão e conquista.
Programação dinâmica.
Algoritmos gulosos.
Algoritmos aproximados.
RECURSIVIDADE
• Uma função é dita recursiva quando executa a si
mesma, ou seja, dentro de um código, tem a
capacidade de chamar um “subcódigo” para ser
executado.
• A recursividade permite descrever algoritmos de
formas que utilizem estruturas recursivas, mais claras
e
concisas,
especialmente
em
problemas
complexos.
EXEMPLO: QUICKSORT
QUICKSORT - PARTICIONAMENTO
QUICKSORT – PIOR CASO
QUICKSORT – MELHOR CASO
QUICKSORT – VANTAGENS E
DESVANTAGENS
QUANDO NÃO USAR RECURSIVIDADE
• Algoritmos recursivos são apropriados quando o
problema a ser resolvido ou os dados a serem
tratados são definidos em termos recursivos.
Entretanto, isso não garante que um algoritmo
recursivo seja o melhor caminho para resolver o
problema.
• Vejamos dois exemplos ilustrativos de algoritmos
para calcular os números da sequência de
Fibonacci:
ALGORITMO 1: FUNÇÃO RECURSIVA
function FibRec (n: integer) : integer;
begin
if n<2
then FibRec := n
else FibRec := FibRec(n-1) + FibRec(n-2);
end;
ALGORITMO 2 : FUNÇÃO ITERATIVA
function FibIter (n: integer): integer;
var i, k, F: integer;
begin
i :=1; F :=0;
for k :=1 to n do
begin
F := i+F;
i := F-i;
end;
FibIter :=F;
end;
COMPLEXIDADES DO ALGORITMO 1 E
DO ALGORITMO 2
• O algoritmo 1 é O( log Φ𝑛 ) = O(n), pois cada
chamada recursiva é empilhada e esse número é
O(n).
• O algoritmo 2 tem complexidade de tempo O(n) e
complexidade de espaço O(1).
n
10
20
30
50
100
FibRec
8 ms
1s
2 min
21 dias
109
anos
FibIter
1
1
½ ms
¾ ms
1,5 ms
6
ms
3
ms
TENTATIVA E ERRO
• Um algoritmo tentativa e erro é aquele que testa
exaustivamente todas as possíveis soluções de um
problema, de modo a obter a solução desejada.
• A ideia é decompor o processo em um número finito de
subtarefas parciais que devem ser exploradas.
• O processo geral pode ser visto como um processo de
pesquisa ou tentativa que gradualmente constrói e
percorre uma árvore de subtarefas.
TABULEIRO DE XADREZ
TENTA UM PRÓXIMO MOVIMENTO
procedure Tenta (i: integer; x,y: TipoIndice; var q: boolean);
var u, v, k: integer; q1: boolean;
begin
k := 0; {inicializa selecao de movimentos}
repeat
k := k+1; q1 := false;
u := x+a[k]; v := y+b[k];
if (u in s) and (v in s)
then if t[u,v] = 0
then begin
t[u,v] := i;
if i<N*N {tabuleiro não esta cheio}
then begin
Tenta (i+1, u, v, q1); {tenta novo movimento}
if not q1
then t [u,v] := 0 {não sucedido apaga reg.
Anterior}
end
else q1 := true;
end;
until q1 or (k=8); {não há mais casas a visitar a partir de x,y}
q := q1;
end;
PASSEIO DE CAVALO NO TABULEIRO
DE XADREZ
program PasseioCavalo;
const N=8; {Tamanho do lado do tabuleiro}
type TipoIndice = 1..N;
var i, j: integer;
t: array[TipoIndice, TipoIndice] of integer;
q: boolean;
s: set of TipoIndice;
a, b: array[TipoIndice] of integer;
{-- Entra aqui o procedimento Tenta do Programa anterior --}
begin {programa principal}
s := [1,2,3,4,5,6,7,8];
a[1] := 2; a[2] :=1; a[3] :=-1; a[4] :=-2;
b[1] := 1; b[2] :=2; b[3] := 2; b[4] :=1;
a[5] :=-2; a[6] :=-1; a[7] :=1; a[8] :=2;
b[5] :=-1; b[6] :=-2; b[7] :=-2; b[8] :=-1;
for i:=1 to N do for j :=1 to N do t[i,j] := 0;
t [i,i] :=1; {escolhemos uma casa do tabuleiro}
Tenta (2,1,1,q);
if q
then for i:=1 to N do
begin for j :=1 to N do write (t[i,j]:4); writeln; end
else writeln (‘Sem soluçao’);
end.
QUICKSORT - REORDENAÇÃO
DIVISÃO E CONQUISTA
• Consiste em dividir o problema em partes menores,
encontrar soluções para estas partes e combiná-las em
uma solução global.
• Divide-se em 3 fases:
1. Divisão (particionamento) do problema original em
sub-problemas similares ao original mas que são
menores em tamanho.
2. Resolução de cada sub-problema sucessivamente e
independentemente (em geral de forma recursiva).
3. Combinação das soluções individuais em uma
solução global para todo o problema.
O uso deste paradigma geralmente leva a soluções
eficientes e elegantes, em especial quando é utilizado
recursivamente.
Como exemplo, vamos considerar o problema de
encontrar simultaneamente o maior elemento e o
menor elemento de um vetor de inteiros.
VERSÃO RECURSIVA PARA OBTER O
MÁXIMO E O MÍNIMO
procedure MaxMin4 (Linf, Lsup: integer; var Max, Min: integer);
var Max1, Max2, Min1, Min2, Meio: integer;
begin
if Lsup – Linf <= 1
then if A[Linf] < A[Lsup]
then begin Max := A[Lsup] ; Min := A[Linf] ; end
else begin Max := A[Linf] ; Min := A[Lsup]; end
else begin
Meio := (Linf + Lsup) div 2;
MaxMin4 (Linf, Meio, Max1, Min1);
MaxMin4 (Meio+1, Lsup, Max2, Min2);
if Max1 > Max2 then Max := Max1 else Max := Max2;
if Min1 < Min2 then Min := Min1 else Min := Min2;
end;
end;
COMPLEXIDADE
• Seja T uma função de complexidade tal que T(n) é
o número de comparações entre os elementos de
A, se A tiver n elementos, T(n) = (3n/2) – 2 para o
melhor caso, caso médio, e pior caso.
• Este algoritmo é ótimo.
FIM
Download

Paradigmas de Projetos de Algoritmos