ALGORITMOS Oficinas de Desenvolvimento de Software

Preview:

Citation preview

ALGORITMOSOficinas de Desenvolvimento de Software

Prof. Norton

www.norton.net.brNorton.Glaser@fatec.sp.gov.br

Programação

Inicio as 19:00 Conceitos e definição de algoritmos Vetores e matrizes Recursão Intervalo 20:40 Retorno 21:00 Pesquisa Ordenação

O que é algoritmo ?

Um algoritmo é uma sequência ordenada de instruções para resolver um problema.

Um algoritmo deve possuir as seguintes propriedades: garantia de término, exatidão e efetividade.

“Algoritmo é uma sequência de passos que visa atingir um objetivo bem definido” (FORBELLONE, 1999)

“Algoritmo é a descrição de uma sequência de passos que deve ser seguida para a realização de uma tarefa”

(ASCENCIO, 1999)

O que é algoritmo ?

Um algoritmo e composto por: Problematização Instruções unitarias Sequencia Logica

Um algoritmo pode ser representado por: Uma descrição narrativa Um Fluxograma Um Programa

Variáveis

Variável e um espaço alocado na memoria para o armazenamento de um dado, durante a execução de um programa.

Este valor pode ser modificado durante o processamento do algoritmo

Exemplo:int quantidade = 8;float temperatura = 21.5;

Estruturas de Dados

Os tipos primitivos (inteiro, real, caracter e lógico) não são suficientes para representar todos os tipos de informação.

Particularmente quando temos mais de uma informação relacionada. Ex: Lista dos nomes dos alunos de uma sala, endereço de alguém etc.

Utilizaremos os tipos primitivos para construir outras estruturas de dados mais complexas.

Vetores

Também denominados: Estruturas compostas homogêneas unidimensionais

Permitem a manipulação de um conjunto de informações de um mesmo tipo primitivo

Exemplo: float valores [40];

Onde: 40: Quantidade total de elementos do vetor float: Tipo primitivo base do vetor valores: nome que representa o vetor no programa O índice do vetor inicia-se em 0 (zero) indo até 39 (n – 1)

Vetores Manipulação:

0 1 2 3 4 5 6 7 8 37 38 39

int A = 5;

valores [ 6 ] = 6.5;

6.57.8 5.3

valores

valores [ 1 ] = 7.8;valores [ 3 ] = 5.3;

valores [ A ] = 9.8;valores [ A-1 ] = 9.1;leia ( valores [ A+3 ] ); // supondo que foi informado 4.7

9.89.1 4.7

Vetores - Notas acima da média usando vetor

float notas [10];int NotaAcima;float Soma, Media;Soma = 0;NotaAcima = 0;for(int X =0; X < 10; X++){

cin >> notas[X];Soma=Soma + notas[X];

}Media = Soma / 10;for(int X=0; X<10; X++){

if(notas[X] > Média ){NotaAcima=NotaAcima + 1;

}}cout << NotaAcima;

Matrizes

Também denominadas: Estruturas compostas homogêneas

multidimensionais Permitem a manipulação de um conjunto de

informações de um mesmo tipo primitivo. Exemplo:

int SALA[4][4];

Onde: SALA: Nome da matriz 4: Capacidade da primeira e da segunda dimensão int: Tipo primitivo base da matriz

Matrizes Manipulação:

0 1 2 3int A, B;

SALA [1][2] = 5;

SALA

SALA [2][1]= 6;SALA [0][1] = 7;A = 3;

SALA [A][B]= 8;SALA [A][B-2]= 9;SALA [A-2][B-2]= 10;

0

1

2

3

5

6

7

89

10

11

12

SALA [B][A] =11;SALA [B-2][A] =12;

B = 2;

Matrizes – Temperatura Semanal

float temperatura [7][3];float minima, maxima, media;minima = 99;maxima = -99;media = 0;for(int J =0 ; J<7; J++){

cin >> temperatura[J][0] ; //Temperatura minima do diacin >> temperatura[J][1] ; //Temperatura maxima do diatemperatura[J][2] = (temperatura[J][0] + temperatura[J][1]) /2;if(temperatura[J][0] <= minima) minima = temperatura[J][0];if(temperatura[J][1] >= maxima) maxima = temperatura[J][1];media += temperatura[J][2];

}media = media / 7;cout << minima << maxima << media;

