Rotações binárias de árvores

16

As árvores de pesquisa binária equilibrada são essenciais para garantir pesquisas O (log n) (ou operações similares). Em um ambiente dinâmico em que muitas chaves são inseridas e / ou excluídas aleatoriamente, as árvores podem degenerar em listas vinculadas que são horríveis para pesquisas. Portanto, existem vários tipos de árvores binárias de auto-equilíbrio que neutralizam esse efeito (como árvores AVL ou árvores espalhadas ). Essas árvores são baseadas em diferentes tipos de rotações que reequilibram a árvore.

Rotações

Neste desafio, veremos apenas as rotações à direita, uma rotação (a rotação à esquerda seria simétrica) é assim:

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

Se alguma das folhas 1, 4ou 6tivesse subárvores esquerda ou direita, uma rotação simplesmente as manteria lá. Se essa é uma subárvore de uma árvore maior, simplesmente "a cortamos" no nó 5e "reconectamos" a árvore girada (agora nó 3) a esse nó.

Desafio

Dada uma árvore de pesquisa binária 1 e uma chave, gire com o botão direito a árvore nesse nó, conforme descrito acima. A chave fornecida no exemplo acima seria 5.

Regras e E / S

  • você pode usar qualquer tipo de chave desde que haja uma bijeção entre as chaves de sua escolha e as dos casos de teste
  • você pode escolher qualquer representação para árvores binárias, desde que não haja ambiguidade (por exemplo, [3,[]]seja ambígua, a menos que seja especificado de outra forma) e seja natural para o seu idioma de escolha
  • como a entrada sempre será uma árvore de pesquisa binária, não há chaves duplicadas
  • você pode assumir que a chave está contida na árvore
  • você pode assumir que o nó que contém a chave tem um filho esquerdo
  • você não pode assumir uma subárvore direita sob a chave fornecida
  • você não pode assumir que a árvore está desequilibrada antes da rotação
  • você não pode assumir que a árvore está equilibrada após a rotação
  • você pode usar qualquer método de E / S padrão
  • seu envio pode ser uma função retornando a árvore ou um programa completo imprimindo a solução

Casos de teste

Estes exemplos representam uma árvore da seguinte maneira

  • se é uma folha: []
  • se é uma árvore com chave xe as duas subárvores são folhas:[x]
  • se é uma árvore com chave xe subárvores left right:[x,left,right]

O primeiro exemplo é o fornecido na seção Rotações . Se por algum motivo você precisa de uma representação gráfica deles, aqui 2 que você vá.

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: significando que, para qualquer nó, todas as chaves na subárvore esquerda serão menores que essa chave e todas as chaves na subárvore direita serão maiores que ele

2: para evitar o rot-link, eu os incorporei como um comentário

ბიმო
fonte

Respostas:

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

Obrigado a @BMO, @alephalpha e @Laikoni por um byte cada e @nimi por oito bytes!

Experimente online!

Angs
fonte
Usar data B=B[B]Intpouparia mais alguns bytes.
Laikoni
@Laikoni apenas um byte eu acho, mas eu vou levá-la
Angs
Você pode salvar 2 bytes primeiro mesclando os dois casos k<n=B[k!l,r]ne k>n=B[l,k!r]n, em um:, k/=n=B[k!l,k!r]ne depois adicionando k!x=xpara tornar o padrão correspondente exaustivo.
Radek
5

Vim , 25 bytes

Pega a entrada na chave e na árvore separadas pelo espaço do buffer. Espera-se que a árvore seja representada da seguinte maneira:

  • folha: []
  • nó com chave k, filho esquerdo <left>e filho direito <right>:[ k <left><right>]

Não os espaços ao redor da chave kque são importantes, de modo que a solução funcione para árvores arbitrárias.

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

Experimente online!

Explicação

"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)

Pré-visualização

Aqui está uma prévia do primeiro caso de teste, gerado com este script por Lynn :

                       Visualização do Vim

ბიმო
fonte
3

Wolfram Language (Mathematica) , 30 bytes

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

Experimente online!

Uma árvore representada da seguinte maneira:

  • se é uma folha: $ (você pode substituí-lo por qualquer valor que não seja uma chave)
  • se é uma árvore com chave xe subárvores left right:x[left,right]

Por exemplo, a árvore no primeiro caso de teste é representada por 5[3[1[$,$],4[$,$]],6[$,$]] .

Explicação:

#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
alefalpha
fonte
3

Lisp comum, 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))))))

Experimente online ou verifique todos os casos de teste!

Uma árvore é representada da seguinte maneira:

  • uma árvore vazia é representada como nil(ou equivalente no Common Lisp como a lista vazia ())
  • uma árvore não vazia é representada como uma lista de três elementos (node left-subtree right-subtree) (para que uma folha Lseja representada como (L nil nil)).
Renzo
fonte
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)

Experimente online! O link inclui casos de teste. Todos os nós devem ter entradas esquerda e direita, mas podem estar []indicando nenhuma subárvore nesse lado. Como abreviação, a suíte de testes usa l(N)para indicar que Né uma folha e l(N,L)para indicar que Ntem uma subárvore esquerda, Lmas nenhuma subárvore direita, tanto na entrada quanto na saída.

Neil
fonte
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:]]

Experimente online!

Formato de entrada:

  • Árvore: [KEY, LEFT_SUBTREE, RIGHT_SUBTREE]
  • Folha: []
Erik, o Outgolfer
fonte
1

Gelatina , 24 bytes

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

Experimente online!

Aviso: Normalmente, a linha superior não deve existir e a linha inferior deve ter um ß, não um ç. No entanto, a cadeia inteligente engana e ßnão combina bem, devido aßaridade variável. Tecnicamente, eu ainda poderia ter omitido a linha superior, mas o resultado teria que ser um programa completo, pois, caso contrário, teria que poder ser incorporado como sua própria linha dentro de qualquer programa, o que não é possível, a menos que você tem sorte. Isso significa que, infelizmente, a saída teria uma representação ambígua, porque, quando você envia um programa completo, o que é realmente contado é a saída, e não qual é o resultado tecnicamente antes do encerramento do programa. Portanto, para não mexer na recursão e na representação adequada de cadeias de caracteres, decidi enviar uma função de duas linhas, na qual o trabalho da linha superior é apenas chamar a inferior. A consequência? Um enorme desperdício de 2 bytes preciosos e valiosos. Na defesa de Jelly (e Dennis, bem como de todos os outros contribuidores),

Erik, o Outgolfer
fonte