En informática , un montón binomial sesgado (o cola binomial sesgada ) es una estructura de datos para operaciones de cola de prioridad . Es una variante del montón binomial que admite operaciones de inserción de tiempo constante en el peor de los casos, en lugar de tiempo amortizado .
Así como los montículos binomiales se basan en el sistema numérico binario , los montículos binarios sesgados se basan en el sistema numérico binario sesgado . [1] Los montículos binomiales ordinarios sufren de la complejidad logarítmica del peor caso para la inserción, porque una operación de acarreo puede caer en cascada, de manera análoga a la suma binaria. Los montículos binomiales sesgados se basan en el sistema numérico binario sesgado, donde el dígito n (indexado a cero) representa , en lugar de . Los dígitos son 0 o 1, excepto el dígito más bajo distinto de cero, que puede ser 2. Una ventaja de este sistema es que se necesita como máximo una operación de acarreo. Por ejemplo, 60 se representa como 11200 en binario sesgado (31 + 15 + 7 + 7), y sumar 1 produce 12000 (31 + 15 + 15). Dado que se garantiza que el siguiente dígito más alto no sea 2, se realiza un acarreo como máximo una vez. Esta analogía se aplica a la operación de inserción introduciendo enlaces ternarios (sesgados), que vinculan tres árboles entre sí. Esto permite que la operación de inserción se ejecute en tiempo constante.
Un montón binomial sesgado es un bosque de árboles binomiales sesgados , que se definen inductivamente:
Al realizar cualquier enlace, el árbol con la clave más pequeña siempre se convierte en la raíz. Además, imponemos la invariante de que solo puede haber un árbol de cada rango, excepto el rango más bajo que puede tener hasta dos.
El siguiente código OCaml demuestra las operaciones de vinculación:
tipo ' un montón = ' una lista de árbol y ' un árbol = Árbol de ' un * int * ' una lista de árbol sea rango ( Árbol (_, r , _)) = rsea simple_link ( Árbol ( k1 , r , c1 ) como t1 ) ( Árbol ( k2 , r , c2 ) como t2 ) = si k1 <= k2 entonces Árbol ( k1 , r + 1 , t2 :: c1 ) de lo contrario Árbol ( k2 , r + 1 , t1 :: c2 ) sea skew_link k1 ( Árbol ( k2 , r , c2 ) como t2 ) ( Árbol ( k3 , r , c3 ) como t3 ) = si k1 <= k2 && k1 <= k3 entonces (* tipo A *) Árbol ( k1 , r + 1 , [ t2 ; t3 ]) de lo contrario (* tipo B *) sea t1 = Árbol ( k1 , 0 , [] ) en si k2 <= k3 entonces Árbol ( k2 , r + 1 , t1 :: t3 :: c2 ) de lo contrario Árbol ( k3 , r + 1 , t1 :: t2 :: c3 )
A partir de estas propiedades, se puede deducir que la raíz de un árbol binomial de rango oblicuo tiene hasta hijos. El número de nodos en un árbol binomial de rango oblicuo también está limitado por . Dado que los árboles del mismo rango pueden tener diferentes números de nodos, puede haber más de una forma de distribuir los rangos en el montón.
Estas construcciones pueden considerarse una generalización de los árboles binarios y binomiales. Un árbol binomial oblicuo construido utilizando únicamente enlaces simples es un árbol binomial ordinario, y el uso exclusivo de enlaces oblicuo de tipo A da como resultado un árbol binario perfectamente equilibrado.
Busque en la lista de raíces el nodo que contiene la clave mínima. Esto lleva tiempo.
En una configuración imperativa, se puede mantener un puntero a la raíz que contenga la clave mínima, lo que permite el acceso en el tiempo. Este puntero debe actualizarse después de cada operación, lo que solo agrega una sobrecarga constante en la complejidad temporal.
En un entorno funcional sin acceso aleatorio a los nodos, se puede representar el montón como un árbol único con árboles binomiales sesgados como sus hijos. La raíz de este árbol es el mínimo del montón, lo que permite el acceso. Tenga en cuenta que este árbol no será necesariamente un árbol binomial sesgado en sí mismo. Las demás operaciones deben modificarse para tratar con este árbol único. Este concepto de raíz global se utiliza en las optimizaciones que se describen a continuación, aunque de forma ligeramente diferente.
Para fusionar dos montones binomiales sesgados, primero elimine cualquier árbol de rango duplicado en cada montón mediante la realización de enlaces simples . Luego, fusione los montones de la misma manera que los montones binomiales ordinarios, que es similar a la adición binaria. Los árboles con los mismos rangos se vinculan con un enlace simple y se pasa un árbol de "acarreo" hacia arriba si es necesario. Debido a que el rango de los árboles en cada montón ahora es único, se consideran como máximo tres árboles del mismo rango, lo que es suficiente para establecer un límite.
deje que rec unique = function | t1 :: t2 :: ts cuando rango t1 = rango t2 -> unique ( simple_link t1 t2 :: ts ) | ts -> tsdeje que rec merge_uniq h1 h2 = coincida con h1 , h2 con | h1 , [] -> h1 | [] , h2 -> h2 | t1 :: ts1 , t2 :: ts2 -> si rango t1 < rango t2 entonces t1 :: merge_uniq ts1 h2 de lo contrario si rango t1 > rango t2 entonces t2 :: merge_uniq h1 ts2 de lo contrario único ( enlace_simple t1 t2 :: merge_uniq ts1 ts2 ) deje que h1 h2 se fusione = merge_uniq ( h1 único ) ( h2 único )
Cree un árbol binomial sesgado de rango 0 (un nodo singleton) que contenga la clave que se insertará. A continuación, se consideran los dos árboles más pequeños del montón:
Como se realiza hasta un enlace, esta operación se ejecuta en el peor de los casos , mejorando el montón binomial que se basa en el análisis amortizado para su límite, con un peor caso de .
deje que inserte k = función | t2 :: t3 :: ts cuando rango t2 = rango t3 -> skew_link k t2 t3 :: ts | ts -> Árbol ( k , 0 , [] ) :: ts
Encuentre y descarte el nodo que contiene la clave mínima. Este nodo debe ser la raíz de un árbol. Divida sus hijos en dos grupos, aquellos con rango 0 y aquellos con rango > 0. Tenga en cuenta que puede haber más de dos hijos con rango 0, debido a los enlaces sesgados . Los hijos cuyo rango > 0 forman un montón binomial sesgado válido, ya que ya están ordenados y no tienen duplicados. Fusionar estos hijos en el montón lleva tiempo. Luego, vuelva a insertar cada uno de los hijos de rango 0 en el montón a un costo de cada uno. El tiempo total requerido es .
Esta operación no se modifica con respecto a los montículos binomiales. Disminuir la clave de un nodo puede hacer que sea más pequeño que su padre. Intercámbielo repetidamente con su padre hasta que se cumpla la propiedad de montículo mínimo , a costa de una complejidad de tiempo. Esta operación requiere un puntero al nodo que contiene la clave en cuestión y es más fácil de realizar en una configuración imperativa.
Brodal y Okasaki demostraron cómo la complejidad temporal de la operación de fusión se puede reducir a , aplicando la técnica de "bootstrapping" de Buchsbaum y Tarjan . [2]
Sea el tipo de un montón binomial sesgado primitivo que contiene elementos de tipo . En lugar de la representación del bosque de árboles descrita anteriormente, mantenemos un solo árbol con una raíz global como mínimo.
Sea el tipo de un montón binomial sesgado con raíz
es decir, un par que contiene un elemento de tipo y un montón primitivo de montones enraizados.
Finalmente, definimos el tipo de un montón bootstrap encerrando los montones enraizados en un tipo de opción :
que permite el montón vacío.
Las operaciones en este montón de arranque se redefinen en consecuencia. En el siguiente código de OCaml, el símbolo primo '
indica operaciones para montones de arranque.
tipo ' a bootstrap = | Vacío | Raíz de ' a rootedsea find_min' ( Raíz ( k , h )) = kdeje que se fusionen' bh1 bh2 = coincida bh1 , bh2 con | _, Vacío -> bh1 | Vacío , _ -> bh2 | Raíz ( k1 , h1 ), Raíz ( k2 , h2 ) -> si k1 <= k2 entonces Raíz ( k1 , inserte bh2 h1 ) de lo contrario Raíz ( k2 , inserte bh1 h2 )deje que inserte' k h = fusionar' ( Raíz ( k , [] )) hdeje que delete_min' ( Root ( x , h )) = deje que Root ( y , h1 ) = find_min h en deje que h2 = delete_min h en Root ( y , merge h1 h2 )
La nueva operación de fusión utiliza únicamente operaciones de inserción en montones primitivos. Por lo tanto, se ejecuta en el tiempo. Esta técnica se puede aplicar a cualquier cola de prioridad con inserción en tiempo constante y fusión logarítmica.
Aquí se muestran las complejidades temporales [3] de varias estructuras de datos de montón. La abreviatura am. indica que la complejidad dada se amortiza, de lo contrario es una complejidad del peor caso. Para el significado de " O ( f )" y " Θ ( f )", consulte la notación Big O. Los nombres de las operaciones suponen un montón mínimo.