Algoritmo para fusionar dos matrices ordenadas con un número mínimo de comparaciones

24

Dado son dos matrices ordenadas una , b de tipo T con el tamaño de n y m . Estoy buscando un algoritmo que combine las dos matrices en una nueva matriz (de tamaño máximo n + m).

Si tiene una operación de comparación barata, esto es bastante simple. Simplemente tome de la matriz con el primer elemento más bajo hasta que una o ambas matrices estén completamente atravesadas, luego agregue los elementos restantes. Algo como esto /programming/5958169/how-to-merge-two-sorted-arrays-into-a-sorted-array

Sin embargo, la situación cambia cuando comparar dos elementos es mucho más costoso que copiar un elemento de la matriz de origen a la matriz de destino . Por ejemplo, puede tener una gran variedad de enteros de precisión arbitraria, o cadenas, donde la comparación puede ser bastante costosa. Simplemente suponga que crear matrices y copiar elementos es gratuito, y lo único que cuesta es comparar elementos.

En este caso, desea fusionar las dos matrices con un número mínimo de comparaciones de elementos . Estos son algunos ejemplos en los que debería poder hacerlo mucho mejor que el algoritmo de fusión simple:

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

O

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

Hay algunos casos en los que el algoritmo de fusión simple será óptimo, como

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

Por lo tanto, el algoritmo idealmente debería degradarse con gracia y realizar un máximo de n + m-1 comparaciones en caso de que las matrices estén entrelazadas, o al menos no sean significativamente peores.

Una cosa que debería funcionar bastante bien para las listas con una gran diferencia de tamaño sería utilizar la búsqueda binaria para insertar los elementos de la matriz más pequeña en la matriz más grande. Pero eso no se degradará con gracia en caso de que ambas listas sean del mismo tamaño y estén intercaladas.

Lo único disponible para los elementos es una función de orden (total), por lo que no es posible ningún esquema que haga las comparaciones más baratas.

¿Algunas ideas?

Se me ocurrió esta parte en Scala . Creo que es óptimo con respecto al número de comparaciones, pero está más allá de mi capacidad de demostrarlo. Al menos es mucho más simple que las cosas que he encontrado en la literatura.

Y desde la publicación original, escribí una publicación de blog sobre cómo funciona esto.

Rüdiger Klaehn
fuente
2
No hay forma de hacer menos comparaciones que en el "algoritmo de fusión simple". Puede intentar manejar casos extremos como el primero que menciona, pero esto empeorará el caso promedio.
Mephy
55
@Mephy: ilumínanos y danos una prueba formal, por favor. O si no puede, considere eliminar (o al menos refinar) su comentario.
Doc Brown
44
@DocBrown si tuviera una prueba formal, daría una respuesta, no un comentario. De todos modos, es un problema lineal bastante obvio, porque tratar de encontrar una solución mejor que lineal necesitaría al menos tiempo lineal.
Mephy
44
@Mephy: le sugiero que se tome el tiempo de leer la respuesta a continuación y piense dos veces sobre lo que escribió.
Doc Brown
44
@Mephy La mayoría de las cosas que son obvias ("no puedes multiplicar en menos de O (n ^ 2)", "si cambio la puerta que elegí no mejoraré mis posibilidades de ganar un precio" , "puedes No ordenar en menos de O (n log n) ", ..) están equivocados. El uso de un enfoque de búsqueda binaria en la lista más corta, por ejemplo, podría mejorar el caso promedio.
Voo

Respuestas:

31

El algoritmo de clasificación de fusión normal: el paso de fusión con normalmente aplica n + m -1 comparaciones, donde una lista es de tamaño ny la otra lista es de tamaño m. El uso de este algoritmo es el enfoque más simple para combinar dos listas ordenadas.

Si las comparaciones son demasiado caras, podría hacer dos cosas: minimizar el número de comparaciones o minimizar el costo de las comparaciones.

Centrémonos en la minimización del costo de comparación. Usted y solo usted pueden decidir si los datos que están comparando pueden cuantificarse o no. Si puede cuantificarlos, que es una forma de implementar un método hash, que es mantener el orden. Por ejemplo, si sus datos se comparan por nombre, entonces el primer tname, ... puede tomar el primero a los caracteres del nombre "Klaehn, Ruediger" y reducir / cuantificar su elemento de datos a "Kl.Ru", si lo compara a "Packer, The" conserva el pedido "Pa.Th": ahora puede aplicar un algoritmo de comparación más barato, comparando los valores reducidos. Pero si encuentra otro "Kl.Ru", ahora tiene un valor cercano, y ahora puede cambiar a un enfoque más costoso al comparar estos elementos.