Recursão

Recursividade é o mecanismo de programação no qual uma definição de função ou de outro objeto refere-se ao próprio objeto sendo definido.

São sinônimos: recursividade, recursão, recorrência.

Recursão

Funções Recursivas Recursividade Mutua Recursividade de cauda

Recursão – Funções Recursivas Estratégia para a definição recursiva de uma função:

dividir o problema em problemas menores do mesmo tipo

resolver os problemas menores (dividindo-os em problemas ainda menores, se necessário)

combinar as soluções dos problemas menores para formar a solução final

Ao dividir o problema sucessivamente em problemas menores eventualmente os casos simples são alcançados: não podem ser mais divididos suas soluções são definidas explicitamente

Recursão – Funções Recursivas Em todas as funções recursivas existe:

Um caso base, ou condição de parada, cujo resultado é imediatamente conhecido.

Um passo recursivo em que se tenta resolver um sub problema do problema inicial.

Assim função recursiva é uma função que é definida em termos de si mesma.

Recursão – Fatorial

int fatorial(int n){if(n == 1) return n;return fatorial(n-1) * n;}

Recursão – Potencia de 2

int pot(int base, int exp){if(exp == 0) return 1;return (base * pot(base, exp-1));}

Recursão – Fibonacci

int fibonacci(int n){if(n==1 || n==2) return 1;elsereturn fibonacci(n-1)+fibonacci(n-2);}

Recursão – Recursividade Mutua Recursividade mútua ocorre quando

duas ou mais funções são definidas em termos uma da outra.

Na Recursividade mútua , as subrotinas são conectadas através de uma cadeia de chamadas sucessivas que acaba retornando à primeira que desencadeou.

Para exemplificar a recursividade indireta vamos utilizar um código que verifica se um número é par ou ímpar:

Recursão – Par e Impar

int par(int n){if(n==0) return 1;return impar(n-1);}

int impar(int n){if(n==0) return 0;return par(n-1);}

Recursividade de Cauda

Uma função recursiva apresenta recursividade de cauda se o resultado final da chamada recursiva é o resultado final da própria função.

Se o resultado da chamada recursiva deve ser processado de alguma maneira para produzir o resultado final, então a função não apresenta recursividade de cauda.

A recursão de cauda é uma técnica de recursão que faz menos uso de memória durante o processo de empilhamento, o que a torna mais rápida que a recursão comum.

Recursividade de Cauda

int fatorial_aux(int n, int parcial){if(n==1) return parcial;return fatorial_aux((n-1), parcial*n));}

int fatorial_cauda(int n){return fatorial_aux(n, 1);}

Recursividade de Cauda

O que acontece é uma transcrição direta de um cálculo iterativo: passa-se inicialmente o valor parcial 1 para a função

fatorial_aux() e ela “atualiza” este valor a cada chamada recursiva, multiplicando o cálculo parcial do fatorial por n, n – 1, n – 2, …, até o “caso base”.

Neste ponto, o valor do fatorial já foi calculado e é apenas retornado.

Esta recursão de cauda poderia gastar menos memória ainda se utilizasse passagem por referência dos parâmetros.

Desta forma, cada função recursiva empilhada não criaria um espaço de memória para os parâmetros n e parcial, mas apenas atualizaria estas duas variáveis sem ficar fazendo cópias delas.

Recursão versus Iteração

Recursão Iteração

Estruturas de seleção if, if-else ou switch.

Estruturas de repetição for, while ou do-while

Repetição por chamadas de funções repetidas.

Repetição explícita.

Termina quando um caso base é reconhecido.

Termina quando teste do laço falha.

Pode ocorrer infinitamente Pode ocorrer infinitamente.

Lento Rápido.

Soluções simples e de fácil manutenção

Soluções complicadas e de difícil manutenção.

Recursão versus Iteração

