การหมุนของต้นไม้ไบนารี


16

แผนผังการค้นหาแบบไบนารีที่สมดุลเป็นสิ่งจำเป็นในการรับประกันการค้นหาO (บันทึก n) (หรือการดำเนินการที่คล้ายกัน) ในสภาพแวดล้อมแบบไดนามิกที่มีการแทรกและสุ่มคีย์จำนวนมากและ / หรือลบต้นไม้อาจทำให้รายการเชื่อมโยงแย่ลงซึ่งน่ากลัวสำหรับการค้นหา ดังนั้นจึงมีหลายชนิดของต้นไม้ไบนารีสมดุลตัวเองที่ต่อต้านผลกระทบนี้ (เช่นต้นไม้ AVLหรือต้นไม้ splay ) ต้นไม้เหล่านี้ขึ้นอยู่กับการหมุนแบบต่าง ๆที่ปรับสมดุลของต้นไม้

ผลัด

ในความท้าทายนี้เราจะดูเฉพาะการหมุนทางขวาเดียวการหมุน (การหมุนซ้ายจะสมมาตร) เช่นนี้:

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

หากมีใบใดใบ1หนึ่ง4หรือ6มีต้นไม้ย่อยทางซ้ายหรือขวาการหมุนก็จะทำให้พวกมันอยู่ตรงนั้น หากนี่เป็นทรีย่อยของต้นไม้ที่มีขนาดใหญ่ขึ้นเราเพียงแค่ "ตัดมันออก" ที่โหนด5และ "แนบใหม่" ต้นไม้ที่หมุน (ตอนนี้โหนด3) ไปยังโหนดนั้น

ท้าทาย

ให้แผนภูมิการค้นหาแบบไบนารี่1และคีย์หมุนทรีบนโหนดนั้นตามที่อธิบายไว้ข้างต้น 5ที่สำคัญที่ให้ไว้ในตัวอย่างข้างต้นจะเป็น

กฎและ I / O

  • คุณสามารถใช้กุญแจประเภทใดก็ได้ตราบใดที่มี bijection ระหว่างปุ่มที่คุณเลือกและของกรณีทดสอบ
  • คุณสามารถเลือกการแสดงใด ๆ สำหรับต้นไม้ไบนารีตราบเท่าที่ไม่มีความกำกวม (เช่น[3,[]]ไม่ชัดเจนเว้นแต่จะระบุไว้เป็นอย่างอื่น) และเป็นเรื่องปกติสำหรับภาษาที่คุณเลือก
  • เนื่องจากอินพุตจะเป็นแผนผังการค้นหาแบบไบนารีเสมอไม่มีคีย์ที่ซ้ำกัน
  • คุณอาจคิดว่ากุญแจนั้นมีอยู่ในต้นไม้
  • คุณอาจสมมติว่าโหนดที่มีรหัสมีลูกซ้าย
  • คุณอาจไม่ถือว่าทรีย่อยถูกต้องภายใต้คีย์ที่ให้ไว้
  • คุณอาจไม่คิดว่าต้นไม้ไม่สมดุลก่อนหมุน
  • คุณอาจไม่คิดว่าต้นไม้มีความสมดุลหลังจากการหมุน
  • คุณสามารถใช้วิธีI / O เริ่มต้น
  • การส่งของคุณอาจเป็นฟังก์ชันที่ส่งคืนต้นไม้หรือโปรแกรมเต็มรูปแบบที่พิมพ์โซลูชัน

กรณีทดสอบ

ตัวอย่างเหล่านี้แสดงถึงต้นไม้ดังต่อไปนี้

  • ถ้าเป็นใบไม้: []
  • ถ้ามันเป็นต้นไม้ที่มีกุญแจxและต้นไม้ทั้งสองใบเป็นใบไม้:[x]
  • ถ้าเป็นต้นไม้ที่มีคีย์xและ subtrees left right:[x,left,right]

ตัวอย่างแรกเป็นหนึ่งที่มีให้บริการในส่วนของการหมุน ถ้าด้วยเหตุผลบางอย่างที่คุณต้องการการแสดงภาพกราฟิกของพวกเขาที่นี่2คุณไป

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: หมายความว่าสำหรับโหนดใด ๆ คีย์ทั้งหมดในทรีย่อยด้านซ้ายจะเล็กกว่าคีย์นั้นและคีย์ทั้งหมดในทรีย่อยด้านขวามีค่ามากกว่ามัน

2: เพื่อป้องกันไม่ให้ลิงค์เน่าฉันฝังมันเป็นความคิดเห็น

คำตอบ:


8

Haskell , 93 92 84 83 82 ไบต์

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

ขอบคุณ @BMO, @alephalpha และ @Laikoni สำหรับแต่ละไบต์และ @nimi สำหรับแปดไบต์!

ลองออนไลน์!


การใช้data B=B[B]Intจะช่วยประหยัดไบต์ได้มากขึ้น
Laikoni

@Laikoni เพียงหนึ่งไบต์ฉันคิดว่า แต่ฉันจะเอามัน
Angs

