Algoritmo para mesclar duas matrizes classificadas com número mínimo de comparações

24

Dadas duas matrizes ordenadas a , b do tipo T com tamanho n e m . Estou procurando um algoritmo que mescla as duas matrizes em uma nova matriz (de tamanho máximo n + m).

Se você tem uma operação de comparação barata, isso é bastante simples. Apenas retire da matriz com o primeiro elemento mais baixo até que uma ou ambas as matrizes sejam atravessadas completamente e adicione os elementos restantes. Algo como este /programming/5958169/how-to-merge-two-sorted-arrays-into-a-sorted-array

No entanto, a situação muda ao comparar dois elementos, é muito mais caro do que copiar um elemento da matriz de origem para a matriz de destino . Por exemplo, você pode ter uma matriz de grandes números inteiros de precisão arbitrária, ou seqüências de caracteres, onde uma comparação pode ser bastante cara. Suponha que a criação de matrizes e cópia de elementos seja gratuita e a única coisa que custa é comparar elementos.

Nesse caso, você deseja mesclar as duas matrizes com um número mínimo de comparações de elementos . Aqui estão alguns exemplos em que você deve fazer muito melhor do que o algoritmo de mesclagem simples:

a = [1,2,3,4, ... 1000]
b = [1001,1002,1003,1004, ... 2000]

Ou

a = [1,2,3,4, ... 1000]
b = [0,100,200, ... 1000]

Existem alguns casos em que o algoritmo de mesclagem simples será ideal, como

a = [1,3,5,7,9,....,999]
b = [2,4,6,8,10,....,1000]

Portanto, o algoritmo idealmente deve degradar e executar no máximo n + m-1 comparações caso as matrizes sejam intercaladas ou, pelo menos, não sejam significativamente piores.

Uma coisa que deve funcionar muito bem para listas com uma grande diferença de tamanho seria usar a pesquisa binária para inserir os elementos da matriz menor na matriz maior. Mas isso não será degradado se as duas listas forem do mesmo tamanho e intercaladas.

A única coisa disponível para os elementos é uma função de pedido (total), portanto, qualquer esquema que torne as comparações mais baratas não é possível.

Alguma ideia?

Eu vim com essa parte em Scala . Eu acredito que é ótimo em relação ao número de comparações, mas está além da minha capacidade de provar isso. Pelo menos, é muito mais simples do que as coisas que encontrei na literatura.

E desde a postagem original, escrevi uma postagem no blog sobre como isso funciona.

Rüdiger Klaehn
fonte
2
Não há como fazer menos comparações do que no "algoritmo de mesclagem simples". Você pode tentar lidar com casos extremos como o primeiro que você mencionou, mas isso piorará o caso médio.
Mephy
5
@ Mephy: ilumine-nos e nos dê uma prova formal, por favor. Ou, se não puder, considere excluir (ou pelo menos refinar) seu comentário.
Doc Brown
4
@DocBrown, se eu tivesse uma prova formal, daria uma resposta, não um comentário. Enfim, é um problema linear bastante óbvio, porque tentar encontrar uma solução melhor que o linear precisaria de pelo menos tempo linear.
Mephy
4
@ Mephy: sugiro que você reserve um tempo para ler a resposta abaixo e pense duas vezes sobre o que escreveu.
Doc Brown
4
@Mephy A maioria das coisas óbvias ("você não pode multiplicar em menos de O (n ^ 2)", "se eu mudar a porta que escolhi, não melhorarei minhas chances de ganhar um preço" , "você pode classifique em menos de O (n log n) ", ..) está errado. Usar uma abordagem de pesquisa binária na lista mais curta, por exemplo, deve melhorar o caso médio.
Voo

Respostas:

31

O algoritmo normal de classificação de mesclagem - etapa de mesclagem normalmente aplica comparações n + m -1, em que uma lista é do tamanho n e a outra lista é do tamanho m. O uso desse algoritmo é a abordagem mais simples para combinar duas listas classificadas.

Se as comparações forem muito caras, você poderá fazer duas coisas - minimizar o número de comparações ou minimizar o custo das comparações.

Vamos nos concentrar na minimização do custo de comparação. Você e somente você pode decidir se os dados que você está comparando podem ser quantizados ou não. Se você pode quantizá-los, é uma forma de implementar um método hash, que está mantendo a ordem. Por exemplo, se seus dados são comparados por nome, então o primeiro tname, ... você pode levar o primeiro a Chars com o nome "Klaehn, Ruediger" e reduzir / quantizar seu elemento de dados para "Kl.Ru", se você o comparar para "Empacotador, O", você preserva a ordem "Pa.Th" - agora você pode aplicar um algoritmo de comparação mais barato, comparando os valores reduzidos. Mas se você encontrar outro "Kl.Ru", agora terá um valor próximo e poderá agora mudar para uma abordagem mais cara comparando esses elementos.

