Puede mantener un árbol AVL sin clave o similar.
Funcionaría de la siguiente manera: el árbol mantiene un orden en los nodos tal como lo hace normalmente un árbol AVL, pero en lugar de que la clave determine dónde debe estar el nodo "," no hay claves, y debe insertar explícitamente los nodos "después "otro nodo (o en otras palabras" entre "dos nodos), donde" después "significa que viene después de él en el recorrido en orden del árbol. El árbol mantendrá así el orden para usted de forma natural, y también se equilibraría, debido a las rotaciones incorporadas del AVL. Esto mantendrá todo distribuido uniformemente de forma automática.
Inserción
Además de la inserción regular en la lista, como se demuestra en la pregunta, mantendría un árbol AVL separado. La inserción en la lista misma esO ( 1 ), ya que tiene los nodos "antes" y "después".
El tiempo de inserción en el árbol es O ( logn ), lo mismo que la inserción en un árbol AVL. La inserción implica tener una referencia al nodo que desea insertar después, y simplemente inserte el nuevo nodo a la izquierda del nodo más a la izquierda del hijo derecho; esta ubicación es "siguiente" en el orden del árbol (es la siguiente en el recorrido en orden). Luego haga las rotaciones AVL típicas para reequilibrar el árbol. Puede hacer una operación similar para "insertar antes"; Esto es útil cuando necesita insertar algo al comienzo de la lista, y no hay un nodo "antes".
Respondiendo consultas
Para responder consultas de ( X<?Y), simplemente encuentras a todos los antepasados de X y Yen el árbol, y analiza la ubicación de dónde divergen los antepasados en el árbol; el que diverge a la "izquierda" es el menor de los dos.
Este procedimiento lleva O ( logn )tiempo escalando el árbol hasta la raíz y obteniendo las listas de antepasados. Si bien es cierto que esto parece más lento que la comparación de enteros, la verdad es que es lo mismo; solo esa comparación de enteros en una CPU está limitada por una gran constante para que seaO ( 1 ); si desborda esta constante, debe mantener varios enteros (O ( logn ) enteros en realidad) y hacer lo mismo O ( logn )comparaciones Alternativamente, puede "vincular" la altura del árbol en una cantidad constante y "engañar" de la misma manera que la máquina lo hace con enteros: ahora aparecerán consultasO ( 1 ).
Demostración de la operación de inserción
Para demostrarlo, puede insertar algunos elementos con su orden de la lista en la pregunta:
Paso 1
Empezar con re
Lista:
Árbol:
Paso 2
Insertar C, ∅ < C< D.
Lista:
Árbol:
Nota, pones explícitamente C "antes de" re, no porque la letra C esté antes de D, sino porque C< D en la lista.
Paso 3
Insertar UNA, ∅ < A < C.
Lista:
Árbol:
Rotación AVL:
Paso 4
Insertar si, A < B < C.
Lista:
Árbol:
No hay rotaciones necesarias.
Paso 5
Insertar mi, D < E< ∅
Lista:
Árbol:
Paso 6
Insertar F, B < F< C
Simplemente lo explicamos "después" si en el árbol, en este caso simplemente uniéndolo a sitiene razón; asíF ahora es justo después si en el recorrido en orden del árbol.
Lista:
Árbol:
Rotación AVL:
Demostración de la operación de comparación
UNA<?F
ancestors(A) = [C,B]
ancestors(F) = [C,B]
last_common_ancestor = B
B.left = A
B.right = F
... A < F #left is less than right
re<?F
ancestors(D) = [C]
ancestors(F) = [C,B]
last_common_ancestor = C
C.left = D
C.right = B #next ancestor for F is to the right
... D < F #left is less than right
si<?UNA
ancestors(B) = [C]
ancestors(A) = [B,C]
last_common_ancestor = B
B.left = A
... A < B #left is always less than parent
Fuentes gráficas