คุณสามารถประหยัด 2 ไบต์ครั้งแรกโดยการรวมสองกรณีk<n=B[k!l,r]nและk>n=B[l,k!r]nลงไปที่หนึ่ง: k/=n=B[k!l,k!r]nและแล้วเพิ่มk!x=xเพื่อให้ครบถ้วนสมบูรณ์จับคู่รูปแบบ
Radek

5

เป็นกลุ่ม 25 ไบต์

รับอินพุตในบัฟเฟอร์ - ช่องว่างระหว่างคีย์และแผนผัง ต้นไม้คาดว่าจะแสดงดังนี้

  • ใบ: []
  • โหนดพร้อมคีย์kลูกซ้าย<left>และลูกขวา<right> :[ k <left><right>]

ไม่ใช่ช่องว่างรอบ ๆ กุญแจkซึ่งสำคัญเช่นโซลูชันทำงานกับต้นไม้โดยพลการ

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

ลองออนไลน์!

คำอธิบาย

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

ดูตัวอย่าง

นี่คือตัวอย่างของกรณีทดสอบครั้งแรกที่สร้างโดยสคริปต์นี้โดยLynn :

                       เป็นกลุ่มตัวอย่าง


3

ภาษา Wolfram (Mathematica)ขนาด 30 ไบต์

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

ลองออนไลน์!

ต้นไม้แสดงดังนี้:

  • ถ้าเป็นใบไม้: $ (คุณสามารถแทนที่ด้วยค่าใด ๆ ที่ไม่ใช่คีย์)
  • ถ้ามันเป็นต้นไม้ที่มีคีย์xและ subtreesleft right:x[left,right]

ตัวอย่างเช่นต้นไม้ในกรณีทดสอบแรกจะถูกแทนด้วย 5[3[1[$,$],4[$,$]],6[$,$]]ยกตัวอย่างเช่นต้นไม้ในกรณีที่การทดสอบครั้งแรกที่เป็นตัวแทนจาก

คำอธิบาย:

#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 สามัญ, 146 ไบต์

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

ลองออนไลน์หรือตรวจสอบการทดสอบทั้งหมด!

ต้นไม้แสดงดังนี้:

  • ต้นไม้ว่างถูกแสดงเป็นnil(หรือเทียบเท่าใน Common LISP เป็นรายการว่าง())
  • ต้นไม้ที่ไม่ว่างเปล่าจะแสดงเป็นรายการขององค์ประกอบสามอย่าง(node left-subtree right-subtree) (ดังนั้นใบไม้Lจะถูกแทนด้วย(L nil nil))

2

JavaScript (Node.js) , 70 ไบต์

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)

ลองออนไลน์! ลิงก์มีกรณีทดสอบ โหนดทั้งหมดต้องมีรายการด้านซ้ายและขวา แต่สามารถ[]ระบุว่าไม่มีทรีย่อยบนด้านนั้น ในฐานะที่เป็นตัวย่อชุดทดสอบใช้l(N)เพื่อระบุว่าNเป็นใบไม้และl(N,L)เพื่อระบุว่าNมีทรีย่อยด้านซ้ายLแต่ไม่มีทรีย่อยที่ถูกต้องทั้งในอินพุตและเอาต์พุต



1

เยลลี่ 24 ไบต์

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

ลองออนไลน์!

คำเตือน: ปกติบรรทัดบนสุดไม่ควรอยู่และบรรทัดด้านล่างควรจะมีไม่ได้ß çอย่างไรก็ตามเทคนิคลูกโซ่ที่ฉลาดและßไม่เข้ากันได้ดีเนื่องจากßความแปรปรวนของตัวแปร ในทางเทคนิคแล้วฉันยังคงมองข้ามบรรทัดบนสุด แต่จากนั้นผลลัพธ์จะต้องเป็นโปรแกรมเต็มรูปแบบเนื่องจากไม่เช่นนั้นจะต้องสามารถรวมเป็นบรรทัดของตัวเองในโปรแกรมใด ๆ ซึ่งเป็นไปไม่ได้เว้นแต่คุณจะ โชคดี ซึ่งหมายความว่าน่าเสียดายที่ผลลัพธ์จะมีการแสดงที่ไม่ชัดเจนเพราะเมื่อคุณส่งโปรแกรมเต็มรูปแบบสิ่งที่ได้รับการนับจำนวนจริงไม่ใช่สิ่งที่ผลลัพธ์ทางเทคนิคก่อนที่โปรแกรมจะปิด ดังนั้นเพื่อไม่ให้ยุ่งกับการเรียกซ้ำและการแสดงสตริงที่เหมาะสมฉันตัดสินใจส่งฟังก์ชั่น 2 บรรทัดซึ่งงานของสายบนสุดเป็นเพียงการโทรไปที่ด้านล่าง ผลที่ตามมาคืออะไร? ขยะจำนวน 2 ไบต์ที่มีค่าและมีค่ามาก ในการป้องกันของเจลลี่ (และเดนนิสรวมถึงผู้สนับสนุนอื่น ๆ )

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.