Un árbol splay es un árbol de búsqueda binaria con la propiedad adicional de que los elementos accedidos recientemente se pueden volver a acceder rápidamente. Al igual que los árboles de búsqueda binaria autoequilibrados , un árbol splay realiza operaciones básicas como inserción, búsqueda y eliminación en un tiempo amortizado de O (log n ) . Para patrones de acceso aleatorios extraídos de una distribución aleatoria no uniforme, su tiempo amortizado puede ser más rápido que logarítmico, proporcional a la entropía del patrón de acceso. Para muchos patrones de operaciones no aleatorias, los árboles splay también pueden tener un tiempo mejor que logarítmico, sin requerir conocimiento previo del patrón. Según la conjetura de optimalidad dinámica no probada, su rendimiento en todos los patrones de acceso está dentro de un factor constante del mejor rendimiento posible que podría lograr cualquier otro árbol de búsqueda binaria autoajustable, incluso uno seleccionado para ajustarse a ese patrón. El árbol splay fue inventado por Daniel Sleator y Robert Tarjan en 1985. [ 1 ]
Todas las operaciones normales en un árbol de búsqueda binaria se combinan con una operación básica llamada splaying . El splaying del árbol para un elemento específico reorganiza el árbol de manera que dicho elemento se coloque en la raíz. Una forma de lograr esto con la operación de búsqueda básica es realizar primero una búsqueda estándar en el árbol binario para el elemento en cuestión y luego usar rotaciones de árbol de una manera específica para colocar el elemento en la raíz. Alternativamente, un algoritmo descendente puede combinar la búsqueda y la reorganización del árbol en una sola fase.
Ventajas
El buen rendimiento de un árbol splay depende de su capacidad de autooptimización, ya que los nodos de uso frecuente se acercan a la raíz, donde se puede acceder a ellos más rápidamente. La altura máxima, aunque improbable, es O( n ), con un promedio de O(log n ). Tener los nodos de uso frecuente cerca de la raíz representa una ventaja para muchas aplicaciones prácticas (véase también localidad de referencia ) y resulta especialmente útil para implementar cachés y algoritmos de recolección de basura .
Las ventajas incluyen:
- Rendimiento comparable: El rendimiento en el caso promedio es tan eficiente como el de otros árboles. [ 3 ]
- Bajo consumo de memoria : Los árboles Splay no necesitan almacenar ningún dato contable.
Desventajas
La desventaja más significativa de los árboles splay es que su altura puede ser lineal. [ 2 ] : 1 Por ejemplo, esto ocurrirá tras acceder a todos los n elementos en orden no decreciente. Dado que la altura del árbol corresponde al tiempo de acceso en el peor de los casos, esto significa que el coste real de una sola operación puede ser elevado. Sin embargo, el coste de acceso amortizado de este peor caso es logarítmico, O(log n ). Además, el coste de acceso esperado puede reducirse a O(log n ) mediante el uso de una variante aleatoria. [ 4 ]
La representación de los árboles splay puede cambiar incluso cuando se accede a ellos en modo de solo lectura (es decir, mediante operaciones de búsqueda ). Esto complica su uso en entornos multihilo. En concreto, se requiere una gestión adicional si se permite que varios hilos realicen operaciones de búsqueda simultáneamente. Esto también los hace inadecuados para su uso general en programación puramente funcional, aunque incluso en este ámbito pueden utilizarse de forma limitada para implementar colas de prioridad.
Finalmente, cuando el patrón de acceso es aleatorio, la sobrecarga adicional de dispersión añade un factor constante significativo al coste en comparación con alternativas menos dinámicas.
Operaciones
Separación
Cuando se accede a un nodo x , se realiza una operación de splay sobre x para moverlo a la raíz. Una operación de splay es una secuencia de pasos de splay , cada uno de los cuales acerca x a la raíz. Al realizar una operación de splay sobre el nodo de interés después de cada acceso, los nodos accedidos recientemente se mantienen cerca de la raíz y el árbol permanece aproximadamente equilibrado, lo que proporciona los límites de tiempo amortizados deseados.
Cada paso en particular depende de tres factores:
- Ya sea que x sea el hijo izquierdo o derecho de su nodo padre, p ,
- si p es la raíz o no, y si no lo es
- ya sea que p sea el hijo izquierdo o derecho de su padre, g (el abuelo de x ).
Existen tres tipos de pasos de ramificación, cada uno con dos variantes simétricas: levógira y dextrógira. Para mayor brevedad, solo se muestra una de estas dos variantes para cada tipo. (En los siguientes diagramas, los círculos indican nodos de interés y los triángulos indican subárboles de tamaño arbitrario). Los tres tipos de pasos de ramificación son:
Paso en zigzag: este paso se realiza cuando p es la raíz. El árbol se rota en la arista entre x y p . Los pasos en zigzag existen para abordar el problema de la paridad, se realizarán únicamente como último paso en una operación de dispersión y solo cuando x tenga una profundidad impar al comienzo de la operación.

