Eu sei que a pergunta não é muito específica.
Tudo o que quero é que alguém me diga como converter uma classificação de mesclagem normal em uma classificação de mesclagem no local (ou uma classificação de mesclagem com sobrecarga de espaço extra constante).
Tudo o que posso encontrar (na rede) são páginas dizendo "é muito complexo" ou "fora do escopo deste texto".
As únicas maneiras conhecidas de mesclar no local (sem espaço extra) são muito complexas para serem reduzidas a programas práticos. (tirada daqui )
Mesmo que seja muito complexo, qual é o conceito básico de como fazer a mesclagem se encaixar?
Respostas:
Knuth deixou isso como um exercício (Vol 3, 5.2.5). Existem classificações de mesclagem no local. Eles devem ser implementados com cuidado.
Primeiro, a mesclagem ingênua no local, como descrita aqui, não é a solução certa. Reduz o desempenho para O (N 2 ) .
A idéia é classificar parte da matriz enquanto usa o restante como área de trabalho para mesclagem.
Por exemplo, como a seguinte função de mesclagem.
Leva a matriz
xs
, as duas sub-matrizes ordenadas são representadas como intervalos[i, m)
e[j, n)
respectivamente. A área de trabalho começa emw
. Comparado com o algoritmo de mesclagem padrão fornecido na maioria dos livros, este troca o conteúdo entre a sub-matriz classificada e a área de trabalho. Como resultado, a área de trabalho anterior contém os elementos classificados mesclados, enquanto os elementos anteriores armazenados na área de trabalho são movidos para as duas sub-matrizes.No entanto, existem duas restrições que devem ser atendidas:
Com esse algoritmo de fusão definido, é fácil imaginar uma solução, que pode classificar metade da matriz; A próxima pergunta é: como lidar com o restante da peça não classificada armazenada na área de trabalho, como mostrado abaixo:
Uma idéia intuitiva é classificar recursivamente outra metade da área de trabalho, portanto, existem apenas 1/4 dos elementos ainda não classificados.
O ponto chave nesta fase é que devemos mesclar os elementos 1/4 classificados B com os elementos A classificados 1/2, mais cedo ou mais tarde.
A área de trabalho é deixada, que contém apenas 1/4 elementos, grande o suficiente para mesclar A e B? Infelizmente não é.
No entanto, a segunda restrição mencionada acima nos dá uma dica, de que podemos explorá-la organizando a área de trabalho para se sobrepor a qualquer sub-matriz, se pudermos garantir a sequência de mesclagem de que os elementos não imersos não serão substituídos.
Na verdade, em vez de classificar a segunda metade da área de trabalho, podemos classificar a primeira metade e colocar a área de trabalho entre as duas matrizes classificadas da seguinte forma:
Essa configuração organiza efetivamente a sobreposição da área de trabalho com o subconjunto A. Essa idéia é proposta em [Jyrki Katajainen, Tomi Pasanen, Jukka Teuhola. `` Combinação prática no local ''. Nordic Journal of Computing, 1996].
Portanto, a única coisa que resta é repetir o passo acima, o que reduz a área de trabalho de 1/2, 1/4, 1/8,… Quando a área de trabalho se torna pequena o suficiente (por exemplo, apenas dois elementos restantes), podemos alterne para uma classificação de inserção trivial para finalizar esse algoritmo.
Aqui está a implementação no ANSI C com base neste documento.
Onde wmerge é definido anteriormente.
O código fonte completo pode ser encontrado aqui e a explicação detalhada pode ser encontrada aqui
A propósito, esta versão não é a classificação de mesclagem mais rápida, porque precisa de mais operações de troca. De acordo com o meu teste, é mais rápido que a versão padrão, que aloca espaços extras em cada recursão. Mas é mais lento que a versão otimizada, que dobra a matriz original com antecedência e a utiliza para mesclagem adicional.
fonte
Knuth left this as an exercise (Vol 3, 5.2.5).
refere-se a ex. 13. [40] Implemente o método de classificação interno sugerido [no final desta seção], produzindo que classifique dados aleatórios em O (N) unidades de tempo com apenas O (sqrt (N)) locais de memória adicionais. ? ( 40 indicando um problema muito difícil ou demorado que talvez seja adequado como um projeto de longo prazo em situações de sala de aula. )Incluindo seu "grande resultado", este documento descreve algumas variantes da classificação de mesclagem no local (PDF):
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.22.5514&rep=rep1&type=pdf
Classificação no local com menos movimentos
Tomi A. Pasanen, Jyrki Katajainen
Eu acho que isso é relevante também. Tenho uma cópia impressa por aí, passada por um colega, mas não a li. Parece cobrir a teoria básica, mas não estou familiarizado o suficiente com o tópico para julgar o quão abrangente:
http://comjnl.oxfordjournals.org/cgi/content/abstract/38/8/681
Mesclagem estável ideal
Antonios Symvonis
fonte
Realmente não é fácil ou eficiente, e sugiro que você não faça isso a menos que realmente precise (e provavelmente não precisará, a menos que seja um dever de casa, pois os aplicativos de mesclagem no local são principalmente teóricos). Você não pode usar o quicksort? O Quicksort será mais rápido de qualquer maneira com algumas otimizações mais simples e sua memória extra é O (log N) .
Enfim, se você deve fazer isso, então você deve. Aqui está o que eu encontrei: um e dois . Não estou familiarizado com a classificação de mesclagem no local, mas parece que a idéia básica é usar rotações para facilitar a mesclagem de duas matrizes sem o uso de memória extra.
Observe que isso é mais lento mesmo que a classificação de mesclagem clássica que não está no local.
fonte
A etapa crítica é fazer com que a mesclagem seja implementada. Não é tão difícil quanto essas fontes descobrem, mas você perde algo quando tenta.
Observando uma etapa da mesclagem:
Sabemos que a ordenada seqüência é menor do que tudo o resto, que x é menor do que tudo o resto na A , e que y é menor do que tudo o resto em B . No caso em que x é menor ou igual a y , basta mover o ponteiro para o início de A em um. No caso em que y é menor que x , você deve embaralhar y além de A para classificar . Esse último passo é o que torna isso caro (exceto em casos degenerados).
Geralmente é mais barato (especialmente quando as matrizes contêm apenas palavras únicas por elemento, por exemplo, um ponteiro para uma sequência ou estrutura) para trocar algum espaço por tempo e ter uma matriz temporária separada que você alterna entre elas.
fonte
Apenas para referência, aqui está uma boa implementação de uma classificação de mesclagem no local estável . Complicado, mas não tão ruim.
Acabei implementando uma classificação de mesclagem no local estável e uma classificação rápida no local estável em Java. Observe que a complexidade é O (n (log n) ^ 2)
fonte
Um exemplo de fusão sem buffer em C.
Um exemplo de fusão adaptativa (otimizada).
Adiciona código de suporte e modificações para acelerar a mesclagem quando um buffer auxiliar de qualquer tamanho está disponível (ainda funciona sem memória adicional). Usa mesclagem para frente e para trás, rotação de anel, mesclagem e classificação de pequenas seqüências e mesclagem iterativa.
fonte
Esta resposta possui um exemplo de código , que implementa o algoritmo descrito no artigo Mesclagem prática no local de Bing-Chao Huang e Michael A. Langston. Devo admitir que não entendo os detalhes, mas a complexidade dada da etapa de mesclagem é O (n).
De uma perspectiva prática, há evidências de que implementações puras no local não estão apresentando um desempenho melhor nos cenários do mundo real. Por exemplo, o padrão C ++ define std :: inplace_merge , que é o nome que implica uma operação de mesclagem no local.
Supondo que as bibliotecas C ++ sejam tipicamente muito bem otimizadas, é interessante ver como elas são implementadas:
1) libstdc ++ (parte da base de códigos do GCC): std :: inplace_merge
A implementação delega para __inplace_merge , que evita o problema ao tentar alocar um buffer temporário:
Caso contrário, ele retornará a uma implementação ( __merge_without_buffer ), que não requer memória extra, mas não é mais executada no tempo O (n).
2) libc ++ (parte da base de códigos Clang): std :: inplace_merge
Parece semelhante. Ele delega para uma função , que também tenta alocar um buffer . Dependendo se ele possui elementos suficientes, ele escolherá a implementação. A função de fallback de memória constante é chamada __buffered_inplace_merge .
Talvez até o fallback ainda esteja no tempo O (n), mas o ponto é que eles não usam a implementação se houver memória temporária disponível.
Observe que o padrão C ++ oferece explicitamente às implementações a liberdade de escolher essa abordagem, diminuindo a complexidade necessária de O (n) para O (N log N):
Obviamente, isso não pode ser tomado como prova de que o espaço constante no local se mescla no tempo O (n) nunca deve ser usado. Por outro lado, se fosse mais rápido, as bibliotecas C ++ otimizadas provavelmente mudariam para esse tipo de implementação.
fonte
Esta é a minha versão C:
fonte
Há uma implementação relativamente simples da classificação de mesclagem no local usando a técnica original do Kronrod, mas com uma implementação mais simples. Um exemplo pictórico que ilustra essa técnica pode ser encontrado aqui: http://www.logiccoder.com/TheSortProblem/BestMergeInfo.htm .
Há também links para análises teóricas mais detalhadas do mesmo autor associado a este link.
fonte
Eu apenas tentei colocar o algoritmo de mesclagem no lugar para classificar no JAVA usando o algoritmo de classificação de inserção, seguindo as etapas a seguir.
1) Duas matrizes ordenadas estão disponíveis.
2) Compare os primeiros valores de cada matriz; e coloque o menor valor na primeira matriz.
3) Coloque o valor maior na segunda matriz usando a classificação por inserção (percorra da esquerda para a direita).
4) Compare novamente o segundo valor da primeira matriz e o primeiro valor da segunda matriz e faça o mesmo. Mas quando a troca acontece, há alguma pista para ignorar a comparação dos itens adicionais, mas é necessário apenas a troca.
Eu fiz alguma otimização aqui; para manter comparações menores na classificação de inserção.
A única desvantagem que encontrei com essas soluções é que ele precisa de uma troca maior de elementos da matriz na segunda matriz.
por exemplo)
Primeira___Array: 3, 7, 8, 9
Segunda matriz: 1, 2, 4, 5
Então 7, 8, 9 faz com que a segunda matriz troque (mova para a esquerda por um) todos os seus elementos um a cada vez para se colocar no último.
Portanto, a suposição aqui é trocar itens é insignificante comparar com a comparação de dois itens.
https://github.com/skanagavelu/algorithams/blob/master/src/sorting/MergeSort.java
fonte