2013-11-25 22 views
6

Tôi đã gặp sự cố khi viết mã để xóa một nút khỏi cây.Các vấn đề về Cây tìm kiếm nhị phân trong Clojure (cấu trúc không thay đổi)

cho BST và giá trị khóa, tìm khóa trong cây và xóa nó.

vì vậy đây là ý tưởng của tôi, đầu tiên, nếu BST là nil sau đó trở về nil và nếu BST chỉ có một nút gốc, sau đó trả lại nil là tốt.

Và sau đó nếu một khóa trong BST khớp với khóa đã cho, hãy kiểm tra số lượng lá mà nút này có. nếu nút không có con nào cả, sau đó tạo lại một bst từ người tiền nhiệm đầu tiên (gốc) đến người tiền nhiệm cuối cùng của nút này và chia sẻ tất cả dữ liệu còn lại không phải là tiền thân.

nếu nút có một con, coi là con không có con, nhưng chỉ cần thêm con vào người tiền nhiệm cuối cùng.

cho nút có hai con, tôi phải tìm một số nút không có bất kỳ con nào để thay thế vị trí của chúng.

phần cứng xuất hiện khi viết mã, tôi không thực sự bây giờ cách tạo và chia sẻ dữ liệu của cây.

để ai đó có thể đưa ra một số gợi ý hoặc đầu mối?

+0

Bạn đã xem xét dây kéo chưa? –

+0

@ lgrapenthin, bạn có nghĩa là sử dụng dây kéo để lưu trữ thông tin? – Landey

+0

tôi thành thật không có đầu mối nào cả về cách tạo lại cây trong khi chia sẻ dữ liệu. @ lgrapenthin – Landey

Trả lời

3

Dường như với tôi giống như bạn khá nhiều, nhưng chỉ cần một chút trợ giúp với các chi tiết. Vì vậy, giả sử bạn có một số cấu trúc nút và chức năng sau để hoạt động trên nó:

  • (left-subtree [node]) - trả về cây con trái của node, hoặc nil nếu node không có cây con trái
  • (right-subtree [node]) - trả về cây con phải của node hoặc nil nếu node không có cây con phù hợp.
  • (value [node]) - trả về giá trị gắn liền với node
  • (leaf? [node]) - trả true nếu node là một chiếc lá, nếu không false.

Bây giờ chúng ta hãy viết một hàm without-root mà phải mất một (sub) cây và trả về một cây mới có chứa tất cả mọi thứ trong cây gốc trừ nút gốc của nó:

(defn without-root [node] 
    (cond (leaf? node) nil ; resulting tree is the empty tree, return nil 
     (and (left-subtree node) ; two children, "difficult" case 
      (right-subtree node)) (handle-difficult-case node) 
     ;; cases for single child 
     (left-subtree node) (left-subtree node) 
     (right-subtree node) (right-subtree node))) 

Như bạn nêu trong câu hỏi, trường hợp "khó" là khi node có hai con. Vì vậy, tôi đã quyết định chia nó ra thành một chức năng riêng biệt để tạo điều kiện thảo luận.

Vì vậy, hãy nói về handle-difficult-case. Vì có hai đứa con, chúng ta bằng cách nào đó cần phải kết hợp chúng thành một cây duy nhất. Nếu bạn đọc Wikipedia nói gì về BST Deletion, về cơ bản bạn muốn chọn người tiền nhiệm hoặc người thừa kế theo thứ tự (nghĩa là nút ngoài cùng bên phải của cây con trái hoặc nút ngoài cùng bên trái của cây con bên phải) và biến nó thành thư mục gốc mới . Nó không quan trọng bạn chọn cái nào - dù là ai cũng sẽ làm. Vì mục đích của cuộc thảo luận này, chúng ta sẽ chọn nút cao nhất của cây con trái.

Bây giờ chúng ta có thể viết một hàm mới, without-rightmost-node, có thể chấp nhận một cây và trả về một cây mới mà không có nút ngoài cùng bên phải của nó. Tuy nhiên, chúng tôi cũng cần giá trị được lưu trữ trong nút đó. Vì vậy, chúng ta sẽ cần phải gọi một cách độc lập một số chức năng find-rightmost-node để nhận giá trị của nó (sẽ không hiệu quả) hoặc trả về giá trị cùng với cây mới (sẽ làm lệch mục đích của hàm). Thay vào đó, hãy viết một hàm chấp nhận một cây và trả về một cây mới tương đương với cây gốc, ngoại trừ gốc của nó là nút ngoài cùng bên phải của cây gốc. Để giải trí, hãy gọi hàm này percolate-rightmost-node vì, như chúng ta sẽ thấy, nút ngoài cùng bên phải sẽ đệ quy "bong bóng lên" lên trên cùng của cây (phụ).

(defn percolate-rightmost-node [node] 
    (if-let [right-side (right-subtree node)] 
    ;; then (recurse down the right side) 
    (let [percolated (percolate-rightmost-node right-side)] 
     ;; Construct a new tree from the result. 
     (with-left-subtree percolated 
         (with-right-subtree node (left-subtree percolated)))) 
    ;; else (we are at the rightmost node -- return it!) 
    node)) 

Tôi cảm thấy mặt "sau đó" của biểu thức if-let không rõ ràng, vì vậy hãy để tôi giải thích một chút. Về cơ bản, chúng tôi lấy các phụ tùng percolated, có được subtree trái (đó là con duy nhất của percolated) và thay thế nó cho subtree quyền của node. Sau đó chúng tôi lấy kết quả đó và thay thế nó cho cây con trái của percolated (hiệu quả tái rễ cây), tạo ra kết quả cuối cùng.

Đầu ra của percolate-rightmost-node sẽ chỉ có một cây con trái - nó sẽ không bao giờ có một cây con phù hợp. Vì vậy, sau khi kết quả đã hoàn thành "sủi bọt", chúng tôi chỉ cần cung cấp cho nó một cây con ngay. Do đó, chúng tôi có thể triển khai handle-difficult-case là:

(defn handle-difficult-case [node] 
    (let [percolated (-> node   ; Find the rightmost node of the left 
         (left-subtree) ; subtree and "percolate" it to the top 
         (percolate-rightmost-node))] 
    ;; Now take the percolated tree. Its right subtree is empty, 
    ;; so substitute in the right subtree of node. 
    (with-right-subtree percolated 
         (right-subtree node)))) 

Và điều đó phải là vậy. Tất nhiên, bạn sẽ cần phải điều chỉnh điều này để mã của bạn (tối thiểu, hoặc là nội tuyến handle-difficult-case hoặc cung cấp cho nó một tên thích hợp). Nhưng hy vọng rằng sẽ giúp bạn bắt đầu.

Làm trống caveat: Tôi đã không cố gắng kiểm tra mã được đưa ra trong câu trả lời này. Sửa chữa được hoan nghênh!

2

Đây sẽ là câu trả lời dài, vì vậy hãy để tôi xin lỗi trước vì đã chỉ cho bạn hướng tới một cuốn sách và không trả lời trực tiếp. Tôi rất khuyên bạn nên xem Purely Functional Data Structures được (theo luật) có sẵn dưới dạng PDF từ tác giả. Mặc dù đó là một cuốn sách tốt để có trong print/ebook anyway.

và câu trả lời siêu ngắn được sử dụng Clojure được xây dựng trong sorted-map nếu bạn muốn điều này trong thực tế (mặc dù viết tất nhiên của riêng bạn sẽ nhận được nerd-street-cred) vì bản đồ được sắp xếp sử dụng một cây nhị phân màu đỏ-đen dưới mui xe

Các vấn đề liên quan