Universidade Estadual de Campinas Faculdade de Tecnologia ST 364 – Estruturas de Dados GRUPO 04 MERGESORT Alunos: André Pereira Giacon Dandara Contieri Folis Diego Narciso Hernandes Fernanda Cristina Spadotim Ordenação Ordenação é o ato de se colocar os elementos de uma sequência de informações, ou dados, em uma relação de ordem predefinida. O termo técnico em inglês para ordenação é sorting, cuja tradução literal é "classificação". Algumas ordens são facilmente definidas. Por exemplo, a ordem numérica, ou a ordem alfabética – crescentes ou decrescentes. Contudo, existem ordens, especialmente de dados compostos, que podem ser não triviais de se estabelecer. Um algoritmo que ordena um conjunto, geralmente representada num vetor, é chamado de algoritmo de ordenação. Algoritmo de ordenação: existem várias razões para se ordenar uma sequência. Uma delas é a possibilidade de acessar seus dados de modo mais eficiente. Entre os mais importantes, podemos citar bubble sort (ou ordenação por flutuação), heap sort (ou ordenação por heap), insertion sort (ou ordenação por inserção), merge sort (ou ordenação por mistura) e o quicksort. Existem diversos outros, que o aluno pode com dedicação pesquisar por si. Métodos de ordenação de vetores Métodos simples Insertion sort Selection sort Bubble sort Métodos sofisticados Quick sort Merge sort Heapsort Shell sort Radix sort Gnome sort Count sort Bogosort Bucket sort Cocktail sort Métodos de pesquisa Pesquisa binária Busca linear BogoBusca Introdução ao MergeSort História Ainda existe uma discussão sobre o assunto, mas apareceram evidências de que o algoritmo foi proposto por John Von Neumann em 1945. Essa discussão existe, pois estudar as várias contribuições que ele fez é, ao mesmo tempo, complexa e fascinante. Essa complexidade devesse em parte a existência de muitas fontes de informação, algumas pouco acessíveis, outras discordantes entre si ou polêmicas. A atribuição a ele veio de Knuth, que argumentou no seu livro ‘Arte de Programação Computacional: Ordenando e Procurando’ que Von Neumann foi o primeiro a descrever a idéia. Significado do MergeSort Nós vimos que o Quicksort é baseado em selecionar um elemento e dividir a lista em duas metades e então, ordenar-las separadamente. Há também um processo complementar o qual é chamado de junção. Dando 2 listas as quais estão ordenadas, combinando-as em uma lista ordenada maior. O processo de Seleção e junção são complementares porque: Seleção: divide a lista em 2 outras independentes. Junção: une 2 listas independentes em uma lista maior ordenada. Isso insinua que o Mergesort consiste em duas chamadas recursivas e um processo de junção. Então, Mergesort é um algoritmo recursivo, que é implementado dividindo uma sequência original em pares de dados, ordena-as e depois as agrupa em sequências de quatro elementos, e assim por diante, até ter toda a sequência dividida em apenas duas partes. Assim, sua idéia básica é que é muito fácil criar uma sequência ordenada a partir de duas outras também ordenadas. Classificação - Ordenação por partição O Mergesort é classificado como ordenação por partição, que parte do princípio de "dividir para conquistar". Este princípio é uma técnica que foi utilizada pela primeira vez por Anatolii Karatsuba em 1960 e consiste em dividir um problema maior em problemas pequenos, e sucessivamente até que o mesmo seja resolvido diretamente. Esta técnica realiza-se em três fases: Divisão: o problema maior é dividido em problemas menores e os problemas menores obtidos são novamente divididos sucessivamente de maneira recursiva. Conquista: o resultado do problema é calculado quando o problema é pequeno o suficiente. Combinação: os resultados dos problemas menores são combinados até que seja obtida a solução do problema maior. Algoritmos que utilizam o método de partição são caracterizados por serem os mais rápidos dentre os outros algoritmos pelo fato de sua complexidade ser, na maioria das situações, O(nlogn). Os dois representantes mais ilustres desta classe são o quicksort e o mergesort. - Não é um método in-place Em ciência da computação, um algoritmo in-place é um algoritmo que transforma a entrada de informação usando Estrutura de Dados com uma pequena e constante quantidade de espaço de memória extra. A entrada de informação geralmente é sobrescrita por uma saída de dados como o algoritmo executa. Um algoritmo que não é in-place, no caso, do Merge Sort, é chamado de out-of-place. Aplicando Dividir para conquistar no MergeSort Dividir: dividir a lista em duas listas com cerca da metade do tamanho. Conquistar: dividir cada uma das duas sublistas recursivamente até que tenham tamanho um. Combinar: fundir as duas sublistas de volta em uma lista ordenada. Sendo estável na maioria de suas implementações, onde estas podem ser iterativas ou recursivas. Sua desvantagem é o fato de utilizar uma estrutura auxiliar, ocupando o dobro de memória. É interessante destacar suas características em cima do paradigma de "divisão para conquista": Dividir: se a seqüência tiver mais de um elemento, divida em duas partes. Conquistar: ordene cada subseqüência em separado usando mergesort. Combinar: junte as duas subseqüências em uma seqüência ordenada. A operação de fusão merge, do mergesort, é muito utilizada na busca online, aonde os dados chegam de blocos em blocos, são ordenados por qualquer método e depois fundidos pela mesma. No entanto, esta abordagem pode demandar muito tempo e espaço de armazenamento se os blocos recebidos forem pequenos em comparação com os dados ordenados. Figura 1: Funcionamento do algoritmo mergesort. Funcionamento do MergeSort Pseudocódigo Variáveis: n = número de elementos X = vetor para ordenação T = auxiliar na comparação A,B = vetores auxiliares m = auxiliar na divisão do vetor i, j = auxiliares na intercalação e divisão k = auxiliar na intercalação Complexidade Primeiramente vamos definir o que é melhor, médio e pior caso para o MergeSort. Melhor Caso – nunca é necessário trocar após comparações. Médio Caso – há necessidade de haver troca após comparações. Pior Caso – sempre é necessário trocar após comparações. Para o MergeSort não tem tanta importância se o vetor está no melhor, médio ou pior caso, porque para qualquer que seja o caso ele sempre terá a complexidade de ordem n*logn, como pode ser verificado na tabela abaixo: Melhor caso Médio caso Pior caso O(n log2 n) O(n log2 n) O(n log2 n) Isso é pelo motivo de que o MergeSort independentemente em que situação se encontra o vetor, ele sempre irá dividir e intercalar. Na prática, é difícil (senão impossível) prever com rigor o tempo de execução de um algoritmo ou programa. O tempo vai depender de varias constantes, como por exemplo, o tempo de processamento de cada computador, do algoritmo implementado. Desta maneira, nós não vamos apresentar aqui como é o calculo da análise de complexidade do MergeSort. Testes: Teste realizado por um aluno na Universidade Federal de Ouro Preto. Computador com as seguintes configurações: - Processador Pentium D 2.8 Ghz FSB 800 Mhz; - 1 GB de memória ram DDR 533 Mhz; - Placa Mãe Asus P5ND2; - Sistema Operacional Microsoft Windows XP Service Pack 3. - Linguagem C++ - Software: Microsoft Visual Studio Express 2008. Métodos de ordenação: 1. BubbleSort 2. QuickSort 3. MergeSort Tipo de vetor: Vetor aleatório – Caso médio Quantidade de Comparações 100 1.000 10.000 100.000 BubbleSort 4.950 499.500 49.995.000 4.999.950.000 QuickSort 997 12.852 181.203 2.114.943 MergeSort 558 8.744 123.685 1.566.749 Quantidade de Movimentos 100 1.000 10.000 100.000 BubbleSort 2.628 242.827 25.160.491 2.499.136.980 QuickSort 570 8.136 103.575 1.310.586 MergeSort 1376 19968 272640 3385984 Tempo de execução (s) 100 1.000 10.000 100.000 BubbleSort 0,00007 0,0081 0,8587 114,8400 QuickSort 0,00003 0,0004 0,0049 0,0844 MergeSort 0,00015 0,0016 0,0194 0,2316 Vantagens e Desvantagens Vantagens: - Útil para ordenação externa; - Pior caso: O(n log2 n) - Aplicações com restrição de tempo - Fácil implementação Desvantagens: - Utiliza memória auxiliar - Alto consumo de memória Outras Informações • Eficiente para ordenar listas: Na literatura da ciência da computação está cheio de algoritmos de ordenação, e todas elas parecem funcionar em vetores. Bubblesort, Insertion Sort and Selection Sort são ruins; Shellsort é melhor, mas nada perto do limite teórico O(n log n); Quicksort é ótimo quando funciona, mas não confiável; Mergesort é confiável, mas requer O(n) espaço auxiliar; Heapsort is reliably good, but unstable, and also about a factor of 4 slower than Quicksort's best case. Mas e se quisermos ordenar algo mais do que um vetor? Árvores binárias já são todas pré-ordenadas, mas e as listas ligadas? Para isso, temos o MergeSort que funciona ainda melhor em listas ligadas em comparação que ele faz em matrizes. Isso evita a necessidade de um espaço auxiliar, e se torna um simples e confiável algoritmo de ordenação. E ainda como bônus, é muito estável. Descrição do Algoritmo MergeSort leva a lista de entrada e a trata como uma coleção de pequenas listas ordenadas. Faz log N, passa ao longo da lista, e em cada passagem, combina cada par adjacente de pequenas listas ordenadas em uma lista maior ordenada. Quando uma passagem só precisa fazer isso uma vez, toda lista de saída deve ser ordenada. Mais detalhadamente. Em cada passagem, estamos fazendo a fusão de listas de tamanho K em listas de tamanho 2K. (Inicialmente, K for igual a 1.) Assim, começamos por apontar um ponteiro temporário p no topo da lista, e também a preparar uma lista vazia L que vamos acrescentar elementos ao final enquanto terminamos de lidar com eles. Assim um passe de como este é realizado e é só preciso fazer uma mescla, o algoritmo termina, e da lista de saída L é ordenado. Caso contrário, o valor de K dobra, e voltar ao começo. Este procedimento utiliza apenas ligações para a frente, por isso não precisa de uma lista duplamente ligada. Se ele tem que lidar com uma lista duplamente ligada, o único lugar onde importa é quando adicionar outro item de L. Lidar com uma lista ligada circular também é possível. Você apenas tem que ter cuidado ao pisar ao longo da lista. Para lidar com a ambigüidade entre p == topo significa que você acabou de tirar o pé do final da lista, e p == topo significa que você apenas começou, eu costumo usar uma forma alternativa de a etapa "exploração: em primeiro lugar p passo para o elemento sucessor e, em seguida, redefini-lo para null se esse passo a que se tornasse igual à cabeça da lista. (Você pode rapidamente de-circularise uma lista ligada, encontrando o segundo elemento, e, em seguida, quebrar o link para ela do primeiro, mas este se move toda a lista por um round antes do processo de triagem. Isso não importa - estamos prestes a classificar a lista, depois de tudo - exceto que ela faz com que a sorte instável). • MergeSort possui ordenação estável Um algoritmo de ordenação diz-se estável se preserva a ordem de registros de chaves iguais. Isto é, se tais registros aparecem na sequência ordenada na mesma ordem em que estão na sequência inicial. Esta propriedade é útil apenas quando há dados associados às chaves de ordenação. Exemplo Por exemplo, um algoritmo estável ordenando a sequência de números (chaves) com letras associadas (registros): 3[a], 2[b], 2[c], 1[d] obrigatoriamente retornará: 1[d], 2[b], 2[c], 3[a] enquanto algoritmos instáveis sujeitam os elementos associados aos objetos a serem ordenados a mudanças: 1[d], 2[c], 2[b], 3[a] Implementação Certos algoritmos são estáveis a partir de sua concepção original, como o MergeSort. Porém, é possível implementar a estabilidade artificialmente em certos algoritmos. Por exemplo, numa comparação de dois objetos de mesmo valor pode aplicar-se uma comparação adicional para verificar se a ordem original dos registros associados foi mantida. Neste caso, a implementação de estabilidade requer um custo adicional de eficiência. Algoritmos estáveis Alguns algoritmos de ordenação estáveis: Bubble sort Cocktail sort Insertion sort Merge sort Bucket sort Counting sort Algoritmos instáveis Alguns algoritmos de ordenação instáveis: Quicksort Heapsort Selection sort Shell sort Referencias Bibliográficas BOSCARIOL, LEANDRO A.; GAMEIRO, LUCAS B.; ARRUDA, RODRIGO L. S. Algoritmos de Ordenação. Disponível em: < http://www2.dc.uel.br/~rlarruda/trab/algoritmos-ordenacao.pdf>. Acesso em: 01 de jun. de 2010. CAPPABIANCO, FÁBIO AUGUSTO MENOCCI. MC102, Aula 19 – MergeSort. Disponível em: <http://www.ic.unicamp.br/~fabioamc/mc102b/aulas/aula20.pdf >. Acesso em: 03 de jun. de 2010. JÚNIOR, ANTONIO CARLOS DE NAZARÉ. Algoritmos e Estruturas de Dados Métodos de ordenação Interna. Disponível em: < http://www.decom.ufop.br/menotti/aedI082/tps/tp3-sol1.pdf>. Acesso em: 30 de mai. de 2010.