Xoay cây đỏ-đen: Khi tôi có y = x.right; x.right = y.left. Có giống như vậy khi viết y.left.p = x là x.right.p = x


8

Trong CLRS, các tác giả giới thiệu hoạt động xoay vòng trong cây đỏ đen bằng cách làm mã giả sau: Xoay trái

LEFT-ROTATE(T, x)

    y = x.right        # Line 1
    x.right = y.left   # Line 2
    if y.left ≠ T.nil  # Line 3
        y.left.p = x   # Line 4
    y.p = x.p
    if x.p == T.nil
        T.root = y
    elseif x == x.p.left
        x.p.left = y
    else x.p.right = y
    y.left = x
    x.p = y

trong đó thuộc tính .left, .right, .p tương ứng với con trái, con phải và cha mẹ của nó. T là cây.

Câu hỏi chính của tôi nằm ở Dòng 3 và Dòng 4:

  1. Tại sao tôi cần phải có điều kiện if của Line 3? Cuốn sách nói rằng NIL thực sự là một chiếc lá của cây đỏ đen, vì vậy tôi cho rằng NIL cũng có thể có con trỏ cha. Các mã này vẫn hoạt động mà không có Dòng 3.

  2. Với Dòng 1 và Dòng 2, tôi có thể viết Dòng 4 là x.right.p = xkhông? Nếu chúng thực sự giống nhau, có lý do nào mà tác giả chọn viết nó y.left.p = xkhông?

Bản năng của tôi x.right.p = xlà khác với y.left.p = x. Tuy nhiên, tôi không thể tìm thấy một lời giải thích tốt cho việc này. Tôi đã kiểm tra định nghĩa của con trỏ , nhưng nó vẫn còn khá khó hiểu sau khi tôi đã googled rất nhiều ...

Câu trả lời:


3

nhập mô tả hình ảnh ở đây

Lưu ý: Tôi không đặt mũi tên mối quan hệ cha mẹ trên mỗi sơ đồ để loại bỏ một số lộn xộn.

Nút null không thể có cha mẹ, như sơ đồ hiển thị. Có nhiều giải thích sâu hơn ở đây

  1. như sơ đồ cho thấy, việc kiểm tra trên dòng 3 là không cần thiết, nếu y.leftKHÔNG BAO GIỜ null. Nếu điều này không được đảm bảo, kiểm tra này là để ngăn chặn lỗi "lỗi con trỏ null".

  2. sự lựa chọn sử dụng y.left.p = xlà sở thích của người dùng. Với tôi, nó rõ ràng hơn nhiều. Chúng tôi đang làm cho "y left subtree into x right subtree".

Ví dụ @HolderRoy đưa ra sẽ hoạt động, nhưng nó thực hiện phân bổ bổ sung để có thể lưu trữ y.leftcon trỏ, gọi hàm foreach.


Có bất kỳ lý do mà một nút null không có con trỏ cha? Tôi kiểm tra cuốn sách của phần này một lần nữa. Tuy nhiên, nó không giải quyết tài sản này cả.
cindy50633

1
@ cindy50633 null cho thấy biến / thuộc tính đã được khởi tạo, nhưng không có địa chỉ nào nó trỏ đến, vì vậy nó sẽ không có bất kỳ cấu trúc hoặc thuộc tính nào. Cấu trúc giữ tài sản parentkhông tồn tại, do parentđó không tồn tại.
mr.vea

2

Sau khi đọc dòng mô tả cuối cùng của bạn, tôi nhận thấy rằng bạn không học được con trỏ, vì vậy bạn có thể khó hiểu tại sao chúng ta cần phán xét nếu có gì đó là T.nil. Nhưng tôi vẫn cố gắng trả lời câu hỏi của bạn, tôi hy vọng tôi có thể giải thích rõ ràng.

  1. Về cấu trúc dữ liệu, chắc chắn bạn không cần Dòng 3, bạn cần điều chỉnh y.left.p trong mọi trường hợp.

    Tuy nhiên, đối với một ngôn ngữ nhất định, chỉ cần sử dụng C / C ++ làm ví dụ, chúng tôi sử dụng NULL hoặc nullptr cho cha mẹ của lá và gốc, nghĩa là không có gì. Chỉ cần nghĩ về nó, có cần thiết phải tốn nhiều bộ nhớ như nút cây để cứu những chiếc lá vô dụng? Dĩ nhiên là không. Vì vậy, chúng tôi đánh dấu nó là con trỏ NULL, có nghĩa là không có gì, và alse không có p, trái hoặc phải.

    Kết luận rằng điều đó phụ thuộc vào việc bạn thực hiện liệu bạn có nên đánh giá T.nil ở Dòng 3 hay không.

  2. Vâng, bạn có thể. saux.right = y.left , x.right và y.left tạm thời là cùng một thứ, vì vậy x.right.p và y.left.p giống nhau.

    Đối với dòng 2 ~ 4, bạn cũng có thể viết như thế này:

beta = y.left;
x.right = beta; 
if beta != T.nil
    beta.p = x;
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.