Rotaciones de árboles binarios.

16

Los árboles de búsqueda binarios balanceados son esenciales para garantizar búsquedas O (log n) (u operaciones similares). En un entorno dinámico donde muchas claves se insertan y / o eliminan al azar, los árboles pueden degenerar en listas vinculadas que son horribles para las búsquedas. Por lo tanto, hay varios tipos de árboles binarios autoequilibrados que contrarrestan este efecto (como los árboles AVL o los árboles de separación ). Estos árboles se basan en diferentes tipos de rotaciones que reequilibran el árbol.

Rotaciones

En este desafío, solo veremos rotaciones derechas individuales, tal rotación (la rotación izquierda sería simétrica) se ve así:

    5            3
   / \          / \
  3   6   =>   1   5
 / \              / \
1   4            4   6

Si alguna de las hojas 1, 4o 6tuviera subárboles a la izquierda o derecha, una rotación simplemente las mantendría allí. Si este es un subárbol de un árbol más grande, simplemente lo "cortaríamos" en el nodo 5y "volveríamos a unir" el árbol girado (ahora nodo 3) a ese nodo.

Desafío

Dado un árbol de búsqueda binario 1 y una tecla, gire a la derecha el árbol en ese nodo como se describió anteriormente. La clave proporcionada en el ejemplo anterior sería 5.

Reglas y E / S

  • puede usar cualquier tipo de teclas siempre que haya una biyección entre las teclas de su elección y las de los casos de prueba
  • puede elegir cualquier representación para árboles binarios siempre que no haya ambigüedad (por ejemplo, [3,[]]es ambigua a menos que se especifique lo contrario) y es natural para su idioma de elección
  • Como la entrada siempre será un árbol de búsqueda binario, no hay claves duplicadas
  • puede suponer que la clave está contenida en el árbol
  • puede suponer que el nodo que contiene la clave tiene un hijo izquierdo
  • es posible que no asuma un subárbol derecho en la clave proporcionada
  • es posible que no se asuma que el árbol está desequilibrado antes de la rotación
  • es posible que no se asuma que el árbol está equilibrado después de la rotación
  • puede usar cualquier método de E / S predeterminado
  • su envío puede ser una función que devuelve el árbol o un programa completo que imprime la solución

Casos de prueba

Estos ejemplos representan un árbol de la siguiente manera

  • si es una hoja: []
  • si es un árbol con clave xy ambos subárboles son hojas:[x]
  • si es un árbol con clave xy subárboles left right:[x,left,right]

El primer ejemplo es el proporcionado en la sección Rotaciones . Si por alguna razón necesita una representación gráfica de ellos, aquí 2 que vaya.

5 [5,[3,[1],[4]],[6]]  ->  [3,[1],[5,[4],[6]]]
5 [5,[3,[1],[4]],[]]  ->  [3,[1],[5,[4],[]]]
5 [5,[3,[],[4]],[6]]  ->  [3,[],[5,[4],[6]]]
5 [5,[3,[1],[]],[]]  ->  [3,[1],[5]]
4 [8,[4,[2,[1],[3]],[6,[5],[7]]],[12,[10,[9],[11]],[14,[13],[15]]]]  ->  [8,[2,[1],[4,[3],[6,[5],[7]]]],[12,[10,[9],[11]],[14,[13],[15]]]]
8 [10,[8,[6,[4,[2,[],[3]],[5]],[7]],[9]],[11]]  ->  [10,[6,[4,[2,[],[3]],[5]],[8,[7],[9]]],[11]]
10 [10,[8,[6,[4,[2,[],[3]],[5]],[7]],[9]],[11]]  ->  [8,[6,[4,[2,[],[3]],[5]],[7]],[10,[9],[11]]]
9 [6,[3,[2],[5]],[9,[8],[12,[11],[15,[14],[]]]]]  ->  [6,[3,[2],[5]],[8,[],[9,[],[12,[11],[15,[14],[]]]]]]
7 [7,[5,[3,[1],[4]],[6]],[8]]  ->  [5,[3,[1],[4]],[7,[6],[8]]]
15 [17,[9,[5,[2,[0],[4]],[8]],[15,[13,[11,[10],[12]],[14]],[16]]],[40,[27,[21,[19,[18],[20]],[24,[22],[25]]],[28]],[44,[42,[41],[]],[51,[47],[59,[55],[61]]]]]]  ->  [17,[9,[5,[2,[0],[4]],[8]],[13,[11,[10],[12]],[15,[14],[16]]]],[40,[27,[21,[19,[18],[20]],[24,[22],[25]]],[28]],[44,[42,[41],[]],[51,[47],[59,[55],[61]]]]]]
21 [17,[9,[5,[2,[0],[4]],[8]],[15,[13,[11,[10],[12]],[14]],[16]]],[40,[27,[21,[19,[18],[20]],[24,[22],[25]]],[28]],[44,[42,[41],[]],[51,[47],[59,[55],[61]]]]]]  ->  [17,[9,[5,[2,[0],[4]],[8]],[15,[13,[11,[10],[12]],[14]],[16]]],[40,[27,[19,[18],[21,[20],[24,[22],[25]]]],[28]],[44,[42,[41],[]],[51,[47],[59,[55],[61]]]]]]

1: lo que significa que para cualquier nodo todas las claves en el subárbol izquierdo serán más pequeñas que esa clave y todas las claves en el subárbol derecho son mayores que

2: para evitar la rotura de enlaces, los incruste como comentario

ბიმო
fuente

Respuestas:

8

Haskell , 93 92 84 83 82 bytes

