Algoritma untuk menguji apakah pohon biner adalah pohon pencarian dan menghitung cabang lengkap

10

Saya perlu membuat algoritma rekursif untuk melihat apakah pohon biner adalah pohon pencarian biner serta menghitung berapa banyak cabang lengkap yang ada (simpul orangtua dengan simpul anak kiri dan kanan) dengan asumsi variabel penghitungan global. Ini adalah tugas untuk kelas struktur data saya.

Sejauh ini saya punya

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

Tetapi saya tidak dapat benar-benar memahami hal ini. Saya tahu bahwa algoritma ini tidak akan menyelesaikan masalah karena hitungannya akan nol jika pernyataan kedua jika tidak benar.

Adakah yang bisa membantu saya dalam hal ini?

OghmaOsiris
sumber
Bagaimana operator membandingkan <didefinisikan pada node?
Joe
Apakah Anda ingin menghitung hitungan meskipun itu bukan pohon pencarian biner?
Joe
1
Apakah algoritma Anda seharusnya mengembalikan sesuatu, seperti trueatau false?
Joe
2
Mungkin Anda harus mencoba mendefinisikan dua fungsi terpisah: Satu untuk memeriksa apakah itu BST dan satu untuk menghitung cabang lengkap. Itu harus lebih mudah dikelola.
sepp2k
1
@OghmaOsiris Saya membayangkan dia mengatakan itu karena pertanyaannya pada dasarnya "Ini kode saya, bagaimana cara membuatnya berfungsi?". Jika kodenya bukan dari variasi pseudo (ish), itu pasti akan menjadi pertanyaan SO.
sepp2k

Jawaban:

10

Seperti yang telah ditunjukkan orang lain dalam komentar, Anda benar-benar memiliki dua fungsi yang tidak terkait di sini: menguji apakah pohon itu adalah pohon pencarian, dan menghitung cabang lengkap. Kecuali jika penugasan secara khusus memanggilnya, saya akan menulis dua fungsi terpisah.

Mari kita lihat jumlah menghitung cabang lengkap terlebih dahulu. Itu berarti menghitung node yang memiliki anak kiri dan anak kanan. Maka Anda perlu menambah penghitung ( count = count + 1) saat keduanya T.leftdan T.rightbukan nol (tidak T.left.datadan T.right.data: data tidak masalah untuk tugas ini).

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

Selanjutnya, Anda perlu menjelajahi subtree kiri bahkan jika subtree kanan kosong, dan Anda perlu menjelajahi subtree kanan bahkan jika subtree kiri kosong. Jadi perhatikan di mana Anda melakukan panggilan rekursif.

Untuk menguji apakah pohon itu pohon pencarian, Anda perlu memeriksa nilai data. Anda sudah mendapatkan sesuatu yang dekat dengan perbandingan yang tepat; tidak benar. Tulis beberapa pohon contoh dengan berbagai bentuk (tidak terlalu besar, 2 hingga 5 node) dan jalankan algoritma Anda pada mereka untuk melihat apa yang terjadi.

Anda masih perlu menemukan tempat untuk meletakkan hasil pemeriksaan validitas. Sekali lagi, perhatikan di mana Anda melakukan panggilan rekursif (jika Anda hanya melakukan bagian ini, ada beberapa solusi, tetapi pada tahap ini jangan khawatir jika Anda hanya melihat satu).

Terakhir, setelah Anda berhasil menulis kedua fungsi secara terpisah, dan Anda telah mengujinya pada beberapa contoh, kumpulkan semuanya dengan hati-hati (jika diperlukan oleh penugasan).

Gilles 'SANGAT berhenti menjadi jahat'
sumber
terima kasih, saya membaca kembali pertanyaannya dan itu seharusnya menjadi metode yang terpisah.
OghmaOsiris
7

Dalam hal-hal seperti ini, seringkali lebih mudah untuk berpikir mundur, jadi pertimbangkan dulu apa yang Anda butuhkan. Dari deskripsi Anda, mari daftarkan mereka:

  • Pengulangan
  • Keabsahan
  • Hitungan node lengkap

