Thuật toán để kiểm tra xem cây nhị phân có phải là cây tìm kiếm hay không và đếm các nhánh hoàn chỉnh


10

Tôi cần tạo một thuật toán đệ quy để xem cây nhị phân có phải là cây tìm kiếm nhị phân không cũng như đếm xem có bao nhiêu nhánh hoàn chỉnh (một nút cha có cả hai nút con trái và phải) với biến đếm toàn cục giả định. Đây là một bài tập cho lớp cấu trúc dữ liệu của tôi.

Cho đến nay tôi có

void BST(tree T) {
   if (T == null) return
   if ( T.left and T.right) {
      if (T.left.data < T.data or T.right.data > T.data) {
        count = count + 1
        BST(T.left)
        BST(T.right)
      }
   }
}

Nhưng tôi thực sự không thể tìm ra cái này. Tôi biết rằng thuật toán này sẽ không giải quyết được vấn đề vì số đếm sẽ bằng 0 nếu câu lệnh thứ hai nếu không đúng.

Bất cứ ai có thể giúp tôi ra về điều này?


Làm thế nào là toán tử so sánh <được xác định trên các nút?
Joe

Bạn có muốn tính số đếm ngay cả khi nó không phải là cây tìm kiếm nhị phân không?
Joe

1
Là thuật toán của bạn có nghĩa vụ phải trả lại bất cứ điều gì, chẳng hạn như truehoặc false?
Joe

2
Có lẽ trước tiên bạn nên cố gắng xác định hai hàm riêng biệt: Một để kiểm tra xem đó có phải là BST và một để đếm các nhánh hoàn chỉnh hay không. Điều đó nên được quản lý nhiều hơn.
sepp2k

1
@OghmaOsiris Tôi tưởng tượng anh ấy nói rằng vì câu hỏi về cơ bản là "Đây là mã của tôi, làm thế nào để tôi làm cho nó hoạt động?". Nếu mã không thuộc loại giả (ish), đó chắc chắn là một câu hỏi SO.
sepp2k

Câu trả lời:


10

Như những người khác đã chỉ ra trong các bình luận, bạn thực sự có hai chức năng không liên quan ở đây: kiểm tra xem cây có phải là cây tìm kiếm hay không và đếm các nhánh hoàn chỉnh. Trừ khi bài tập đặc biệt gọi cho nó, tôi sẽ viết hai hàm riêng biệt.

Chúng ta hãy xem abount đếm các nhánh hoàn chỉnh đầu tiên. Điều đó có nghĩa là đếm các nút có cả con trái và con phải. Sau đó, bạn cần tăng bộ đếm ( count = count + 1) khi cả hai T.leftT.rightkhông null (không T.left.dataT.right.data: dữ liệu không quan trọng đối với tác vụ này).

