Luân phiên cây nhị phân


16

Cây tìm kiếm nhị phân cân bằng là rất cần thiết để đảm bảo tra cứu O (log n) (hoặc các hoạt động tương tự). Trong một môi trường năng động, nơi có rất nhiều khóa được chèn và / hoặc xóa ngẫu nhiên, cây có thể bị thoái hóa thành các danh sách được liên kết, điều này thật kinh khủng cho việc tra cứu. Do đó, có nhiều loại cây nhị phân tự cân bằng khác nhau chống lại hiệu ứng này (chẳng hạn như cây AVL hoặc cây splay ). Những cây này dựa trên các loại luân chuyển khác nhau để cân bằng lại cây.

Xoay

Trong thử thách này, chúng ta sẽ chỉ nhìn vào các góc quay phải, một vòng quay như vậy (xoay trái sẽ đối xứng) trông như thế này:

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

Nếu bất kỳ lá nào 1, 4hoặc 6có cây con trái hoặc phải, một vòng quay sẽ chỉ đơn giản là giữ chúng ở đó. Nếu đây là cây con của cây lớn hơn, chúng ta chỉ cần "cắt nó" tại nút 5và "gắn lại" cây đã xoay (nút bây giờ 3) vào nút đó.

Thử thách

Cho cây tìm kiếm nhị phân 1 và khóa phải xoay cây trên nút đó như mô tả ở trên. Khóa được cung cấp trong ví dụ trên sẽ là 5.

Quy tắc và I / O

  • bạn có thể sử dụng bất kỳ loại nào cho các khóa miễn là có một sự lựa chọn giữa các khóa bạn chọn và các trường hợp kiểm tra
  • bạn có thể chọn bất kỳ đại diện nào cho cây nhị phân miễn là không có sự mơ hồ (ví dụ: [3,[]]không rõ ràng trừ khi có quy định khác) và đó là điều tự nhiên đối với ngôn ngữ bạn chọn
  • vì đầu vào sẽ luôn là cây tìm kiếm nhị phân, không có khóa trùng lặp
  • bạn có thể cho rằng chìa khóa được chứa trong cây
  • bạn có thể cho rằng nút chứa khóa có con trái
  • bạn không thể sử dụng một cây con đúng theo khóa được cung cấp
  • bạn không thể cho rằng cây bị mất cân bằng trước khi xoay
  • bạn không thể cho rằng cây được cân bằng sau khi xoay
  • bạn có thể sử dụng bất kỳ phương pháp I / O mặc định nào
  • trình của bạn có thể là một hàm trả về cây hoặc chương trình đầy đủ in giải pháp

Các trường hợp thử nghiệm

Những ví dụ này đại diện cho một cây như sau

  • nếu đó là một chiếc lá: []
  • nếu đó là một cây có chìa khóa xvà cả hai cây con đều là lá:[x]
  • nếu đó là một cây có chìa khóa xvà cây con left right:[x,left,right]

Ví dụ đầu tiên là ví dụ được cung cấp trong phần Xoay vòng . Nếu vì lý do nào đó bạn cần một đại diện đồ họa của họ, ở đây 2 bạn đi.

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: có nghĩa là đối với bất kỳ nút nào, tất cả các khóa trong cây con bên trái sẽ nhỏ hơn khóa đó và tất cả các khóa trong cây con bên phải đều lớn hơn nó

2: để ngăn chặn liên kết, tôi đã nhúng chúng dưới dạng nhận xét

Câu trả lời:


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

Cảm ơn @BMO, @alephalpha và @Laikoni cho mỗi byte mỗi và @nimi cho tám byte!

Hãy thử trực tuyến!


Sử dụng data B=B[B]Intsẽ tiết kiệm thêm một số byte.
Laikoni

Tôi nghĩ @Laikoni chỉ một byte nhưng tôi sẽ lấy nó
Angs

Bạn có thể lưu 2 byte bằng cách trước tiên hợp nhất hai trường hợp k<n=B[k!l,r]nk>n=B[l,k!r]nthành một: k/=n=B[k!l,k!r]nvà sau đó thêm vào k!x=xđể làm cho mô hình khớp hoàn toàn.
Radek

5

Vim , 25 byte

Lấy đầu vào trong bộ đệm - phím và cây được phân tách bằng dấu cách. Cây dự kiến ​​sẽ được đại diện như sau:

  • Lá cây: []
  • nút có khóa k, con trái <left>và con phải <right>:[ k <left><right>]

Không phải khoảng trống xung quanh phím klà quan trọng, sao cho giải pháp hoạt động cho các cây tùy ý.

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

Hãy thử trực tuyến!

Giải trình

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

Xem trước

Đây là bản xem trước của trường hợp thử nghiệm đầu tiên, được tạo bởi kịch bản này bởi Lynn :

                       Xem trước Vim


3

Ngôn ngữ Wolfram (Mathicala) , 30 byte

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

Hãy thử trực tuyến!

Một cây đại diện như sau:

  • nếu đó là một chiếc lá: $(bạn có thể thay thế nó bằng bất kỳ giá trị nào không phải là khóa)
  • nếu đó là một cây có chìa khóa xvà cây con left right:x[left,right]

Ví dụ, cây trong trường hợp thử nghiệm đầu tiên được đại diện bởi 5[3[1[$,$],4[$,$]],6[$,$]].

Giải trình:

#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 thông thường, 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))))))

Hãy thử trực tuyến hoặc xác minh tất cả các testcase!

Một cây được biểu diễn như sau:

  • một cây trống được biểu diễn dưới dạng nil(hoặc tương đương trong Common Lisp dưới dạng danh sách trống() )
  • một cây không trống được biểu diễn dưới dạng một danh sách gồm ba phần tử (node left-subtree right-subtree) (vì vậy một lá Lđược biểu diễn dưới dạng (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)

Hãy thử trực tuyến! Liên kết bao gồm các trường hợp thử nghiệm. Tất cả các nút phải có các mục bên trái và bên phải nhưng chúng có thể []chỉ ra không có cây con ở bên đó. Là một từ viết tắt, bộ kiểm tra sử dụng l(N)để chỉ ra đó Nlà một chiếc lá và l(N,L)để chỉ ra rằng nó Ncó một cây con bên trái Lnhưng không có cây con bên phải cả trên đầu vào và đầu ra.



1

Thạch , 24 byte

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

Hãy thử trực tuyến!

Cảnh báo: Thông thường, dòng trên cùng không nên tồn tại và dòng dưới cùng nên có a ß, không phải a ç. Tuy nhiên, thủ thuật chuỗi thông minh vàß không hợp nhau, doßarity biến của. Về mặt kỹ thuật, tôi vẫn có thể bỏ qua dòng trên cùng, nhưng sau đó kết quả sẽ phải là một chương trình đầy đủ, vì nếu không, nó sẽ phải được kết hợp thành dòng riêng trong bất kỳ chương trình nào, trừ khi bạn không thể Thật may mắn. Điều này có nghĩa là, thật không may, đầu ra sẽ có một đại diện mơ hồ, bởi vì, khi bạn gửi một chương trình đầy đủ, những gì thực sự được tính là đầu ra, và không phải là kết quả về mặt kỹ thuật trước khi chương trình đóng lại. Vì vậy, để không gây rối với cả đệ quy và biểu diễn chuỗi thích hợp, tôi đã quyết định gửi hàm 2 dòng, trong đó công việc của dòng trên cùng chỉ là gọi hàm dưới cùng. Hậu quả? Một sự lãng phí rất lớn của 2 byte quý giá. Trong phòng thủ của Jelly (và Dennis, cũng như mọi người đóng góp khác),

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.