OK, itu daftar yang cukup singkat, ini harus dapat dikelola. Mari kita mulai dengan metode kosong dan saya akan menambahkan deskripsi tentang apa yang seharusnya terjadi.

valid_bst () {
}

Sekarang validitas. Bagaimana Anda memeriksa validitas? Dalam obrolan Anda mengatakan pohon itu valid "jika ... semua anak yang tersisa lebih kecil dari orang tua, dan anak yang tepat lebih besar dari orang tua." Saya yakin Anda bermaksud untuk mengizinkan kesetaraan juga. Itu pasti t.left.value <= t.value <= t.right.value.

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

Tetapi bagaimana jika salah satu dari anak-anak itu hilang? Dari apa yang Anda katakan, saya yakin Anda tahu simpul masih valid jika salah satu (atau keduanya) hilang. Mari kita tambahkan ini, restrukturisasi sedikit:

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, kita sekarang tahu apakah simpul ini valid. Bagaimana kita memeriksa apakah seluruh pohon itu valid? Itu tidak ada dalam array, jadi kita mungkin tidak bisa / tidak ingin mengulanginya secara linear. Tugas Anda memberikan jawabannya: rekursi. Tetapi bagaimana kita mengumpulkan jawaban menggunakan rekursi? Kami memiliki akses ke tiga informasi, apakah simpul ini valid, dan hasil panggilan yang menanyakan apakah simpul kiri dan kanan itu valid. Jelas pohon itu hanya valid jika ketiganya benar.

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.
}

Jika Anda memperhatikan, itu bahkan memberi tahu kami apa yang harus dikembalikan oleh fungsi kami.

Sekarang, bagaimana kita mengintegrasikan penghitungan? Anda mengatakan apa yang diperhitungkan ("simpul orangtua dengan simpul anak kiri dan kanan"), dan itu seharusnya tidak sulit untuk diterjemahkan ke dalam kode aktual. Periksa apakah kondisi itu terpenuhi dan tambahkan penghitung dengan tepat. Ingat saja ini harus di suatu tempat di mana ia akan tercapai setiap kali itu benar.

Dan tentu saja saya telah meninggalkan beberapa detail seperti kondisi berhenti rekursi dan memeriksa nol.

Kevin
sumber
6

Tiga komentar saya di atas adalah tiga petunjuk untuk masalah dengan kode Anda.

  1. Kecuali Anda telah menentukan secara spesifik bagaimana operator pembanding harus menangani tipe data node, kemungkinan besar membandingkan dua node secara langsung tidak akan melakukan apa yang Anda inginkan. Apa yang mungkin Anda maksudkan adalah membandingkan bidang yang disimpan dalam node, misalnyanode1.value < node2.value
  2. saat ini, Anda hanya menambah hitungan jika yang ketiga ifbenar, apakah Anda yakin itu yang ingin Anda lakukan? By the way, Anda mungkin ingin memeriksa bahwa jika pernyataan melakukan apa yang Anda inginkan.
  3. Saya berasumsi bahwa Anda ingin mengembalikan true jika pohon itu adalah BST yang valid dan salah sebaliknya. Yang berarti bahwa Anda harus selalu mengembalikan benar atau salah dalam kasus dasar, dan Anda harus mengembalikan hasil panggilan rekursif Anda juga.
Joe
sumber
Mengenai poin satu: Ini adalah kode palsu, bukan? Jadi selama maksudnya disampaikan kepada pembaca, tidak ada alasan untuk mendefinisikan hal-hal seperti itu.
sepp2k
@ sepp2k itu benar, dan komentar saya mungkin agak terlalu pilih-pilih untuk pseudo-code. Saya kira maksud saya adalah bahwa kita perlu memahami apa artinya membandingkan dua node. Maksud Anda adalah bahwa kita harus memahami hal itu secara implisit.
Joe
Tepat, tepatnya.
sepp2k