Rotazioni dell'albero binario


16

Gli alberi di ricerca binaria bilanciata sono essenziali per garantire ricerche O (log n) (o operazioni simili). In un ambiente dinamico in cui molte chiavi vengono inserite e / o eliminate in modo casuale, gli alberi potrebbero degenerare in elenchi collegati che sono orribili per le ricerche. Quindi ci sono vari tipi di alberi binari autobilanciati che contrastano questo effetto (come alberi AVL o alberi di splay ). Questi alberi si basano su diversi tipi di rotazioni che riequilibrano l'albero.

rotazioni

In questa sfida vedremo solo singole rotazioni a destra, tale rotazione (la rotazione a sinistra sarebbe simmetrica) è simile a questa:

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

Se una qualsiasi delle foglie 1, 4o 6avesse sotto-alberi sinistro o destro, una rotazione li avrebbe semplicemente tenuti lì. Se questa è una sottostruttura di un albero più grande, avremmo semplicemente "tagliato" sul nodo 5e "ricollegato" l'albero ruotato (ora nodo 3) a quel nodo.

Sfida

Dato un albero di ricerca binario 1 e una chiave, ruota a destra l'albero su quel nodo come descritto sopra. La chiave fornita nell'esempio sopra sarebbe 5.

Regole e I / O

  • è possibile utilizzare qualsiasi tipo di chiave purché vi sia una biiezione tra le chiavi di propria scelta e quelle dei casi di test
  • puoi scegliere qualsiasi rappresentazione per alberi binari purché non ci siano ambiguità (ad es. [3,[]]è ambigua se non diversamente specificato) ed è naturale per la tua lingua preferita
  • poiché l'input sarà sempre un albero di ricerca binario non ci sono chiavi duplicate
  • puoi presumere che la chiave sia contenuta nell'albero
  • si può presumere che il nodo contenente la chiave abbia un figlio sinistro
  • si può non assumere una sottostruttura proprio sotto la chiave fornita
  • si può non dare per scontato che l'albero è sbilanciato, prima della rotazione
  • si può non pensare che l'albero è bilanciato dopo la rotazione
  • è possibile utilizzare qualsiasi metodo I / O predefinito
  • l'invio può essere una funzione che restituisce l'albero o il programma completo che stampa la soluzione

Casi test

Questi esempi rappresentano un albero come segue

  • se è una foglia: []
  • se è un albero con chiave xed entrambi i sottotitoli sono foglie:[x]
  • se è un albero con chiave xe sottotitoli left right:[x,left,right]

Il primo esempio è quello fornito nella sezione Rotazioni . Se per qualche motivo hai bisogno di una rappresentazione grafica di loro, qui 2 vai.

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: significa che per ogni nodo tutte le chiavi nella sottostruttura sinistra saranno più piccole di quella chiave e tutte le chiavi nella sottostruttura destra sono maggiori di essa

2: per impedire il collegamento del rot, li ho incorporati come commento

Risposte:


8

Haskell , 93 92 84 83 82 byte

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

Grazie a @BMO, @alephalpha e @Laikoni per un byte ciascuno e @nimi per otto byte!

Provalo online!


L'utilizzo data B=B[B]Intrisparmierebbe qualche altro byte.
Laikoni,

@Laikoni solo un byte penso ma lo prenderò
Angs

È possibile salvare 2 byte unendo prima i due casi k<n=B[k!l,r]ne k>n=B[l,k!r]n, in uno k/=n=B[k!l,k!r]n:, quindi aggiungendo k!x=xper rendere esaustivo il pattern matching.
Radek,

5

Vim , 25 byte

Accetta l'input nel buffer - chiave e albero separati da spazio. L'albero dovrebbe essere rappresentato come segue:

  • foglia: []
  • nodo con chiave k, figlio sinistro <left>e figlio destro <right>:[ k <left><right>]

Non gli spazi attorno alla chiave kche sono importanti, in modo tale che la soluzione funzioni per alberi arbitrari.

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

Provalo online!

Spiegazione

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

Anteprima

Ecco un'anteprima del primo caso di test, generato con questo script da Lynn :

                       Anteprima di Vim


3

Wolfram Language (Mathematica) , 30 byte

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

Provalo online!

Un albero rappresentato come segue:

  • se è una foglia: $(puoi sostituirla con qualsiasi valore che non sia una chiave)
  • se è un albero con chiave xe sottotitoli left right:x[left,right]

Ad esempio, l'albero nel primo caso di test è rappresentato da 5[3[1[$,$],4[$,$]],6[$,$]].

Spiegazione:

#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

3

Lisp comune, 146 byte

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

Provalo online o verifica tutti i test!

Un albero è rappresentato come segue:

  • un albero vuoto è rappresentato come nil(o equivalentemente in Common Lisp come elenco vuoto ())
  • un albero non vuoto è rappresentato come un elenco di tre elementi (node left-subtree right-subtree) (quindi una foglia Lè rappresentata come (L nil nil)).

2

JavaScript (Node.js) , 70 byte

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)

Provalo online! Il link include casi di test. Tutti i nodi devono avere voci sinistra e destra ma possono []indicare nessuna sottostruttura su quel lato. Come abbreviazione la suite di test usa l(N)per indicare che Nè una foglia e l(N,L)per indicare che Nha una sottostruttura sinistra Lma nessuna sottostruttura destra sia in input che in output.



1

Gelatina , 24 byte

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

Provalo online!

Avvertenza: normalmente la riga superiore non dovrebbe esistere e la riga inferiore dovrebbe avere un ß, non un ç. Tuttavia, i trucchi a catena intelligenti e ßnon vanno bene insieme, a causa dißarità variabile. Tecnicamente, avrei potuto ancora omettere la riga superiore, ma il risultato avrebbe dovuto essere un programma completo, poiché altrimenti avrebbe dovuto essere in grado di essere incorporato come linea propria all'interno di qualsiasi programma, cosa impossibile se non si sei fortunato. Ciò significa che, sfortunatamente, l'output avrebbe avuto una rappresentazione ambigua, perché, quando si invia un programma completo, ciò che conta effettivamente l'output conta e non quale sia il risultato tecnico prima della chiusura del programma. Quindi, al fine di non fare confusione sia con la ricorsione che con la corretta rappresentazione delle stringhe, ho deciso di inviare una funzione a 2 righe, in cui il lavoro della linea superiore è solo quello di chiamare quello inferiore. La conseguenza? Un enorme spreco di 2 byte preziosi e preziosi. Nella difesa di Jelly (e Dennis, così come di ogni altro collaboratore),

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.