Si puede extraer este valor cuantificado de sus datos, más rápido que compararlo, esto es lo primero que debe hacer, primero compara el valor cuantificado o hash. Tenga en cuenta que este valor debe calcularse solo una vez, para que pueda calcularlo al crear el elemento de datos.

También mencioné otra forma, para minimizar sus comparaciones.

Eché un vistazo al clásico libro TAOCP- Volumen 3-Clasificación y búsqueda, (pp.197-207, sección 5.3.2) que tiene 10 páginas completas sobre este tema. Encontré dos referencias a algoritmos que son más rápidas que las comparaciones n + m-1.

Primero está el algoritmo de fusión de Hwang-Lin y el segundo una mejora de Glenn K Manacher: ambos son citados por TAOCP y Christen, que se acerca al límite inferior de las comparaciones necesarias, en condiciones especiales en la longitud ny m de las listas

El algoritmo de Manacher se presentó en Journal of the ACM Vol. 26 Número 3 en las páginas 434-440: "Mejoras significativas al algoritmo de fusión" Hwan-Lin ". la lista con m elementos y la lista con n elementos pueden ser de diferente longitud, pero también deben ordenarse por la cantidad de elementos que contienen m <= n

El algoritmo de Hwang-Lin divide las listas para fusionarse, aparte de listas más pequeñas y clasifica las listas comparando el primer elemento de cada sublista, y para decidir si algunos elementos de la sublista deben compararse o no. Si la primera lista es más pequeña que la segunda lista, entonces la probabilidad es alta de que los elementos consecutivos de la lista más larga se puedan transferir a la lista resultante sin comparación. Si el primer elemento de la ist pequeña es mayor que el primer elemento de la lista más grande dividida, todos los elementos delante de la sublista se pueden copiar sin comparación.

Análisis de casos promedio del aloritmo de fusión de Hwang y Lin (Vega, Frieze, Santha) en la Sección 2 puede encontrar un pseudocódigo del algoritmo HL. Lo cual es mucho mejor que mi descripción. Y puede ver por qué hay menos comparaciones: el algoritmo usa una búsqueda binaria, para encontrar el índice, dónde insertar el elemento de la lista más corta.

Si las listas no están entrelazadas como en su último ejemplo, en la mayoría de los casos debería tener una lista restante más pequeña y otra más grande. Esto es cuando el algoritmo HL comienza a funcionar mejor.

thepacker
fuente
Gracias por su comentario sobre esto: verifiqué mi respuesta y descubrí que Knuth pasaba 10 páginas completas sobre este tema. Y luego tomé The JACM de mi estantería y busqué más. Mejoraré mi respuesta. - No hay necesidad de downvoting. El algoritmo hash- (cuantificador) es una idea simple, que se puede aplicar en muchos conjuntos de datos, pero solo el tipo que preguntó es el único que decide si es aplicable a sus datos o no.
thepacker
44
Después de mejorar su respuesta, todos los que lo votaron negativamente tendrán la oportunidad de votarlo nuevamente ;-)
Doc Brown
+1 para señalar que si los tamaños son muy diferentes, entonces la combinación estándar no es óptima.
Florian F
1

Suponga que las dos matrices tienen elementos N y M, N ≥ M y que todos los elementos son diferentes.

Si la matriz ordenada contiene un elemento x de N seguido de un elemento y de M o viceversa, entonces x e y deben haberse comparado, de lo contrario no sabríamos en qué orden pertenecen. (No puede haber una cadena de otros elementos, digamos a, b, c, donde sabemos que x <a <b <c <y, por ejemplo, porque no hay elementos entre x e y. Así que x e y deben haber sido comparados directamente.

Si N> M, entonces es posible tener una matriz donde cada elemento de M esté precedido y seguido por un elemento de N, lo que significa que se necesitan al menos 2M comparaciones, incluso si utiliza un algoritmo de clasificación no determinista que puede hacer una suposición perfecta sobre qué números comparar. (Lo que eso significa: suponga que tiene N grande, M = 1. La búsqueda binaria toma O (log2 N) pasos; un algoritmo no determinista adivinaría a qué dos elementos pertenece un elemento de la segunda matriz y haría dos comparaciones con confirma la suposición).

gnasher729
fuente