DCC 001 Programação de Computadores 2º Semestre de 2011 Módulo 10 Aula Expositiva 12 4.3 Ordenação 4.3.1 Seleção (SelectSort) 4.3.2 Intercalação (MergeSort) 4.3.3 Partição (QuickSort) 4.3.4 Dividir para Conquistar DCC 001 Programação de Computadores 2º Semestre de 2011 Prof. Osvaldo Carvalho
Ordenação (“sort”) Problema clássico da Ciência da Computação Dado um vetor A, obter outro vetor com os mesmos elementos de A dispostos em ordem crescente (ou decrescente) DCC001 - 2011-2
Conjunto Desordenado DCC001 - 2011-2
Conjunto Ordenado DCC001 - 2011-2
Ordenação por Seleção e Troca Em inglês, Select Sort Cabeçalho da função: function sA = SelectSort(A) // Constrói o vetor sA com os // mesmos elementos do vetor A // dispostos em ordem crescente. endfunction DCC001 - 2011-2
Ordenação por Seleção e Troca: Raciocínio Indutivo Suponhamos que as k-1 primeiras posições do vetor A já contenham elementos em suas posições finais Selecionamos o menor valor entre A(k) e A(length(A)) Trocamos o valor deste menor elemento com o valor em A(k), e fazemos k = k+1 Terminamos quando k = length(A)-1 O algoritmo se inicia com k igual a 1 DCC001 - 2011-2
Passos da Ordenação por Seleção DCC001 - 2011-2
Seleção de elementos a trocar de posição DCC001 - 2011-2
Ordenação por Seleção Segunda Versão function sA = SelectSort(A) for k = 1:length(A)-1 // Seleciona a posição entre A(k) e // A(length(A)) que contém o menor valor // Troca o valor de A(k) com o valor na // posição selecionada. end sA = A; endfunction DCC001 - 2011-2
Troca de Valores de Duas Variáveis Se fizermos x = y; y = x; o valor antigo de x que queríamos armazenar em y é perdido Se fizermos y = x; x = y; teremos o problema inverso Solução: variável temporária: temp = x; x = y; y = temp; DCC001 - 2011-2
Função MinimoPos Primeira Versão Parece com a função Minimo que teremos que modificar para ter como parâmetro extra de entrada a parte do vetor considerada ter também como parâmetro de saída a posição do elemento de menor valor, e não apenas o seu valor DCC001 - 2011-2
A Função Minimo function m = Minimo(A) // Encontra o menor valor presente no vetor A m = A(1); for k = 2:length(A) if m > A(k) m = A(k); end endfunction DCC001 - 2011-2
Função MinimoPos Versão Final function [m, im] = MinimoPos(A,low,high) // Encontra o menor valor (m) // presente no vetor A entre as // posições low e high, e informa // sua posição no vetor (im) m = A(low); im = low; for k = low+1:high if m > A(k) m = A(k); im = k; end endfunction DCC001 - 2011-2
Programa MinimoPos_teste.sce // Programa que testa a função MinimoPos exec("MinimoPos.sci"); exec("PrintMatrix.sci"); a = int(10*rand(1,10)); PrintMatrix("A",a); inicio = input("Inicio = "); fim = input("Fim = "); while inicio > 0 [m im] = MinimoPos(a,inicio,fim) end DCC001 - 2011-2
Função SelectSort Versão Final function sA = SelectSort(A) for k = 1:length(A)-1 // Seleciona a posição entre A(k) e // A(length(A)) que contém o menor valor [Min iMin] = MinimoPos(A,k,length(A)); // Troca os valores de A(k) com o valor // na posição selecionada. temp = A(k); A(k) = A(iMin); A(iMin) = temp; end sA = A; endfunction DCC001 - 2011-2
Complexidade Ordenação por Seleção O primeiro passo realiza n-1 comparações; O segundo, n-2; o terceiro, n-3, e assim por diante, até o último passo, que faz 1 comparação Nós dizemos que este algoritmo é O(n2), ou que tem complexidade quadrática DCC001 - 2011-2
Teste de Desempenho Ordenação por Seleção DCC001 - 2011-2
Ordenação por Intercalação (Merge Sort) DCC001 - 2011-2
Intercalação Intercalação (merge) é uma operação que produz um vetor ordenado a partir de dois outros já ordenados DCC001 - 2011-2
Ordenação por Intercalação Se o tamanho do vetor for maior que 1: divide-se o vetor em duas partes ordena-se cada parte separadamente faz-se a intercalação das partes já ordenadas senão, o vetor já está ordenado DCC001 - 2011-2
MergeSort Exemplo com n = 16 = 24 DCC001 - 2011-2
MergeSort Exemplo com n = 10 DCC001 - 2011-2
Função MergeSort function sA = MergeSort(A) if length(A) <= 1 then sA = A; else m = int((1+length(A))/2); sA = Merge(MergeSort(A(1:m)),... MergeSort(A(m+1:length(A)))); end endfunction DCC001 - 2011-2
A Função Merge - Intercalação function M = Merge(A,B) pA = 1; pB = 1; pM = 1 while pA <= length(A) & pB <= length(B) if A(pA) <= B(pB) then M(pM) = A(pA); pA = pA+1; else M(pM) = B(pB); pB = pB+1; end pM = pM+1; // continua.... “Consome” um elemento de A “Consome” um elemento de B DCC001 - 2011-2
A Função Merge - Arremate // Esgota A while pA <= length(A) M(pM) = A(pA); pM = pM+1; pA = pA+1; end // Esgota B while pB <= length(B) M(pM) = B(pB); pB = pB+1; endfunction DCC001 - 2011-2
Intercalação - Complexidade Cada passo “consome” um elemento de a ou de b; Se a e b têm tamanhos m e n, respectivamente, a intercalação de a e b exige no máximo m+n passos DCC001 - 2011-2
MergeSort – Complexidade O trabalho está na fase de intercalação O algoritmo é 4 = log2(16) 16 passos 16 passos 16 passos 16 passos DCC001 - 2011-2
Teste de Desempenho Ordenação por Seleção DCC001 - 2011-2
MergeSort – Teste de Desempenho 60 50000 DCC001 - 2011-2
Ordenação por Partição (quicksort) DCC001 - 2011-2
Vetor Particionado ≤ 100 ≥ 100 Para ordenar um vetor particionado, basta ordenar cada partição DCC001 - 2011-2
Vetor Particionado DCC001 - 2011-2
QuickSort, ou Ordenação por Partição Uso de operação de partição, que divide um vetor com 2 ou mais elementos em três partes: a da esquerda, contendo somente elementos menores ou iguais ao pivô, a do meio, contendo somente elementos iguais ao pivô, e a da direita contendo somente elementos maiores ou iguais ao pivô. Após a partição, o algoritmo é aplicado recursivamente às partições esquerda e direita DCC001 - 2011-2
A Função QuickSort function sA = quicksort(A) if length(A) > 1 then [l,m,r] = partition(A) sA = [quicksort(l) m quicksort(r)]; else sA = A; end endfunction DCC001 - 2011-2
Partições Sucessivas DCC001 - 2011-2
A Função Partition function [left,middle,right] = partition(A) pivot = A(int(length(A)/2)); inf = 1; sup = length(A); while sup >= inf while A(inf) < pivot inf = inf+1; end while A(sup) > pivot sup = sup-1; if sup >= inf then temp = A(inf); A(inf) = A(sup); A(sup) = temp; inf = inf+1; sup = sup-1; left = A(1:sup); middle = A(sup+1:inf-1); right = A(inf:length(A)); endfunction DCC001 - 2011-2
Notas sobre a Função Partition O pivô é escolhido como o elemento posicionado ao meio do vetor A. Isto não é um requisito do algoritmo, que entretanto exige que o pivô seja um dos elementos de A; inf é mantido de forma tal que, a qualquer momento, todos os elementos à sua esquerda são menores ou iguais ao pivô. Repare que isto é válido inicialmente, pois não existe nenhum elemento à sua esquerda, e que é mantido válido por todos os comandos; DCC001 - 2011-2
Notas sobre a Função Partition sup é mantido de forma tal que, a qualquer momento, todos os elementos à sua direita são maiores ou iguais ao pivô; a argumentação para esta afirmativa é análoga à empregada para a variável inf; inf avança sempre para a direita, e sup para a esquerda; o loop principal para quando estes dois ponteiros se cruzam; DCC001 - 2011-2
Notas sobre a Função Partition no primeiro loop interno, inf avança para a direita até encontrar um elemento com valor maior ou igual ao pivô; no segundo loop interno, sup avança para a esquerda até encontrar um elemento com valor menor ou igual ao pivô; os elementos encontrados nestes dois loops internos são trocados de posição, a não ser que inf e sup já tenham se cruzado; DCC001 - 2011-2
QuickSort - Complexidade Melhor Caso O pivô é tal que cada partição divide o vetor ao meio São feitas n log(n) comparações Pior Caso O pivô é tal que cada partição produz uma parte com um elemento, e outra com n-1 elementos A complexidade é quadrática - Prática Na prática os casos ruins são raros, e o QuickSort apresenta um excelente desempenho DCC001 - 2011-2
DCC001 - 2011-2
DCC001 - 2011-2
MergeSort – Teste de Desempenho 60 50000 DCC001 - 2011-2
Desempenho Quicksort 700.000 DCC001 - 2011-2
Desempenho Quicksort Elementos Ordenados por Segundo DCC001 - 2011-2
Dividir para Conquistar MergeSort e QuickSort são exemplos de uma estratégia clássica em computação Dado um problema de tamanho n O problema é dividido em 2 subproblemas de tamanho n/2 (ou 3 de tamanho n/3, ou...) Cada subproblema é atacado recursivamente, com a mesma estratégia, a não ser que o seu tamanho seja suficientemente pequeno para permitir uma solução direta As soluções dos subproblemas são combinadas para resolver o problema original DCC001 - 2011-2
Conclusões Um mesmo problema pode admitir diversas soluções, cujo desempenho pode variar significativamente Para problemas grandes a adoção de soluções mais elaboradas pode ser um imperativo Recursividade é uma ferramenta poderosa para a descoberta e descrição de algoritmos DCC001 - 2011-2