Paso en zigzag: este paso se realiza cuando p no es la raíz y x y p son hijos derechos o hijos izquierdos. La imagen a continuación muestra el caso en que x y p son hijos izquierdos. El árbol se rota en la arista que une p con su padre g , y luego se rota en la arista que une x con p . Los pasos en zigzag son la única diferencia entre los árboles splay y el método de rotación a raíz introducido por Allen y Munro [ 5 ] antes de la introducción de los árboles splay.

Paso en zigzag: este paso se realiza cuando p no es la raíz y x es un hijo derecho y p es un hijo izquierdo o viceversa ( x es izquierdo, p es derecho). El árbol se rota en la arista entre p y x , y luego se rota en la arista resultante entre x y g .

Unirse
Dados dos árboles S y T tales que todos los elementos de S son menores que los elementos de T, se pueden utilizar los siguientes pasos para unirlos en un solo árbol:
- Despliega el elemento más grande en S. Ahora este elemento está en la raíz de S y tiene un hijo derecho nulo.
- Establezca el hijo derecho de la nueva raíz en T.
Dividir
Dado un árbol y un elemento x , devuelve dos árboles nuevos: uno que contenga todos los elementos menores o iguales a x y otro que contenga todos los elementos mayores que x . Esto se puede hacer de la siguiente manera:
- Splay x . Ahora está en la raíz, por lo que el árbol a su izquierda contiene todos los elementos menores que x y el árbol a su derecha contiene todos los elementos mayores que x .
- Separe el subárbol derecho del resto del árbol.
Inserción
Para insertar un valor x en un árbol splay:
- Inserta x como en un árbol de búsqueda binaria normal .
- Realiza una expansión en x .
Como resultado, el nodo x recién insertado se convierte en la raíz del árbol.
Alternativamente:
- Utilice la operación de división para dividir el árbol en el valor de x en dos subárboles: S y T.
- Crea un nuevo árbol en el que x sea la raíz, S sea su subárbol izquierdo y T su subárbol derecho.
Supresión
Para eliminar un nodo x , utilice el mismo método que con un árbol de búsqueda binaria:
- Si x tiene dos hijos:
- Intercambia su valor con el del nodo más a la derecha de su subárbol izquierdo (su predecesor en orden) o con el del nodo más a la izquierda de su subárbol derecho (su sucesor en orden).
- En su lugar, elimine ese nodo.
De esta forma, la eliminación se reduce al problema de eliminar un nodo con 0 o 1 hijo. A diferencia de un árbol de búsqueda binaria, en un árbol splay, después de la eliminación, desplazamos el padre del nodo eliminado a la parte superior del árbol.
Alternativamente:
- El nodo que se va a eliminar primero se expande, es decir, se lleva a la raíz del árbol y luego se elimina. Esto deja el árbol con dos subárboles.
- A continuación, los dos subárboles se unen mediante una operación de "unión".
Implementación y variantes
Como se mencionó anteriormente, el splaying se realiza durante una segunda pasada ascendente sobre la ruta de acceso de un nodo. Es posible registrar la ruta de acceso durante la primera pasada para usarla durante la segunda, pero esto requiere espacio adicional durante la operación de acceso. Otra alternativa es mantener un puntero padre en cada nodo, lo que evita la necesidad de espacio adicional durante las operaciones de acceso, pero puede reducir la eficiencia general del tiempo debido a la necesidad de actualizar dichos punteros. [ 1 ]
Otro método que se puede utilizar se basa en el argumento de que el árbol se puede reestructurar durante el recorrido de acceso en lugar de realizar una segunda pasada. Esta rutina de splaying descendente utiliza tres conjuntos de nodos: árbol izquierdo, árbol derecho y árbol central. Los dos primeros contienen todos los elementos del árbol original que se sabe que son menores o mayores que el elemento actual, respectivamente. El árbol central consta del subárbol con raíz en el nodo actual. Estos tres conjuntos se actualizan a lo largo del recorrido de acceso mientras se controlan las operaciones de splay. Otro método, el semisplaying, modifica el caso zig-zig para reducir la cantidad de reestructuración realizada en todas las operaciones. [ 1 ] [ 6 ]
A continuación se presenta una implementación de árboles splay en C++, que utiliza punteros para representar cada nodo del árbol. Esta implementación se basa en la versión de splay ascendente y utiliza el segundo método de eliminación en un árbol splay. Además, a diferencia de la definición anterior, esta versión en C++ no realiza el splay en las búsquedas, sino únicamente en las inserciones y eliminaciones; por lo tanto, la operación de búsqueda tiene una complejidad temporal lineal.
#include <functional>#ifndef SPLAY_TREE #define SPLAY_TREEplantilla < typename T , typename Comp = std :: less < T >> clase splay_tree { privado : Comp comp ; unsigned long p_size ; struct nodo { nodo * izquierda , * derecha ; nodo * padre ; T clave ; nodo ( const T & init = T ()) : izquierda ( nullptr ), derecha ( nullptr ), padre ( nullptr ), clave ( init ) { } ~ nodo () {} } * raíz ; void left_rotate ( nodo * x ) { nodo * y = x -> derecha ; if ( y ) { x -> derecha = y -> izquierda ; if ( y -> izquierda ) y -> izquierda -> padre = x ; y -> padre = x -> padre ; } if ( ! x -> padre ) raíz = y ; else if ( x == x -> padre -> izquierda ) x -> padre -> izquierda = y ; else x -> padre -> derecha = y ; if ( y ) y -> izquierda = x ; x -> padre = y ; } void right_rotate ( nodo * x ) { nodo * y = x -> izquierda ; if ( y ) { x -> izquierda = y -> derecha ; if ( y -> derecha ) y -> derecha -> padre = x ; y -> padre = x -> padre ; } if ( ! x -> padre ) raíz = y ; else if ( x == x -> padre -> izquierda ) x -> padre -> izquierda = y ; else x ->padre -> derecha = y ; si ( y ) y -> derecha = x ; x -> padre = y ; } void splay ( nodo * x ) { mientras ( x -> padre ) { si ( !x -> padre -> padre ) { if ( x -> padre -> izquierda == x ) rotación_derecha ( x -> padre ); else rotación_izquierda ( x -> padre ); } else if ( x -> padre -> izquierda == x && x -> padre -> padre -> izquierda == x -> padre ) { rotación_derecha ( x -> padre -> padre ); rotación_derecha ( x -> padre ); } else if ( x -> padre -> derecha == x && x -> padre -> padre -> derecha == x -> padre ) { rotación_izquierda ( x -> padre -> padre ); rotación_izquierda ( x -> padre ); } else if ( x -> padre -> izquierda == x && x -> padre -> padre -> derecha == x -> padre ) { rotación_derecha ( x -> padre ); rotación_izquierda ( x -> padre ); } else {left_rotate ( x -> parent ); right_rotate ( x -> parent ); } } } void replace ( node * u , node * v ) { if ( ! u -> parent ) root = v ; else if ( u == u -> parent -> left ) u -> parent -> left = v ; else u -> parent -> right = v ; if ( v ) v -> parent = u -> parent ; } node * subtree_minimum ( node * u ) { while ( u -> left ) u = u -> left ; return u ; } node * subtree_maximum ( node * u ) { while ( u -> right ) u = u -> right ; return u ; } public : splay_tree () : root ( nullptr ), p_size ( 0 ) { } void insert ( const T & key ) { node * z = root ; node * p = nullptr ; mientras ( z ) { p = z ; si ( comp ( z -> key , key )) z = z -> right ; de lo contrario z = z ->izquierda ; } z = nuevo nodo ( clave ); z -> padre = p ; si ( ! p ) raíz = z ; si no si ( comp ( p -> clave , z -> clave )) p -> derecha = z ; si no p -> izquierda = z ; splay ( z ); p_size ++ ; } nodo * encontrar ( const T & clave ) { nodo * z = raíz ; mientras ( z ) { si ( comp ( z -> clave , clave )) z = z -> derecha ; si no si ( comp ( clave , z -> clave )) z = z -> izquierda ; si no, devolver z ; } devolver nullptr ; } void borrar ( const T & clave ) { nodo * z = encontrar ( clave ); si ( ! z ) devolver ; splay ( z ); si ( ! z -> izquierda ) reemplazar ( z , z -> derecha ); si no si ( ! z -> derecha ) reemplazar ( z , z -> izquierda ); else { nodo * y = subárbol_mínimo ( z -> derecha ); si ( y ->padre != z ) { reemplazar ( y , y -> derecha ); y -> derecha = z -> derecha ; y -> derecha -> padre = y ; } reemplazar ( z , y ); y -> izquierda = z -> izquierda ; y -> izquierda -> padre = y ; } eliminar z ; p_size -- ; }/* //la implementación alternativa void erase(const T &key) { node *z = find(key); if (!z) return; splay(z); node *s = z->left; node *t = z->right; delete z; node *sMax = NULL; if (s) { s->parent = NULL; sMax = subtree_maximum(s); splay(sMax); root = sMax; } if (t) { if (s) sMax->right = t; else root = t; t->parent = sMax; } p_size--; } */ const T & minimum () { return subtree_minimum ( root ) -> key ; } const T & maximum () { return subtree_maximum ( root ) -> key ; } bool empty () const { return root == nullptr ; } unsigned long size () const { return p_size ; } };#endif // SPLAY_TREEAnálisis
Se puede realizar un análisis amortizado simple de árboles de dispersión estáticos utilizando el método potencial . Definir:
- tamaño( r ) = el número de nodos en el subárbol con raíz en el nodo r (incluido r ).
- rango( r ) = log 2 (tamaño( r )).
- Φ = la suma de los rangos de todos los nodos del árbol.
Φ tenderá a ser alto para árboles mal equilibrados y bajo para árboles bien equilibrados.
Para aplicar el método del potencial , primero calculamos ΔΦ: el cambio en el potencial causado por una operación de dispersión. Verificamos cada caso por separado. Denotamos por rango' la función de rango después de la operación. x, p y g son los nodos afectados por la operación de rotación (ver figuras anteriores).
Paso en zigzag
paso en zigzag
Paso en zigzag
El costo amortizado de cualquier operación es ΔΦ más el costo real. El costo real de cualquier operación en zigzag es 2, ya que hay dos rotaciones que realizar. Por lo tanto:
Cuando se suma sobre toda la operación de dispersión, esto se reduce a 1 + 3(rank(root)−rank( x )) que es O(log n ), ya que usamos la operación Zig como máximo una vez y el costo amortizado de zig es como máximo 1+3(rank'( x )−rank( x )).
Ahora sabemos que el tiempo total amortizado para una secuencia de m operaciones es:
Para pasar del tiempo amortizado al tiempo real, debemos sumar la disminución del potencial desde el estado inicial antes de que se realice cualquier operación (Φ i ) hasta el estado final después de que se hayan completado todas las operaciones (Φ f ).
donde la notación de la gran O se puede justificar por el hecho de que para cada nodo x , el rango mínimo es 0 y el rango máximo es log( n ).
Ahora por fin podemos delimitar el tiempo real:
Análisis ponderado
El análisis anterior puede generalizarse de la siguiente manera.
- Asigne a cada nodo r un peso w ( r ).
- Definimos size( r ) = la suma de los pesos de los nodos en el subárbol con raíz en el nodo r (incluido r ).
- Defina rank( r ) y Φ exactamente como se indicó anteriormente.
Se aplica el mismo análisis y el costo amortizado de una operación de expansión es nuevamente:
donde W es la suma de todos los pesos.
La disminución desde el potencial inicial hasta el final está limitada por:
ya que el tamaño máximo de cualquier nodo individual es W y el mínimo es w(x) .
Por lo tanto, el tiempo real está limitado por:
Teoremas de rendimiento
Existen varios teoremas y conjeturas con respecto al tiempo de ejecución en el peor de los casos para realizar una secuencia S de m accesos en un árbol splay que contiene n elementos.
Teorema del equilibrio : el costo de realizar la secuencia S es.
Toma un peso constante, por ejemplo para cada nodo x . Entonces .
Este teorema implica que los árboles splay se desempeñan tan bien como los árboles de búsqueda binaria balanceados estáticos en secuencias de al menos n accesos. [ 1 ]
Teorema de optimalidad estática — SeaSea el número de veces que se accede al elemento x en S. Si se accede a cada elemento al menos una vez, entonces el costo de realizar S es
Dejar. Entonces.
Este teorema implica que los árboles splay se desempeñan tan bien como un árbol de búsqueda binaria estática óptimo en secuencias de al menos n accesos. [ 7 ] Invierten menos tiempo en los elementos más frecuentes. [ 1 ] Otra forma de enunciar el mismo resultado es que, en secuencias de entrada donde los elementos se extraen independientemente al azar de una distribución de probabilidad no uniforme sobre n elementos, el costo esperado amortizado ( caso promedio ) de cada acceso es proporcional a la entropía de la distribución. [ 8 ]
Teorema del dedo estático : Supongamos que los elementos están numerados del 1 al n en orden ascendente. Sea f un elemento fijo cualquiera (el 'dedo'). Entonces, el costo de realizar S es.
Dejar. Entonces . La caída potencial neta es O ( n log n ) ya que el peso de cualquier artículo es al menos . [ 1 ]
Teorema del dedo dinámico : supongamos que el 'dedo' para cada paso que accede a un elemento y es el elemento al que se accedió en el paso anterior, x . El costo de realizar S es. [ 9 ] [ 10 ]
Teorema del conjunto de trabajo : En cualquier momento durante la secuencia, seasea el número de elementos distintos a los que se accedió antes de que se accediera al elemento de tiempo anterior x. El costo de realizar S es
Dejar. Nótese que aquí los pesos cambian durante la secuencia. Sin embargo, la secuencia de pesos sigue siendo una permutación de . Así que, como antes . La caída de potencial neta es O ( n log n ).
Este teorema es equivalente a que los árboles splay tengan optimalidad independiente de la clave . [ 1 ]
Teorema de escaneo — También conocido como teorema de acceso secuencial o teorema de cola . Acceder a los n elementos de un árbol splay en orden simétrico requiere un tiempo O ( n ), independientemente de la estructura inicial del árbol splay. [ 11 ] La cota superior más ajustada demostrada hasta ahora es. [ 12 ]
Conjetura de optimalidad dinámica
Además de las garantías de rendimiento comprobadas para los árboles splay, existe una conjetura no demostrada de gran interés proveniente del artículo original de Sleator y Tarjan. Esta conjetura se conoce como la conjetura de optimalidad dinámica y básicamente afirma que los árboles splay tienen un rendimiento tan bueno como cualquier otro algoritmo de árbol de búsqueda binaria, salvo por un factor constante.
- Conjetura de optimalidad dinámica: [ 1 ] Seacualquier algoritmo de árbol de búsqueda binaria que acceda a un elementorecorriendo el camino desde la raíz hastaa un costo dey que entre accesos puede realizar cualquier rotación en el árbol a un costo de 1 por rotación. Seaser el costo depara realizar la secuenciade accesos. Entonces, el costo para que un árbol splay realice los mismos accesos es.
Existen varios corolarios de la conjetura de optimalidad dinámica que aún no han sido demostrados:
- Conjetura de recorrido: [ 1 ] SeaySean dos árboles splay que contengan los mismos elementos.sea la secuencia obtenida al visitar los elementos enen preorden (es decir, orden de búsqueda en profundidad). El costo total de realizar la secuenciade accesos enes.
- Conjetura de Deque: [ 11 ] [ 13 ] [ 14 ] Seaser una secuencia deoperaciones de cola de doble extremo (push, pop, inject, eyec). Luego, el costo de realizaren un árbol ramificado es.
- Conjetura de división: [ 6 ] Seasea cualquier permutación de los elementos del árbol splay. Entonces, el costo de eliminar los elementos en el orden, dividiendo cada árbol en dos árboles separados en cada elemento eliminado, es.
Variantes
Para reducir el número de operaciones de reestructuración, es posible reemplazar el splaying con semi-splaying , en el que un elemento se splaya solo hasta la mitad hacia la raíz. [ 1 ] [ 2 ]
Otra forma de reducir la reestructuración es realizar una dispersión completa, pero solo en algunas de las operaciones de acceso: solo cuando la ruta de acceso sea más larga que un umbral, o solo en las primeras m operaciones de acceso. [ 1 ]
El CBTree aumenta el árbol splay con recuentos de acceso en cada nodo y los utiliza para reestructurarlo con poca frecuencia. Una variante del CBTree, llamada LazyCBTree, realiza como máximo una rotación en cada búsqueda. Esto se utiliza junto con un esquema de validación optimista de mano a mano para crear un árbol concurrente autoajustable. [ 15 ]
Utilizando técnicas de compresión de punteros, [ 16 ] es posible construir un árbol splay conciso .
Véase también
- Árbol AVL
- Árbol B
- Árbol de dedos
- Geometría de los árboles de búsqueda binaria
- Estructura del conjunto de trabajo de Iacono
- Árbol de enlace/corte
- Lista de estructuras de datos
- Árbol del chivo expiatorio
- Splaysort , un algoritmo de ordenación que utiliza árboles splay.
- Árbol en T
- Trepa
- rotación de árboles
- Árboles
- Cremallera (estructura de datos)
Notas
- ^ Sleator y Tarjan 1985 .
- ^ Brinkmann , Degraer y De Loof 2009 .
- ↑ Goodrich, Tamassia y Goldwasser 2014 .
- ↑ Albers y Karpinski 2002 .
- ↑ Allen y Munro 1978 .
- 1 2 Lucas 1991 .
- ↑ Knuth 1997 , pág. 478
- ↑ Grinberg et al. (1995) .
- ↑ Cole et al. 2000 .
- ↑ Cole 2000 .
- 1 2 Tarjan 1985 .
- ↑ Elmasry 2004 .
- ↑ Pettie 2008 .
- ↑ Sundar 1992 .
- ↑ Afek et al. 2014
- ↑ Bender et al. 2023 .
Referencias
- Afek, Yehuda; Kaplan, Haim; Korenfeld, Boris; Morrison, Adam; Tarjan, Robert E. (2014). "El árbol CB: un árbol de búsqueda práctico, concurrente y autoajustable" . Distributed Computing . 27 (6): 393– 417. doi : 10.1007/s00446-014-0229-0 .
- Albers, Susanne; Karpinski, Marek (28 de febrero de 2002). "Árboles de dispersión aleatorios: resultados teóricos y experimentales" (PDF) . Information Processing Letters . 81 (4): 213– 221. doi : 10.1016/s0020-0190(01)00230-7 .
- Bose, Prosenjit; Douïeb, Karim; Dujmović, Vida; Fagerberg, Rolf (2010). "Un árbol de búsqueda binaria competitivo O(log log n) con tiempos de acceso óptimos en el peor de los casos". En Kaplan, H. (ed.). Teoría de algoritmos - SWAT 2010. Notas de clase en ciencias de la computación. Vol. 6139. pp. 38–49 . arXiv : 1003.0139 . doi : 10.1007/978-3-642-13731-0_5 . ISBN 978-3-642-13730-3.
- Allen, Brian; Munro, Ian (octubre de 1978). "Árboles de búsqueda binaria autoorganizados" . Journal of the ACM . 25 (4): 526– 535. doi : 10.1145/322092.322094 . S2CID 15967344 .
- Brinkmann, Gunnar; Degraer, Jan; De Loof, Karel (enero de 2009). "Rehabilitación de un niño no querido: semi-splaying" (PDF) . Software: Practice and Experience . 39 (1): 33– 45. CiteSeerX 10.1.1.84.790 . doi : 10.1002/spe.v39:1 . hdl : 11382/102133 .
Los resultados muestran que el semi-splaying, que se introdujo en el mismo artículo que el splaying, funciona mejor que el splaying en casi todas las condiciones posibles. Esto hace que el semi-splaying sea una buena alternativa para todas las aplicaciones donde normalmente se aplicaría el splaying. La razón por la que el splaying se volvió tan prominente mientras que el semi-splaying es relativamente desconocido y mucho menos estudiado es difícil de entender.
- Cole, Richard; Mishra, Bud; Schmidt, Jeanette; Siegel, Alan (enero de 2000). "Sobre la conjetura del dedo dinámico para árboles splay. Parte I: Ordenación splay de secuencias de log n-bloques". SIAM Journal on Computing . 30 (1): 1– 43. CiteSeerX 10.1.1.36.4558 . doi : 10.1137/s0097539797326988 .
- Cole, Richard (enero de 2000). "Sobre la conjetura del dedo dinámico para árboles splay. Parte II: La demostración". SIAM Journal on Computing . 30 (1): 44– 85. CiteSeerX 10.1.1.36.2713 . doi : 10.1137/S009753979732699X .
- Elmasry, Amr (abril de 2004). "Sobre el teorema de acceso secuencial y la conjetura Deque para árboles splay" . Theoretical Computer Science . 314 (3): 459– 466. doi : 10.1016/j.tcs.2004.01.019 .
- Goodrich, Michael; Tamassia, Roberto; Goldwasser, Michael (2014). Estructuras de datos y algoritmos en Java (6.ª ed.). Wiley. pág. 506. ISBN 978-1-118-77133-4.
- Grinberg, Dennis; Rajagopalan, Sivaramakrishnan; Venkatesan, Ramarathnam; Wei, Victor K. (1995). "Árboles splay para compresión de datos" . En Clarkson, Kenneth L. (ed.). Actas del Sexto Simposio Anual ACM-SIAM sobre Algoritmos Discretos, 22-24 de enero de 1995. San Francisco, California, EE. UU . ACM/SIAM. págs. 522-530 .
La profundidad media de acceso en un árbol splay es proporcional a la entropía.
- Knuth, Donald (1997). El arte de la programación informática . Vol. 3: Ordenación y búsqueda (3.ª ed.). Addison-Wesley. pág. 478. ISBN 0-201-89685-0Se
sabe que el tiempo necesario para acceder a los datos en un árbol splay es, como máximo, un pequeño múltiplo constante del tiempo de acceso de un árbol estáticamente óptimo, cuando se amortiza sobre cualquier serie de operaciones.
- Lucas, Joan M. (1991). «Sobre la competitividad de los árboles splay: relaciones con el problema de unión-búsqueda». Algoritmos en línea: Actas de un taller de DIMACS, 11-13 de febrero de 1991. Serie de Matemáticas Discretas e Informática Teórica. Vol. 7. Centro de Matemáticas Discretas e Informática Teórica . págs. 95-124 . ISBN 0-8218-7111-0.
- Pettie, Seth (2008). "Árboles Splay, secuencias de Davenport-Schinzel y la conjetura de Deque". Actas del 19.º Simposio ACM-SIAM sobre algoritmos discretos (PDF) . págs. 1115–1124 . arXiv : 0707.2160 .
- Sleator, Daniel D. ; Tarjan, Robert E. (1985). "Árboles de búsqueda binaria autoajustables" (PDF) . Journal of the ACM . 32 (3): 652– 686. doi : 10.1145/3828.3835 . S2CID 1165848 .
- Sundar, Rajamani (1992). "Sobre la conjetura Deque para el algoritmo splay". Combinatorica . 12 (1): 95– 124. doi : 10.1007/BF01191208 . S2CID 27422556 .
- Tarjan, Robert E. (1985). "El acceso secuencial en árboles splay requiere tiempo lineal". Combinatorica . 5 (4): 367– 378. doi : 10.1007/BF02579253 . S2CID 34757821 .
- Bender, Michael A.; Conway, Alex; Farach-Colton, Martin; Kuszmaul, William; Tagliavini, Guido (2023). «Tiny Pointers». Actas del Simposio Anual ACM-SIAM de 2023 sobre Algoritmos Discretos (SODA) . págs. 477–508 . doi : 10.1137/1.9781611977554.ch21 . ISBN 978-1-61197-755-4. S2CID 244709005 .
Enlaces externos
- Diccionario de algoritmos y estructuras de datos del NIST: Árbol Splay
- Implementaciones en C y Java (por Daniel Sleator)
- Consejos para visualizaciones de árboles de dispersión
- Implementación rápida y eficiente de árboles Splay
- Implementación en Java de un árbol Splay descendente
- Árboles binarios
- Buscar árboles
- Estructuras de datos amortizadas