Estruturas de Dados 2 Técnicas de Projeto de Algoritmos Dividir e Conquistar IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 1/83 Dividir e Conquistar ● Projeto de Algoritmos por Divisão e Conquista ● Introdução ● Busca “Recursiva” ● Ordenação: InsertionSort, MergeSort, HeapSort e QuickSort ● Resumo IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 2/83 Dividir e Conquistar ● Introdução ● “Dividir e Conquistar” é uma técnica de projeto de algoritmos que consiste em resolver um problema a partir da solução de “sub-problemas menores” do mesmo tipo. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 3/83 Dividir e Conquistar ● Introdução ● “Dividir e Conquistar” é uma técnica de projeto de algoritmos que consiste em resolver um problema a partir da solução de “sub-problemas menores” do mesmo tipo. ● Se os sub-problemas obtidos após a “divisão” ainda são muito grandes para a solução “direta”, aplica-se novamente a “divisão”, até ter problemas pequenos o suficiente para terem solução trivial ou direta. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 4/83 Dividir e Conquistar ● Introdução ● Após o processo de “divisão” em sub-problemas menores, e sua “conquista”, basta “combinar” os resultados dos sub-problemas menores, para obter a solução para o problema como um todo. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 5/83 Dividir e Conquistar Passos para “divisão e conquista”: 1. Divisão: propor uma forma de dividir o problema original em sub-problemas iguais, porém menores (recursivamente); 2. Conquista: ao se obter sub-problemas “pequenos o suficiente”, resolvê-los diretamente; 3. Combinação: combinar as soluções de forma a obter a solução ao problema original. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 6/83 Dividir e Conquistar ● Vantagens ● Solução “direta” do ponto de vista da recursividade; ● Elegância; ● Usualmente produz algoritmos eficientes (complexidade logarítmica!!!) ● Desvantagem ● Recursão!!!! IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 7/83 Dividir e Conquistar ● Como aplicar? ● Processo “Indutivo” ao projeto de algoritmos(recursão) ● Aplicável sempre que for possível obter “subproblemas menores independentes entre si” ● Procurar uma divisão “igualitária” de um problema em diversos sub-problemas....... ● Deve ser possível (e de preferência simples e rápido) combinar os resultados dos sub-problemas.... IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 8/83 Dividir e Conquistar ● Justificativa ● Esta técnica pode ser empregada em diversas situações comuns porém importantes: ● Somar N números; ● Encontrar um elemento em um vetor ordenado; IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 9/83 Dividir e Conquistar ● Exemplo da aplicação da técnica: ● Como somar N números, a1, a2, ..., an? Se n é 1, a soma é o próprio a1. ● Se n>1, podemos dividir o problema em dois subproblemas menores: 1.Somar os números de a1 até an/2 ; ● 2.Somar os número de an/2 até an ; 3.Somar os resultados!!! IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 10/83 Dividir e Conquistar ● Exemplo da aplicação da técnica: ● Como somar N números, a1, a2, ..., an? ● Eficiência???? IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 11/83 Dividir e Conquistar ● Exemplo da aplicação da técnica: ● Como somar N números, a1, a2, ..., an? ● Eficiência???? ● O(n)......(Melhor que uma abordagem “exaustiva”????) IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 12/83 Dividir e Conquistar ● Exemplo da aplicação da técnica: ● Como somar N números, a1, a2, ..., an? ● Eficiência???? ● O(n)......(Melhor que uma abordagem “exaustiva”????) ● Claramente NÃO!!!! IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 13/83 Dividir e Conquistar ● Exemplo da aplicação da técnica: ● Como somar N números, a1, a2, ..., an? ● Eficiência???? ● O(n)......(Melhor que uma abordagem “exaustiva”????) ● Claramente NÃO!!!! ● Portanto, aplicar “Divisão e Conquista” não garante, por si só, a obtenção de algoritmos eficientes! IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 14/83 Dividir e Conquistar ● OUTRO exemplo: Buscar um elemento! Como encontrar o elemento em um vetor de tamanho N: a1, a2, ..., an? ● Se n é 1, e o elemento a é o procurado, achou, 1 senão não achou! ● Se n>1, podemos dividir o problema em dois subproblemas menores: 1.Encontrar o elemento no vetor de a1 até an/2 ● 2.Encontrar o elemento no vetor de an/2 até an IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 15/83 Dividir e Conquistar ● Mas esta técnica não consegue gerar resultados melhores que a “Força Bruta”??? IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 16/83 Dividir e Conquistar ● Mas esta técnica não consegue gerar resultados melhores que a “Força Bruta”??? Pode sim..... ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 17/83 Dividir e Conquistar ● Mas esta técnica não consegue gerar resultados melhores que a “Força Bruta”??? Pode sim..... ● Basta aplicá-la “adequadamente”......! ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 18/83 Dividir e Conquistar ● Mas esta técnica não consegue gerar resultados melhores que a “Força Bruta”??? Pode sim..... ● Basta aplicá-la “adequadamente”......! ● Exemplo de uso adequado: “Busca Binária”. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 19/83 Dividir e Conquistar Busca Binária: ● ● Encontrar um determinado elemento (chave) em um vetor ordenado de tamanho N: a1, a2, ..., an?: ● Verificar se a chave está na posição ax = an/2: ● Se estiver, encontrou! ● Se não estiver, realizar a busca binária nos vetores: a1 até ax-1,se chave < ax , ou em ax+1 até an se chave > ax. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 20/83 Dividir e Conquistar Busca Binária: Exemplo: ● Encontrar o número 12 na lista: 3 5 7 8 9 11 12 19 IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 21/83 Dividir e Conquistar Busca Binária: Exemplo: ● Encontrar o número 12 na lista: 3 5 7 8 9 11 12 19 3 5 7 8 9 11 12 19 (está na posição X=n/2?)Ñ! IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 22/83 Dividir e Conquistar Busca Binária: Exemplo: ● Encontrar o número 12 na lista: 3 5 7 8 9 11 12 19 3 5 7 8 9 11 12 19 (está na posição X=n/2?)Ñ! 3 5 7 8 9 11 12 19 (está na posição X=n/2?)S! IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 23/83 Dividir e Conquistar Busca Binária: ● ● Tá, mas e daí???? ● Bem, a eficiência deste algoritmo é Θ(lg n).... ● Muito mais eficiente que a abordagem “Força Bruta”..... ....pena que o vetor precisa estar ordenado....... ● ....mas podemos aplicar a técnica de Divisão e Conquista ● para ordenar vetores também!!!!! IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 24/83 Dividir e Conquistar ● Ordenação com Divisão e Conquista: ● Problema: Ordenar um vetor de tamanho N: a , a , ..., 1 2 an ● Um vetor de um elemento já está ordenado! ● Um vetor de tamanho n pode ser ordenado pela “intercalação” de dois sub-vetores: 1.Um vetor de a1 até an/2 2.Outro vetor de an/2 até an IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 25/83 Dividir e Conquistar ● Ordenação com Divisão e Conquista: ● Problema: Ordenar um vetor de tamanho N: a , a , ..., 1 2 an ● Um vetor de um elemento já está ordenado! ● Um vetor de tamanho n pode ser ordenado pela “intercalação” de dois sub-vetores: 1.Um vetor de a1 até an/2 2.Outro vetor de an/2 até an ● Esta maneira de ordenar dá origem ao algoritmo recursivo de ordenação “MergeSort”!!! IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 26/83 Dividir e Conquistar ● Ordenação com Divisão e Conquista: ● Problema: Ordenar um vetor de tamanho N: a , a , ..., 1 2 an ● Um vetor de um elemento já está ordenado! ● Um vetor de tamanho n pode ser ordenado pela “intercalação” de dois sub-vetores: 1.Um vetor de a1 até an/2 2.Outro vetor de an/2 até an ● Esta maneira de ordenar dá origem ao algoritmo recursivo de ordenação “MergeSort”!!! ● Isto é projetar um algoritmo por divisão e conquista!!! IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 27/83 Dividir e Conquistar ● MergeSort: ● Se a função “intercala” for eficiente=O(n) ● Detalhe: para conseguir implementar a intercalação de forma eficiente, é necessário um “vetor auxiliar”, o que aumenta a memória necessária para o algoritmo...não é uma ordenação “in-place”,como a Ordenação por Seleção ● T(n) = 2T(n/2) + O(n) ● Logo, Mergesort é Θ(n lg n) (Master) IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 28/83 Dividir e Conquistar ● MergeSort(A, e, d): : Pseudo-Código IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 29/83 Dividir e Conquistar ● Intercala(A, e, d): Pseudo-Código IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 30/83 Dividir e Conquistar Aplicando “Dividir e Conquistar” de outra forma: ● Seja S um conjunto de n ≥ 2 inteiros e x um elemento qualquer de S. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 31/83 Dividir e Conquistar Aplicando “Dividir e Conquistar” de outra forma: ● Seja S um conjunto de n ≥ 2 inteiros e x um elemento qualquer de S. ● Sejam S1 e S2 os subconjuntos de {S − x} dos elementos menores ou iguais a x e maiores que x, respectivamente. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 32/83 Dividir e Conquistar Aplicando “Dividir e Conquistar” de outra forma: ● Seja S um conjunto de n ≥ 2 inteiros e x um elemento qualquer de S. ● Sejam S1 e S2 os subconjuntos de {S − x} dos elementos menores ou iguais a x e maiores que x, respectivamente. ● Ambos S1 e S2 possuem menos de n elementos. Por hipótese de indução, sabemos ordenar os conjuntos S1 e S2. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 33/83 Dividir e Conquistar Aplicando “Dividir e Conquistar” de outra forma: ● Seja S um conjunto de n ≥ 2 inteiros e x um elemento qualquer de S. ● Sejam S1 e S2 os subconjuntos de {S − x} dos elementos menores ou iguais a x e maiores que x, respectivamente. ● Ambos S1 e S2 possuem menos de n elementos. Por hipótese de indução, sabemos ordenar os conjuntos S1 e S2. ● Podemos obter S ordenado concatenando S1 ordenado, x e S2 ordenado. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 34/83 Dividir e Conquistar Aplicando “Dividir e Conquistar” de outra forma: ● Seja S um conjunto de n ≥ 2 inteiros e x um elemento qualquer de S. ● Sejam S1 e S2 os subconjuntos de {S − x} dos elementos menores ou iguais a x e maiores que x, respectivamente. ● Ambos S1 e S2 possuem menos de n elementos. Por hipótese de indução, sabemos ordenar os conjuntos S1 e S2. ● Podemos obter S ordenado concatenando S1 ordenado, x e S2 ordenado. ● Esta abordagem dá origem ao algoritmo “QuickSort”!!! ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 35/83 Dividir e Conquistar Em contraste ao Mergesort, no Quicksort é a operação de divisão que é mais custosa: depois de escolhermos o pivô(x), temos que separar os elementos do vetor maiores que o x dos menores ou iguais a x. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 36/83 Dividir e Conquistar Em contraste ao Mergesort, no Quicksort é a operação de divisão que é mais custosa: depois de escolhermos o pivô(x), temos que separar os elementos do vetor maiores que o x dos menores ou iguais a x. ●Conseguimos fazer essa divisão com (n) operações: basta varrer o vetor com dois apontadores, um varrendo da direita para a esquerda e outro da esquerda para a direita, em busca de elementos situados na parte errada do vetor, e trocar um par de elementos de lugar quando encontrado. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 37/83 Dividir e Conquistar Em contraste ao Mergesort, no Quicksort é a operação de divisão que é mais custosa: depois de escolhermos o pivô(x), temos que separar os elementos do vetor maiores que o x dos menores ou iguais a x. ●Conseguimos fazer essa divisão com (n) operações: basta varrer o vetor com dois apontadores, um varrendo da direita para a esquerda e outro da esquerda para a direita, em busca de elementos situados na parte errada do vetor, e trocar um par de elementos de lugar quando encontrado. ●Após essa etapa basta ordenarmos os dois trechos do vetor recursivamente para obtermos o vetor ordenado, ou seja, a conquista é imediata. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 38/83 Dividir e Conquistar ● Quicksort(A,e,d) - Pseudo-Código: IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 39/83 Dividir e Conquistar ● Quicksort(A,e,d) - Pseudo-Código(cont): IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 40/83 Dividir e Conquistar Quicksort- Idéia Base 1. Selecionar um elemento para ser o pivô 2. Rearranjar a lista de modo que todos os elementos nas posições a esquerda do pivô sejam menores ou iguais a ele, e aqueles a direita do pivô sejam maiores que ele. 3. Permutar o pivô com o último elemento da primeira sub-lista(menores ou iguais). Agora o pivô está em sua posição final. 4. Ordenar as duas sub-listas. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 41/83 Dividir e Conquistar QuickSort – Exemplo ● 5 3 1 9 8 2 4 7 partition 2 3 1 4 5 8 9 7 2 3 1 4 partition 1 2 3 4 partition 1 3 4 partition 4 8 9 7 partition 7 8 9 7 9 IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 42/83 Dividir e Conquistar ● ● Quicksort – Análise da Complexidade Quantas comparações e quantas trocas o algoritmo Quicksort executa no pior caso ? IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 43/83 Dividir e Conquistar ● ● ● Quicksort – Análise da Complexidade Quantas comparações e quantas trocas o algoritmo Quicksort executa no pior caso ? Certamente a operação de divisão tem complexidade (n), mas o tamanho dos dois subproblemas depende do pivô escolhido. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 44/83 Dividir e Conquistar ● ● ● ● Quicksort – Análise da Complexidade Quantas comparações e quantas trocas o algoritmo Quicksort executa no pior caso ? Certamente a operação de divisão tem complexidade (n), mas o tamanho dos dois subproblemas depende do pivô escolhido. No pior caso, cada divisão sucessiva do Quicksort separa um único elemento dos demais, recaindo na recorrência: T(n) = 0, se n = 1 T(n) = T(n − 1) + n, se n > 1, IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 45/83 Dividir e Conquistar ● ● ● ● ● Quicksort – Análise da Complexidade Quantas comparações e quantas trocas o algoritmo Quicksort executa no pior caso ? Certamente a operação de divisão tem complexidade (n), mas o tamanho dos dois subproblemas depende do pivô escolhido. No pior caso, cada divisão sucessiva do Quicksort separa um único elemento dos demais, recaindo na recorrência: T(n) = 0, se n = 1 T(n) = T(n − 1) + n, se n > 1, Portanto, (n2) comparações e trocas são executadas no pior caso!!!!!! IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 46/83 Dividir e Conquistar Mas o Quicksort não era o algoritmo de ordenação mais eficiente???? ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 47/83 Dividir e Conquistar Mas o Quicksort não era o algoritmo de ordenação mais eficiente???? ● ● Então, o algoritmo Quicksort é assintoticamente menos eficiente que o Mergesort no pior caso. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 48/83 Dividir e Conquistar Mas o Quicksort não era o algoritmo de ordenação mais eficiente???? ● ● ● Então, o algoritmo Quicksort é assintoticamente menos eficiente que o Mergesort no pior caso. Entretanto, no caso médio, o Quicksort efetua (n log n) comparações e trocas. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 49/83 Dividir e Conquistar Mas o Quicksort não era o algoritmo de ordenação mais eficiente???? ● ● ● ● Então, o algoritmo Quicksort é assintoticamente menos eficiente que o Mergesort no pior caso. Entretanto, no caso médio, o Quicksort efetua (n log n) comparações e trocas. Assim, na prática, o Quicksort é bastante eficiente, com uma vantagem adicional em relação ao Mergesort: é “in place”, isto é, não utiliza um vetor auxiliar. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 50/83 Dividir e Conquistar Considerando que o pior caso não ocorre com freqüência, pois usualmente, pegando um “pivô” aleatório, é “muito difícil” escolher sempre um pivô que divida o vetor de tamanho n em dois vetores, um dos menores e outro dos maiores que o pivô, com tamanhos (n-1) e 1.... ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 51/83 Dividir e Conquistar Considerando que o pior caso não ocorre com freqüência, pois usualmente, pegando um “pivô” aleatório, é “muito difícil” escolher sempre um pivô que divida o vetor de tamanho n em dois vetores, um dos menores e outro dos maiores que o pivô, com tamanhos (n-1) e 1.... ●Desta forma, supondo uma divisão do vetor de tamanho n em dois sub-vetores (n/2), e considerando o tempo de separação entre os maiores e os menores que o pivô sendo O(n).... ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 52/83 Dividir e Conquistar Considerando que o pior caso não ocorre com freqüência, pois usualmente, pegando um “pivô” aleatório, é “muito difícil” escolher sempre um pivô que divida o vetor de tamanho n em dois vetores, um dos menores e outro dos maiores que o pivô, com tamanhos (n-1) e 1.... ●Desta forma, supondo uma divisão do vetor de tamanho n em dois sub-vetores (n/2), e considerando o tempo de separação entre os maiores e os menores que o pivô sendo O(n).... ●O tempo médio T(n)=2T(n/2)+O(n) = O(n lg n) ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 53/83 Dividir e Conquistar Ordenação: Mas não há um algoritmo que seja eficiente em todos os casos, e “in place” ao mesmo tempo? ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 54/83 Dividir e Conquistar Ordenação: Mas não há um algoritmo que seja eficiente em todos os casos, e “in place” ao mesmo tempo? ● Vocês tinham que perguntar????? ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 55/83 Dividir e Conquistar Ordenação: Mas não há um algoritmo que seja eficiente em todos os casos, e “in place” ao mesmo tempo? ● Vocês tinham que perguntar????? ● Este algoritmo chama-se “HeapSort”. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 56/83 Dividir e Conquistar Ordenação: Mas não há um algoritmo que seja eficiente em todos os casos, e “in place” ao mesmo tempo? ● Vocês tinham que perguntar????? ● Este algoritmo chama-se “HeapSort”. ● E é baseado numa estrutura de dados “inteligente” denominada “Heap”..... implementa uma “fila de prioridades”.... ● Podermos utilizá-la para fazer uma ordenação “inplace” e Θ(n lg n)!!!! ● (Mas o Quicksort ainda é mais rápido!!!!) ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 57/83 Dividir e Conquistar Ordenação por Heap(HeapSort): ● Tarefa: Implementar a estrutura de dados “Heap” para podermos utilizá-la para fazer uma ordenação “in-place” e Θ(n lg n)!!!! ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 58/83 Dividir e Conquistar Ordenação por Heap(HeapSort): ● Tarefa: Implementar a estrutura de dados “Heap” para podermos utilizá-la para fazer uma ordenação “in-place” e Θ(n lg n)!!!! ● Mas o que é um Heap??? ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 59/83 Dividir e Conquistar Ordenação por Heap(HeapSort): ● Tarefa: Implementar a estrutura de dados “Heap” para podermos utilizá-la para fazer uma ordenação “in-place” e Θ(n lg n)!!!! ● Mas o que é um Heap??? ● É uma “simulação” de uma árvore binária completa utilizando um vetor!!!! ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 60/83 Dividir e Conquistar Heap: ● Vetor que apresenta as seguintes características: ● Vetor A de tamanho N (lenght(A) = nº de nodos da árvore) ● A[1] = raiz da árvore binária (primeira posição do vetor) ● Para calcular a posição de qualquer nodo, utilizamos as funções PARENT, LEFT E RIGHT: PARENT(i) return ⌊i/2⌋ LEFT(i) return 2i RIGHT(i) return 2i + 1 ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 61/83 Dividir e Conquistar ● Heap: (Cormen) IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 62/83 Dividir e Conquistar Heap: ● Característica que distingue um Heap de uma árvore binária : ● A[PARENT(i)] ≥ A[i] (Max-Heap) ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 63/83 Dividir e Conquistar ● Como utilizar um Heap para Ordenar???? ● ● ● O Heap permite que o elemento máximo do conjunto seja determinado e corretamente posicionado no vetor em tempo constante, trocando o primeiro elemento do heap com o último. O trecho restante do vetor (do índice 1 ao n −1), que pode ter deixado de ter a estrutura de heap, volte a tê-la com número de trocas de elementos proporcional à altura da árvore. O algoritmo Heapsort consiste então da construção de um heap com os elementos a serem ordenados, seguida de sucessivas trocas do primeiro com o último elemento e rearranjos do heap. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 64/83 Dividir e Conquistar ● HeapSort(A, n) - Pseudo-Código: IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 65/83 Dividir e Conquistar ● AjustaHeap(A, i, n) - Pseudo-Código: IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 66/83 Dividir e Conquistar Exemplo do Funcionamento de AjustaHeap(A,2,10): ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 67/83 Dividir e Conquistar Exemplo do Funcionamento de AjustaHeap(A,2,10): ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 68/83 Dividir e Conquistar Exemplo do Funcionamento de AjustaHeap(A,2,10): ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 69/83 Dividir e Conquistar Complexidade do HeapSort: ● Quantas comparações e quantas trocas são executadas no pior caso na etapa de ordenação do algoritmo Heapsort? ● No pior caso, a função AjustaHeap efetua (h) comparações e trocas, onde h é a altura do heap que contém os elementos que resta ordenar. ● Como o heap representa uma árvore binária completa, então h ∈ Θ(log i ), onde i é o número de elementos do heap. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 70/83 Dividir e Conquistar Complexidade do HeapSort: ● Logo, a complexidade da etapa de ordenação do Heapsort é: ● ● ● Portanto, no pior caso, a etapa de ordenação efetua O(n log n) comparações e trocas! Mas e a construção do Heap???? IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 71/83 Dividir e Conquistar ● ConstroiHeap()\ Se o trecho de 1 a i do vetor tem estrutura de Heap, é fácil adicionar a folha i + 1 ao Heap e em seguida rearranjá-lo,garantindo que o trecho de 1 a i + 1 tem estrutura de Heap. ● Esta é a abordagem top-down para construção do Heap. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 72/83 Dividir e Conquistar ● ConstroiHeap(A, n) – Pseudo-Código (Top-Down): IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 73/83 Dividir e Conquistar ConstroiHeap(A, n) – (Top-Down): ● Quantas comparações e quantas trocas são executadas no pior caso na construção do heap pela abordagem top-down ? ● O rearranjo do heap na iteração i efetua (h) comparações e trocas no pior caso, onde h é a altura da árvore representada pelo trecho do Heap de 1 a i . Logo, h ∈ Θ(log i ). ● Portanto, o número de comparações e trocas efetuadas construção do Heap por esta abordagem é: ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 74/83 Dividir e Conquistar Então, o algoritmo Heapsort efetua ao todo Θ (n log n) comparações e trocas no pior caso. ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 75/83 Dividir e Conquistar Então, o algoritmo Heapsort efetua ao todo Θ (n log n) comparações e trocas no pior caso. ●(Bem....sendo mais preciso, executa 2 n log n comparações e trocas......) ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 76/83 Dividir e Conquistar Então, o algoritmo Heapsort efetua ao todo Θ (n log n) comparações e trocas no pior caso. ●(Bem....sendo mais preciso, executa 2 n log n comparações e trocas......) ●Mas existe maneira mais eficiente de construir um Heap? ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 77/83 Dividir e Conquistar ● ● ● ● ● ● Suponha que o trecho de i a n do vetor é tal que, para todo j , i ≤ j ≤ n, a subárvore de raiz j representada por esse trecho do vetor tem estrutura de heap. Note que, em particular, o trecho de ⌊n/2⌋ + 1 a n do vetor satisfaz a propriedade, pois inclui apenas folhas da árvore binária de n elementos. Podemos então executar AjustaHeap(A, i − 1, n), garantindo assim que o trecho de i − 1 a n satisfaz a propriedade. Esta é a abordagem bottom-up para construção do Heap. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 78/83 Dividir e Conquistar ● ConstroiHeap(A, n) – Pseudo-Código Alternativo...: IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 79/83 Dividir e Conquistar ● ConstroiHeap(A, 6) – Exemplo: A=[2,9,7,6,5,8] IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 80/83 Dividir e Conquistar ● ConstroiHeap – Complexidade: ● ● ● ● Quantas comparações e quantas trocas são executadas no pior caso na construção do Heap pela abordagem bottom-up ? O(n lo g n )! Mas é possível provar matematicamente que este pior caso é O(n).... utilizando o conhecimento sobre a “altura” de cada sub-árvore aonde se executa o AjustaHeap(). Ainda assim, o algoritmo HeapSort() continua sendo Θ(n lo g n ) IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 81/83 Dividir e Conquistar Parte Prática: ● Implementar os algoritmos “MergeSort”, “QuickSort” e “HeapSort” apresentados, rodar uma “batelada” de testes para medir os tempos de execução e a quantidade de comparações executada por cada algoritmo, comparando os resultados! ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 82/83 Dividir e Conquistar - Conclusão: ● ● Estes slides são baseados no material disponibilizado pelos profs. Cid Carvalho de Souza e Cândida Nunes da Silva, da UNICAMP. Qualquer incorretude é, entretanto, de inteira responsabilidade do prof. João Alberto Fabro, da UTFPR. IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 83/83 Dividir e Conquistar - Prós e Contras: ● Prós: ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 84/83 Dividir e Conquistar - Prós e Contras: ● Contras: ● IF64C – Estruturas de Dados 2 – Engenharia da Computação – Prof. João Alberto Fabro - Slide 85/83