Mesmo diminuindo-se os gastos de memória da recursão através de uma implementação que usa recursão de cauda e passagem de parâmetros por referência, o cálculo iterativo será comumente mais rápido por não fazer repetidas chamadas de funções.

No entanto, a recursão de cauda é importante principalmente em linguagens de programação funcionais, onde não existem estruturas de repetição.

Neste caso, a recursão é a única abordagem disponível e o desempenho pode ser fator crítico, exigindo implementações de recursão de cauda.

Pesquisa

Algoritmos de pesquisa tem o objetivo de encontrar valores em uma estrutura de dados.

Para vetores ou matrizes não ordenadas utilizamos a pesquisa linear.

Para vetores ou matrizes ordenadas podemos utilizar a pesquisa binaria.

Pesquisa Linear

Busca linear ou sequencial e um tipo de pesquisa em vetores ou listas de modo sequencial, elemento por elemento, de modo que a função do tempo em relação ao número de elementos é linear, ou seja, cresce proporcionalmente.

No melhor caso, o elemento a ser buscado é encontrado logo na primeira tentativa da busca.

No pior caso, o elemento a ser buscado encontra-se na última posição e são feitas N comparações, sendo N o número total de elementos.

Pesquisa Linear - Iterativo

int linearI(int v[], int tamanho, int busca){for(int i=0; i<tamanho; i++){

if(v[i] == busca){return i;

}}return -1;

}

Pesquisa Binaria

A pesquisa ou busca binária é um algoritmo de busca em vetores que segue o paradigma de divisão e conquista.

Ela parte do pressuposto de que o vetor está ordenado e realiza sucessivas divisões do espaço de busca comparando o elemento buscado (chave) com o elemento no meio do vetor.

Se o elemento do meio do vetor for a chave, a busca termina com sucesso.

Caso contrário, se o elemento do meio vier antes do elemento buscado, então a busca continua na metade posterior do vetor.

E finalmente, se o elemento do meio vier depois da chave, a busca continua na metade anterior do vetor.

Pesquisa Binaria - Iterativoint binariaI(int v[], int chave, int N){

int inf = 0; //limite inferiorint sup = N-1; //limite superiorint meio;while(inf <= sup){

meio = inf + (sup-inf)/2;if(chave == v[meio]){

return meio;} else {

if(chave < v[meio])sup = meio – 1;

else inf = meio + 1;

}return -1; //não encontrado

}

Ordenação

Ordenação é o ato de se colocar os elementos de uma sequência de informações, ou dados, em uma ordem predefinida.

Os algoritmos que ordenam um conjunto, geralmente representados em um vetor, são chamados de algoritmos de ordenação.

Os algoritmos de ordenação auxiliam os algoritmos de busca.

Ordenação

Métodos Simples Selection sort – Ordenação por seleção Insertion sort - Ordenação por inserção Bubble sort - Ordenação por flutuação

Métodos Sofisticados Quicksort – Ordenação Eficiente

Ordenação por Seleção

Algoritmo de ordenação baseado em se passar sempre o menor valor do vetor para a primeira posição (ou o maior dependendo da ordem requerida),

Depois o de segundo menor valor para a segunda posição, e assim é feito sucessivamente com os (n-1) elementos restantes, até os últimos dois elementos.

Ordenação por Seleção

Ordenação por Seleçãovoid selection_sort(int v[], int tam){

int min,aux;for(int i=0; i < (tam-1); i++) {min = i;for(int j = (i+1); j<tam; j++){

if(v[j] < num[min]){min = j;

}}if(i != min){aux = num[i];num[i] = num[min]; num[min] = aux;

}}

}

Ordenação por Seleção

5 3 1 4 2 4 comparações (5 e 3; 3 e 1; 1 e 4; 1 e 2)

1 3 5 4 2 3 comparações (3 e 5; 3 e 4; 3 e 2)

1 2 5 4 3 2 comparações (5 e 4; 4 e 3) 1 2 3 4 5 1 comparação (4 e 5) 1 2 3 4 5 n – 1 iterações realizadas: vetor

ordenado

Ordenação por Inserção