if (T.left and T.right) {
    count = count + 1

Hơn nữa, bạn cần khám phá cây con bên trái ngay cả khi cây con bên phải trống và bạn cần khám phá cây con bên phải ngay cả khi cây con bên trái trống. Vì vậy, xem nơi bạn đặt các cuộc gọi đệ quy.

Để kiểm tra xem cây có phải là cây tìm kiếm hay không, bạn cần kiểm tra các giá trị dữ liệu. Bạn đã có một cái gì đó gần với so sánh đúng; không hoàn toàn đúng. Viết một vài cây mẫu với nhiều hình dạng khác nhau (không lớn lắm, 2 đến 5 nút) và chạy thuật toán của bạn trên chúng để xem điều gì xảy ra.

Bạn vẫn cần tìm một nơi nào đó để đặt kết quả kiểm tra tính hợp lệ. Một lần nữa, hãy xem nơi bạn thực hiện các cuộc gọi đệ quy (nếu bạn chỉ thực hiện phần này, có một số giải pháp, nhưng ở giai đoạn này, đừng lo lắng nếu bạn chỉ thấy một cuộc gọi).

Cuối cùng, một khi bạn đã quản lý để viết cả hai chức năng một cách riêng biệt và bạn đã kiểm tra chúng trên một vài ví dụ, hãy đặt chúng cẩn thận (nếu được yêu cầu bởi bài tập).


cảm ơn, tôi đã đọc lại câu hỏi và nó được cho là phương pháp riêng biệt.
OghmaOsiris

7

Trong những điều như thế này, thường dễ nghĩ ngược hơn, vì vậy trước tiên hãy xem xét những gì bạn cần. Từ mô tả của bạn, hãy liệt kê chúng:

  • Đệ quy
  • Hiệu lực
  • Đếm các nút hoàn chỉnh

OK, đó là một danh sách khá ngắn, điều này nên được quản lý. Hãy bắt đầu với một phương thức trống và tôi sẽ thêm mô tả về những gì sẽ xảy ra.

valid_bst () {
}

Bây giờ hiệu lực. Làm thế nào để bạn kiểm tra tính hợp lệ? Trong trò chuyện, bạn nói rằng một cái cây là hợp lệ "nếu ... tất cả trẻ em bên trái đều nhỏ hơn cha mẹ và trẻ em bên phải lớn hơn cha mẹ". Tôi chắc chắn rằng bạn có nghĩa là cho phép bình đẳng là tốt. Đó sẽ là t.left.value <= t.value <= t.right.value.

valid_bst () {
    This node is valid if t.left.value <= t.value <= t.right.value
}

Nhưng nếu một trong những đứa trẻ bị mất thì sao? Từ những gì bạn đã nói, tôi tin rằng bạn biết nút vẫn còn hiệu lực nếu thiếu (hoặc cả hai). Hãy thêm điều này, tái cấu trúc một chút:

valid_bst () {
    This node is valid to the left if 
        there is no left child or 
        it is no greater than the current node.
    This node is valid to the right if 
        there is no right child or 
        it is no less than the current node.
    This node is valid overall if it is valid to the left and right.
}

OK, bây giờ chúng ta biết liệu nút này có hợp lệ không. Làm thế nào để chúng ta kiểm tra xem toàn bộ cây có hợp lệ không? Nó không nằm trong một mảng, vì vậy có lẽ chúng ta không thể / không muốn lặp lại nó một cách tuyến tính. Bài tập của bạn đưa ra câu trả lời: đệ quy. Nhưng làm thế nào để chúng ta tích lũy một câu trả lời bằng cách sử dụng đệ quy? Chúng tôi có quyền truy cập vào ba mẩu thông tin, cho dù nút này có hợp lệ hay không và kết quả của các cuộc gọi hỏi xem các nút trái và phải có hợp lệ hay không. Rõ ràng cây chỉ có giá trị nếu cả ba điều đó đều đúng.

valid_bst () {
    This node is valid to the left if 
        there is no left child or 
        it is no greater than the current node.
    This node is valid to the right if 
        there is no right child or 
        it is no less than the current node.
    This node is valid overall if it is valid to the left and right.
    Is the left child valid?
    Is the right child valid?
    This tree is only valid if this node and both its children are.
}

Nếu bạn đang chú ý, điều đó thậm chí còn cho chúng ta biết chức năng của chúng ta cần trả về.

Bây giờ, làm thế nào để chúng ta tích hợp đếm? Bạn nói những gì được tính ("một nút cha có cả hai nút con trái và phải") và điều đó không khó để dịch thành mã thực tế. Kiểm tra xem điều kiện đó có được thỏa mãn hay không và tăng bộ đếm một cách thích hợp. Chỉ cần nhớ điều này phải ở một nơi nào đó sẽ đạt được mỗi khi nó là sự thật.

Và tất nhiên tôi đã bỏ qua một số chi tiết như điều kiện dừng đệ quy và kiểm tra null.


6

Ba ý kiến ​​của tôi ở trên là ba gợi ý cho các vấn đề với mã của bạn.

  1. Trừ khi bạn đã xác định cụ thể cách toán tử so sánh sẽ xử lý kiểu dữ liệu nút, rất có thể so sánh trực tiếp hai nút sẽ không làm những gì bạn muốn. Những gì bạn có thể có nghĩa là để so sánh các trường được lưu trữ trong các nút, ví dụnode1.value < node2.value
  2. ngay bây giờ, bạn chỉ thêm vào số đếm nếu thứ ba iflà đúng, bạn có chắc đó là những gì bạn muốn làm không? Nhân tiện, bạn có thể muốn kiểm tra lại rằng nếu câu lệnh thực hiện những gì bạn muốn.
  3. Tôi giả sử rằng bạn muốn trả về true nếu cây là BST hợp lệ và ngược lại là sai. Điều đó có nghĩa là bạn phải luôn trả về đúng hoặc sai trong trường hợp cơ sở và bạn cũng nên trả lại kết quả của các cuộc gọi đệ quy.

Về điểm một: Đây là mã giả, phải không? Vì vậy, miễn là ý định được truyền đạt đến người đọc, không có lý do gì để định nghĩa những thứ như thế.
sepp2k

@ sepp2k đó là sự thật, và nhận xét của tôi có lẽ hơi quá kén chọn mã giả. Tôi đoán quan điểm của tôi là chúng ta cần hiểu ý nghĩa của việc so sánh hai nút. Quan điểm của bạn là chúng ta nên hiểu điều đó một cách ngấm ngầm.
Joe

Đúng, chính xác.
sepp2k
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.