data B=B[B]Int|L
k!B[l@(B[x,y]a),r]n|k<n=B[k!l,r]n|k>n=B[l,k!r]n|1>0=B[x,B[y,r]k]a

¡Gracias a @BMO, @alephalpha y @Laikoni por un byte cada uno y @nimi por ocho bytes!

Pruébalo en línea!

Angs
fuente
El uso data B=B[B]Intahorraría algunos bytes más.
Laikoni
@Laikoni solo un byte, creo, pero lo tomaré
Angs
Puede guardar 2 bytes fusionando primero los dos casos k<n=B[k!l,r]ny k>n=B[l,k!r]n, en uno:, k/=n=B[k!l,k!r]ny luego sumando k!x=xpara que la coincidencia de patrones sea exhaustiva.
Radek
5

Vim , 25 bytes

Toma la entrada en el búfer: clave y árbol separados por espacios. Se espera que el árbol se represente de la siguiente manera:

  • hoja: []
  • nodo con clave k, hijo izquierdo <left>y niño derecho <right>:[ k <left><right>]

No son los espacios alrededor de la clave los kque son importantes, de modo que la solución funciona para árboles arbitrarios.

"adw/ <C-r>a⏎3dw%l"apr[%xl%i]

Pruébalo en línea!

Explicación

"adw                           " delete the key and trailing space, keep in register a
    / <C-r>a⏎                  " move cursor to the key surrounded with spaces
             3dw               " remove key and [ (move left node to top)
                %l             " move cursor to the right subtree
                  "ap          " insert key there
                     r[        " insert a [ (appending subtree to key)
                       %       " move to the end of new left subtree
                        x      " remove ] (fix parentheses)
                         l%    " move to the end of new right subtree
                           i]  " insert ] (fix parentheses)

Avance

Aquí hay una vista previa del primer caso de prueba, generado con este script por Lynn :

                       Vista previa de Vim

ბიმო
fuente
3

Wolfram Language (Mathematica) , 30 bytes

#2/.a_~b_~c_~#~d_:>b[a,c~#~d]&

Pruébalo en línea!

Un árbol representado de la siguiente manera:

  • si es una hoja: $(puede reemplazarlo por cualquier valor que no sea una clave)
  • si es un árbol con clave xy subárboles left right:x[left,right]

Por ejemplo, el árbol en el primer caso de prueba está representado por 5[3[1[$,$],4[$,$]],6[$,$]].

Explicación:

#2                                the second input
  /.                              replace
    a_~b_~c_~#~d_                 #[b[a,c],d], where # is the first input
                 :>               by
                   b[a,c~#~d]     b[a,#[c,d]]
                             &    define a function
alephalpha
fuente
3

Lisp común, 146 bytes

(defun r(k a)(cond((not a)a)((=(car a)k)`(,(caadr a),(cadadr a)(,(car a),(car(cddadr a)),(caddr a))))(t`(,(car a),(r k(cadr a)),(r k(caddr a))))))

¡Pruébelo en línea o verifique todos los casos de prueba!

Un árbol se representa de la siguiente manera:

  • un árbol vacío se representa como nil(o equivalente en Common Lisp como la lista vacía ())
  • un árbol no vacío se representa como una lista de tres elementos (node left-subtree right-subtree) (por lo que una hoja Lse representa como (L nil nil)).
Renzo
fuente
2

JavaScript (Node.js) , 70 bytes

n=>f=a=>n-a[0]?(a[i=n<a[0]?1:2]=f(a[i]),a):(i=a[1],a[1]=i[2],i[2]=a,i)

Pruébalo en línea! El enlace incluye casos de prueba. Todos los nodos deben tener entradas izquierda y derecha, pero pueden []indicar que no hay subárbol en ese lado. Como abreviatura, el conjunto de pruebas utiliza l(N)para indicar que Nes una hoja y l(N,L)para indicar que Ntiene un subárbol izquierdo Lpero no un subárbol derecho tanto en la entrada como en la salida.

Neil
fuente
2

Python 2 , 85 bytes

R=lambda T,k:k in T and T[1][:2]+[[T[0],T[1][2],T[2]]]or T[:1]+[R(i,k)for i in T[1:]]

Pruébalo en línea!

Formato de entrada:

  • Árbol: [KEY, LEFT_SUBTREE, RIGHT_SUBTREE]
  • Hoja: []
Erik el Outgolfer
fuente
1

Jalea , 24 bytes

ñ
Ḣ,1ịṪƊṭ@ṪṭḢð{Ḣ;ç€ɗ¹¡i?

Pruébalo en línea!

Advertencia: Normalmente, la línea superior no debería existir, y la línea inferior debería tener un ß, no un ç. Sin embargo, los trucos de la cadena inteligente y ßno van bien juntos, debido aßArity variable. Técnicamente, podría haber omitido la línea superior, pero entonces el resultado habría sido un programa completo, ya que de lo contrario tendría que poder incorporarse como su propia línea dentro de cualquier programa, lo cual no es posible a menos que usted Tienes suerte. Esto significa que, desafortunadamente, la salida habría tenido una representación ambigua, porque, cuando envía un programa completo, lo que realmente se obtiene cuenta, y no cuál es el resultado técnico antes de que se cierre el programa. Entonces, para no hacer un lío con la recursión y la representación de cadena adecuada, he decidido enviar una función de 2 líneas, donde el trabajo de la línea superior es solo llamar a la inferior. ¿La consecuencia? Una gran pérdida de 2 bytes preciosos y valiosos. En defensa de Jelly (y Dennis, así como de todos los demás contribuyentes),

Erik el Outgolfer
fuente