Semelhante ao processo de ordenação de cartas usado por jogadores de baralho. Olhar a sequência de cartas da esquerda para a direita

e ver se alguma está fora da ordem. Ao encontrar uma fora da ordem, procura sua posição

correta nas cartas já olhadas que estão em ordem. Eficiente quando aplicado a um pequeno número de

elementos. Em termos gerais, ele percorre um vetor de elementos

da esquerda para a direita e à medida que avança vai deixando os elementos mais à esquerda ordenados

Ordenação por Inserção

Ordenação por Inserção

void insertSort(int v[], int tam){int eleito, j;for(int i=1; i < tam; i++) {eleito = v[i];j = i-1;while((j>=0) && (eleito < v[j])){v[j+1] = números[j];j--;

}v[j+1] = eleito;}}

Ordenação por Inserção

5 4 3 2 1 1 comparação (5 e 4) 4 5 3 2 1 2 comparações (3 e 5; 3 e 4) 3 4 5 2 1 3 comparações (2 e 5; 2 e 4; 2 e 3) 2 3 4 5 1 4 comparações (1 e 5; 1 e 4; 1 e 3;

1 e 2) 1 2 3 4 5 N vazio e O igual ao tamanho do

vetor: vetor ordenado

Ordenação por Bolha

Dado um vetor de N elementos, inicia a iteração comparando o primeiro elemento com o segundo: se não estiverem em ordem (primeiro maior

que o segundo), eles são trocados; caso contrário, nada acontece. Em seguida, faz-se o mesmo para o segundo e

terceiro elementos. O processo se repete até que, ao final de n – 1

iterações, o maior elemento do vetor será deslocado de sua posição inicial para a última.

Ordenação por bolha

Ordenação por bolha

void bubbleSort(int v[], int tam){int aux;for(int i=tam-1; i >=1; i--) {for(int j=0; j < i; j++) {if(v[j]>v[j+1]){aux = v[j];v[j] = v[j+1];}

}}

}

Ordenação por Bolha

5 4 3 2 1 4 comparações (5 e 4; 5 e 3; 5 e 2; 5 e 1)

4 3 2 1 5 3 comparações (4 e 3; 4 e 2; 4 e 1) 3 2 1 4 5 2 comparações (3 e 2; 3 e 1) 2 1 3 4 5 1 comparação (2 e 1) 1 2 3 4 5 n – 1 iterações realizadas: vetor

ordenado

Ordenação Eficiente - QuickSort O Quicksort adota a estratégia de divisão

e conquista. A estratégia consiste em rearranjar as

chaves de modo que as chaves "menores" precedam as chaves "maiores".

Em seguida o Quicksort ordena as duas sublistas de chaves menores e maiores recursivamente até que a lista completa se encontre ordenada.

Ordenação Eficiente - QuickSort Os passos são:

1. Escolha um elemento da lista, denominado pivô;

2. Rearranje a lista de forma que todos os elementos anteriores ao pivô sejam menores que ele, e todos os elementos posteriores ao pivô sejam maiores que ele. Ao fim do processo o pivô estará em sua posição final e haverá duas sublistas não ordenadas. Essa operação é denominada partição;

3. Recursivamente ordene a sublista dos elementos menores e a sublista dos elementos maiores;

Ordenação Eficiente - QuickSort A base da recursão

são as listas de tamanho zero ou um, que estão sempre ordenadas. O processo é finito, pois a cada iteração pelo menos um elemento é posto em sua posição final e não será mais manipulado na iteração seguinte

Ordenação Eficiente - QuickSort

Ordenação Eficiente - QuickSort

void quickSort(int v[], int esquerda, int direita){int i, j, x, y;i = esquerda;j = direita;x = v[(esquerda + direita) / 2];while(i<=j) {

while(valor[i] < x && i < direita) {i++;

}while(valor[j] > x && j > esquerda){j--;

}if(i <=j){y = valor[i];valor[i] = valor[j];valor[j] = y;i++;j--;

}}if(j > esquerda) quickSort(v, esquerda, j);if(i < direita) quickSort(v, i, direita);

}

Recommended