¿La unión de cobertura es siempre tan rápida como dividir y conquistar?

8

Adams describe un algoritmo de divide y vencerás para encontrar la unión de dos conjuntos (representados como árboles de búsqueda binarios con equilibrio de peso). Luego describe un nuevo algoritmo de "unión de cobertura" que, según él, mejora con respecto al de dividir y conquistar. Sin embargo, no ofrece una prueba, ni siquiera una explicación real, de por qué debería serO(m+n), y mucho menos por qué debería ser más rápido que dividir y conquistar.

Blelloch, Ferizovic y Sun muestran que el algoritmo de divide y vencerás de Adams en realidad alcanza lo óptimo teóricamenteΘ(mlog(n/m+1)) dónde mn. Sin embargo, no abordan el algoritmo de unión de cobertura.

¿Es la unión de cobertura, de hecho, tan eficiente como dividir y conquistar? La parte menos obvia es la moldura interior. Parece, al menos superficialmente, duplicar el trabajo entre los subárboles izquierdo y derecho que la división completa comparte entre ellos. Quizás esto esté bien por alguna razón, pero no sé por qué.

Una investigación adicional: Haskell Data.Sety Data.Maputiliza variantes de intersección y diferencia de cobertura, así como la unión. No he encontrado ninguna discusión publicada de esos algoritmos en absoluto. Preguntas similares se aplican a estos también.

dfeuer
fuente

Respuestas:

3

Si bien aún no he visto ni producido un análisis teórico de los algoritmos de cobertura, sí tengo alguna evidencia empírica de que son peores que los algoritmos de dividir y conquistar para árboles binarios.

Comenzando con el código en el containerspaquete Haskell , optimicé el algoritmo de unión de cobertura aplicando manualmente la especialización del patrón de llamada para reducir la asignación intermedia. Esto mejoró su rendimiento en aproximadamente un 10%, dándole una oportunidad justa.

Comenzando con el código de divide y vencerás en Adams, optimicé el algoritmo de unión agregando casos especiales cuando cualquiera de las entradas es un singleton (el código de unión de cobertura optimiza un lado por lo tanto, y no está claro si el otro lado puede optimizarse similar).

Probé cada implementación usando una colección de puntos de referencia de operación de conjunto empaquetados containers. Dividir y conquistar era generalmente más rápido que el seto, a veces el doble de rápido. Cuando era más lento, solo lo era un poco.

Los puntos de referencia similares de otras operaciones de conjunto dieron resultados similares.


Especulación:

Los algoritmos de cobertura pueden ser útiles cuando se usan árboles con grandes factores de ramificación, que pueden ser más costosos de dividir recursivamente. También pueden ser útiles para pequeños subárboles, donde pueden ahorrar suficiente asignación para que valga la pena el trabajo extra.

dfeuer
fuente
¿Realmente cambiaste la implementación en Data.Setbase a estas observaciones?
Joachim Breitner
@JoachimBreitner, sí, lo hice. También utilicé el mismo enfoque para las nuevas utilidades de fusión segura, aunque caracterizar sus características de rendimiento precisas es seguramente demasiado difícil de molestar.
dfeuer