11

Tengo una colección de elementos (big racionales) que voy a procesar. En cada caso, el procesamiento consistirá en eliminar el elemento más pequeño de la colección, hacer algún trabajo y luego agregar de 0 a 2 elementos nuevos (que siempre será más grande que el elemento eliminado). La colección se inicializará con un elemento y el trabajo continuará hasta que esté vacío. No estoy seguro de qué tamaño alcanzará la colección, pero esperaría en el rango de 1M a 100M elementos. No necesitaré ubicar ningún artículo que no sea el más pequeño.¿Es un árbol rojo-negro mi estructura de datos ideal?

Actualmente estoy planeando utilizar un árbol rojo-negro, posiblemente ajustado para mantener un puntero al elemento más pequeño. Sin embargo, nunca he usado uno antes, y no estoy seguro si mi patrón de uso se adapta bien a sus características.

1) ¿Existe algún peligro de que el patrón de eliminación desde la izquierda + inserción aleatoria afecte el rendimiento, por ejemplo, requiriendo un número de rotaciones significativamente mayor que la eliminación aleatoria? ¿O las operaciones de eliminación e inserción seguirán siendo O (log n) con este patrón de uso?

2) ¿Alguna otra estructura de datos me daría un mejor rendimiento, ya sea por el patrón de eliminación o aprovechando el hecho de que solo tengo que encontrar el artículo más pequeño?

Actualización: me alegro de haber preguntado, el montón binario es claramente una mejor solución para este caso, y como prometió resultó ser muy fácil de implementar.

Hugo

+0

A menos que sepa con certeza que los nodos que se deben eliminar lógicamente no serán necesarios para los valores recién calculados, es posible que desee ignorar o retrasar las eliminaciones. Un enfoque Halt & Sweep debería funcionar para este último, donde las raíces de los subárboles que se han vuelto demasiado desordenadas son visitadas por el código de reequilibrio para reequilibrar en'masse. Esto evita la degeneración bruta, a la vez que ofrece la perspectiva probable de un rendimiento sin eliminación. – RocketRoy

Respuesta

12

A binary heap es mucho mejor para lo que quiere. Es más fácil de implementar y más rápido ya que solo te importa ubicar el elemento más pequeño y las inserciones. Ubicar el elemento más pequeño es O (1), eliminarlo es O (log N) y una inserción también es O (log N).

+0

en realidad, si sabe que siempre está insertando un artículo más grande que el eliminado, un montón binario (treap) terminará siendo muy desequilibrado en un punto. 100M registros es mucho, por lo que se puede desequilibrar lo suficiente como para que ya no sea O (log (n)), sino más bien O (n) - por ejemplo, si la altura del tratamiento terminó siendo 160k cuando n = 100M, entonces eso es O (n/((lgn)^2)) – Etai

+0

@Etai - un montón binario es siempre 'O (log N)' para las operaciones que he mencionado. No sé por qué mencionaste las trampas, mi respuesta se refiere a montones binarios, no a trampas. Los montones sí juegan un papel en la estructura de las trampas, pero las dos son estructuras de datos diferentes. – IVlad

+0

La inserción del montón binario es 'O (1)' promedio (el peor caso para Brodal), y esa es la principal razón para usarlo en BST: http://stackoverflow.com/a/29548834/895245 –

5

Un montón le dará O (1) O (log n) la eliminación y O (log n) de inserción, y es mucho más fácil de implementar que un árbol rojo-negro

+3

En realidad, la eliminación es O (log N) ** ubicación (encontrar el valor de) ** el mínimo/máximo es O (1). – IVlad

+0

Nunca he visto un montón con 1M-100M elementos, ¿alguien tiene alguna información sobre cómo afecta eso a su velocidad? –

+3

@NickLarsen: para eso es exactamente la notación Big-O. –

1

Es bueno saber cómo crear las estructuras de datos más complicadas si es necesario. Sin embargo, en general, su mejor opción es comenzar lo más simple que pueda, y solo use algo más complejo cuando resulte necesario.

La única vez que implementé un árbol de autoequilibrado fue una vez cuando supe que mi árbol iba a ser muy grande (más de 10.000 elementos), y los datos iban a venir en chorros ordenados. Eso significaba que si hubiera usado un árbol binario normal, habría terminado con casi una lista enlazada.

Si sus datos se ingresan en orden aleatorio, realmente no debería molestarse con un algoritmo de balanceo.

+0

Estoy de acuerdo en general con KISS primero, y complejo solo si es necesario. Hay muchas maneras de evitar el requisito de autoequilibrio, como crear un índice para leer datos en orden aleatorio, pero la advertencia es que esto solo funciona si conoce el requisito. IE: no para uso general, como en la creación de una biblioteca. También es una etiqueta muy mala dejar esta tarea para un pobre bastardo que tiene que mantener tu código más tarde. Dicho esto, generalmente estoy de acuerdo con tu filosofía. – RocketRoy

Cuestiones relacionadas