Se você pode extrair esse valor quantizado dos seus dados, mais rapidamente do que compará-lo, é a primeira coisa que faz, você compara o valor quantizado ou o hash primeiro. Lembre-se de que esse valor precisa ser calculado apenas uma vez, para que você possa calculá-lo ao criar o elemento de dados.

Eu também mencionei outra maneira, para minimizar suas comparações.

Dei uma olhada no livro clássico TAOCP - Volume 3 - Classificação e pesquisa (pp.197-207, seção 5.3.2), que tem 10 páginas completas sobre esse tópico. Encontrei duas referências a algoritmos que são mais rápidos que as comparações n + m-1.

Primeiro, há o algoritmo de mesclagem Hwang-Lin e o segundo, uma melhoria de Glenn K Manacher - ambos são citados pelo TAOCP e também um algoritmo de Christen, que se aproxima do limite inferior das comparações necessárias, em condições especiais no comprimento ne das listas.

O algoritmo de Manacher foi apresentado no Journal of the ACM Vol. 26 Número 3 nas páginas 434-440: "Melhorias significativas no algoritmo de mesclagem" Hwan-Lin "". a lista com m itens e a lista com n itens podem ter tamanhos diferentes, mas também devem ser odiadas pelo número de elementos que contêm m <= n

O algoritmo Hwang-Lin divide as listas para mesclar, além de listas menores e classifica as listas, comparando o primeiro elemento de cada sub-lista e para decidir se alguns elementos na sub-lista precisam ser comparados ou não. Se a primeira lista for menor que a segunda, a chance é alta de que elementos consecutivos da lista mais longa possam ser transferidos para a lista resultante sem comparação. Se o primeiro elemento do pequeno ist for maior que o primeiro elemento da lista maior dividida, todos os elementos na frente da sublist poderão ser copiados sem comparação.

Análise de caso médio do aloritmo de fusão de Hwang e Lin (Vega, Frieze, Santha) na Seção 2, você pode encontrar um pseudocódigo do algoritmo HL. O que é muito melhor que a minha descrição. E você pode ver por que há menos comparações - o algoritmo usa uma pesquisa binária, para encontrar o índice, onde inserir o elemento da lista mais curta.

Se as listas não forem intercaladas como no seu último exemplo, na maioria dos casos você deverá ter uma lista menor e outra maior. É quando o algoritmo HL começa a funcionar melhor.

thepacker
fonte
Obrigado, pelo seu comentário sobre isso - verifiquei minha resposta e descobri que Knuth gasta 10 páginas completas nesse tópico. E então peguei o JACM da estante de livros e olhei para mais adiante. Eu melhorarei minha resposta. - Não há necessidade de voto negativo. O algoritmo hash- (quantizador) é uma idéia simples, que pode ser aplicada em muitos conjuntos de dados - mas apenas o indivíduo que solicitou é o único a decidir se é ou não aplicável a seus dados.
thepacker
4
Depois que você melhorar sua resposta, todos que votaram com você novamente terão a chance de te votar novamente ;-) #
Doc Brown
+1 por observar que, se os tamanhos forem muito diferentes, a mesclagem padrão não é ideal.
Florian F
1

Suponha que as duas matrizes tenham elementos N e M, N ≥ M, e todos os elementos sejam diferentes.

Se a matriz classificada contiver um elemento x de N seguido por um elemento y de M ou vice-versa, então xey deverão ter sido comparados; caso contrário, não saberíamos em que ordem eles pertencem. (Não pode haver uma cadeia de outros elementos, digamos a, b, c, onde sabemos que x <a <b <c <y, por exemplo, porque não existem elementos entre x e y. Portanto, x e y devem ter sido comparados diretamente.

Se N> M, é possível ter uma matriz em que cada elemento de M seja precedido e seguido por um elemento de N, o que significa que são necessárias pelo menos 2 milhões de comparações - mesmo se você usar um algoritmo de classificação não determinístico que possa fazer um palpite perfeito de quais números comparar. (O que isso significa: suponha que você tenha N grande, M = 1. A pesquisa binária executa etapas O (log2 N); um algoritmo não determinístico poderia adivinhar entre quais dois elementos o elemento da segunda matriz pertence e fazer duas comparações com confirme a suposição).

gnasher729
fonte