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
, 4
ou 6
tivesse 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ó 5
e "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
x
e as duas subárvores são folhas:[x]
- se é uma árvore com chave
x
e subárvoresleft
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
data B=B[B]Int
pouparia mais alguns bytes.k<n=B[k!l,r]n
ek>n=B[l,k!r]n
, em um:,k/=n=B[k!l,k!r]n
e depois adicionandok!x=x
para tornar o padrão correspondente exaustivo.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:
[]
k
, filho esquerdo<left>
e filho direito<right>
:[ k <left><right>]
Não os espaços ao redor da chave
k
que são importantes, de modo que a solução funcione para árvores arbitrárias.Experimente online!
Explicação
Pré-visualização
Aqui está uma prévia do primeiro caso de teste, gerado com este script por Lynn :
fonte
Wolfram Language (Mathematica) , 30 bytes
Experimente online!
Uma árvore representada da seguinte maneira:
$
(você pode substituí-lo por qualquer valor que não seja uma chave)x
e subárvoresleft
right
:x[left,right]
Por exemplo, a árvore no primeiro caso de teste é representada por
5[3[1[$,$],4[$,$]],6[$,$]]
.Explicação:
fonte
Lisp comum, 146 bytes
Experimente online ou verifique todos os casos de teste!
Uma árvore é representada da seguinte maneira:
nil
(ou equivalente no Common Lisp como a lista vazia()
)(node left-subtree right-subtree)
(para que uma folhaL
seja representada como(L nil nil)
).fonte
JavaScript (Node.js) , 70 bytes
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 usal(N)
para indicar queN
é uma folha el(N,L)
para indicar queN
tem uma subárvore esquerda,L
mas nenhuma subárvore direita, tanto na entrada quanto na saída.fonte
Python 2 , 85 bytes
Experimente online!
Formato de entrada:
[KEY, LEFT_SUBTREE, RIGHT_SUBTREE]
[]
fonte
Gelatina , 24 bytes
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),fonte