อัลกอริทึมเพื่อทดสอบว่าต้นไม้ไบนารีเป็นต้นไม้ค้นหาและนับสาขาเสร็จสมบูรณ์หรือไม่


10

ฉันต้องสร้างอัลกอริทึมแบบเรียกซ้ำเพื่อดูว่าต้นไม้ไบนารีเป็นต้นไม้ค้นหาแบบไบนารีรวมทั้งนับจำนวนสาขาที่สมบูรณ์ (โหนดแม่ที่มีโหนดลูกทั้งซ้ายและขวา) พร้อมตัวแปรการนับทั่วโลก นี่คือการมอบหมายสำหรับคลาสโครงสร้างข้อมูลของฉัน

จนถึงตอนนี้ฉันมี

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

แต่ฉันไม่สามารถหาอันนี้ได้ ฉันรู้ว่าอัลกอริทึมนี้จะไม่แก้ปัญหาเพราะการนับจะเป็นศูนย์ถ้าที่สองถ้าคำสั่งไม่เป็นความจริง

ใครช่วยฉันออกจากนี้


ตัวดำเนินการเปรียบเทียบ<ถูกกำหนดบนโหนดอย่างไร
Joe

คุณต้องการคำนวณการนับแม้ว่ามันจะไม่ใช่แผนภูมิการค้นหาแบบไบนารีหรือไม่?
Joe

1
อยู่ในขั้นตอนวิธีการของคุณควรจะกลับอะไรเช่นtrueหรือfalse?
Joe

2
บางทีคุณควรลองกำหนดฟังก์ชั่นแยกกันสองฟังก์ชัน: อันแรกสำหรับการตรวจสอบว่าเป็น BST หรือไม่และอีกอันสำหรับการนับกิ่งที่สมบูรณ์ ควรจัดการได้มากกว่านี้
sepp2k

1
@OghmaOsiris ฉันคิดว่าเขาพูดว่าเพราะคำถามคือ "นี่คือรหัสของฉันฉันจะทำให้มันทำงานได้อย่างไร" หากรหัสไม่ได้มาจากความหลากหลายหลอก (ish) มันจะเป็นคำถาม SO แน่นอน
sepp2k

คำตอบ:


10

ดังที่คนอื่น ๆ ได้ระบุไว้ในความคิดเห็นคุณมีสองฟังก์ชั่นที่ไม่เกี่ยวข้องที่นี่: ทดสอบว่าต้นไม้เป็นต้นไม้ค้นหาและนับสาขาที่สมบูรณ์ ฉันจะเขียนสองฟังก์ชั่นแยกกัน

เรามาดูการนับจำนวนกิ่งที่สมบูรณ์ก่อน นั่นหมายถึงการนับโหนดที่มีทั้งลูกซ้ายและลูกขวา จากนั้นคุณต้องเพิ่มตัวนับ ( count = count + 1) เมื่อทั้งคู่T.leftและT.rightไม่เป็นโมฆะ (ไม่ใช่T.left.dataและT.right.data: ข้อมูลไม่สำคัญสำหรับงานนี้)

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

นอกจากนี้คุณต้องสำรวจทรีย่อยด้านซ้ายแม้ว่าทรีย่อยด้านขวาจะว่างเปล่าและคุณต้องสำรวจทรีย่อยด้านขวาแม้ว่าทรีย่อยด้านซ้ายจะว่างเปล่า ดังนั้นดูที่ที่คุณโทรหาแบบเรียกซ้ำ

ในการทดสอบว่าแผนผังนั้นเป็นแผนผังการค้นหาหรือไม่คุณต้องตรวจสอบค่าข้อมูล คุณมีบางสิ่งบางอย่างใกล้เคียงกับการเปรียบเทียบที่ถูกต้องแล้ว ไม่ถูกต้องนัก เขียนตัวอย่างต้นไม้ที่มีรูปร่างต่าง ๆ (ไม่ใหญ่มาก 2 ถึง 5 โหนด) และเรียกใช้อัลกอริทึมของคุณเพื่อดูว่าเกิดอะไรขึ้น

คุณยังต้องหาสถานที่เพื่อนำผลการตรวจสอบความถูกต้องมาใช้ อีกครั้งดูที่คุณโทรซ้ำ (ถ้าคุณเพียงแค่ทำส่วนนี้มีหลายวิธี แต่ในขั้นตอนนี้ไม่ต้องกังวลถ้าคุณเห็นเพียงหนึ่ง)

สุดท้ายเมื่อคุณจัดการเขียนทั้งสองฟังก์ชั่นแยกจากกันและคุณได้ทดสอบกับตัวอย่างสองสามข้อให้รวมเข้าด้วยกันอย่างระมัดระวัง (หากจำเป็นต้องได้รับมอบหมาย)


ขอบคุณฉันอ่านคำถามอีกครั้งและมันควรจะเป็นวิธีการแยก
OghmaOsiris

7

ในสิ่งต่าง ๆ เช่นนี้มักจะคิดย้อนกลับง่ายกว่าดังนั้นก่อนอื่นให้พิจารณาสิ่งที่คุณต้องการ จากคำอธิบายของคุณมาแสดงรายการพวกเขา:

  • recursion
  • ความถูกต้อง
  • จำนวนโหนดที่สมบูรณ์

ตกลงนั่นเป็นรายการที่ค่อนข้างสั้นซึ่งควรจัดการได้ เริ่มกันด้วยวิธีที่ว่างเปล่าแล้วฉันจะเพิ่มคำอธิบายของสิ่งที่ควรจะเกิดขึ้น

valid_bst () {
}

ตอนนี้มีผลบังคับใช้ คุณตรวจสอบความถูกต้องได้อย่างไร ในการแชทคุณกล่าวว่าต้นไม้มีผลบังคับใช้ "ถ้า ... เด็กที่เหลือทั้งหมดน้อยกว่าผู้ปกครองและเด็กที่ถูกต้องมากกว่าผู้ปกครอง" ฉันแน่ใจว่าคุณหมายถึงการให้ความเท่าเทียมกันเช่นกัน t.left.value <= t.value <= t.right.valueที่จะเป็น

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

แต่ถ้าเด็กคนใดคนหนึ่งหายไป จากสิ่งที่คุณพูดฉันเชื่อว่าคุณรู้ว่าโหนดนั้นยังคงใช้ได้หากไม่มี (หรือทั้งสองอย่าง) ขาดหายไป ลองเพิ่มสิ่งนี้ปรับโครงสร้างเล็กน้อย:

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

ตกลงตอนนี้เรารู้ว่าโหนดนี้ถูกต้อง เราจะตรวจสอบว่าต้นไม้ทั้งหมดถูกต้องได้อย่างไร มันไม่ได้อยู่ในอาร์เรย์ดังนั้นเราอาจจะไม่สามารถ / ไม่ต้องการวนซ้ำมันเป็นเส้นตรง การมอบหมายของคุณให้คำตอบ: การเรียกซ้ำ แต่เราจะสะสมคำตอบโดยใช้การเรียกซ้ำได้อย่างไร เราสามารถเข้าถึงข้อมูลสามส่วนไม่ว่าจะเป็นโหนดนี้ถูกต้องและผลของการโทรถามว่าโหนดซ้ายและขวานั้นถูกต้องหรือไม่ เห็นได้ชัดว่าต้นไม้จะใช้ได้ก็ต่อเมื่อทั้งสามนั้นเป็นจริง

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

หากคุณให้ความสนใจนั่นคือสิ่งที่บอกเราถึงสิ่งที่ฟังก์ชั่นของเราต้องการที่จะกลับมา

ตอนนี้เราจะรวมการนับได้อย่างไร คุณพูดสิ่งที่นับ ("โหนดหลักที่มีโหนดลูกทั้งซ้ายและขวา") และไม่ควรแปลเป็นรหัสจริงได้ยาก ตรวจสอบว่าเงื่อนไขนั้นเป็นที่น่าพอใจและเพิ่มเคาน์เตอร์อย่างเหมาะสม เพียงจำไว้ว่าสิ่งนี้จะต้องอยู่ที่ไหนสักแห่งที่จะไปถึงทุกครั้งที่เป็นจริง

และแน่นอนฉันได้ละรายละเอียดบางอย่างเช่นเงื่อนไขการหยุดซ้ำและการตรวจสอบค่าว่าง


6

ความคิดเห็นสามข้อของฉันด้านบนเป็นคำแนะนำสามประการเกี่ยวกับปัญหาของรหัสของคุณ

  1. เว้นแต่ว่าคุณได้กำหนดไว้เป็นพิเศษว่าตัวดำเนินการเปรียบเทียบควรจัดการกับชนิดข้อมูลของโหนดได้อย่างไรการเปรียบเทียบสองโหนดโดยตรงจะไม่ทำในสิ่งที่คุณต้องการ สิ่งที่คุณอาจหมายถึงคือการเปรียบเทียบเขตข้อมูลที่เก็บไว้ในโหนดตัวอย่างเช่นnode1.value < node2.value
  2. ตอนนี้คุณแค่เพิ่มจำนวนถ้าอันดับที่สามifเป็นจริงคุณแน่ใจหรือไม่ว่าคุณต้องการทำเช่นนั้น? โดยวิธีการที่คุณอาจต้องการตรวจสอบอีกครั้งว่าถ้าคำสั่งทำในสิ่งที่คุณต้องการ
  3. ฉันคิดว่าคุณต้องการกลับจริงถ้าต้นไม้เป็น BST ที่ถูกต้องและเท็จอย่างอื่น ซึ่งหมายความว่าคุณต้องส่งคืนจริงหรือเท็จเสมอในกรณีพื้นฐานและคุณควรส่งคืนผลลัพธ์ของการโทรซ้ำด้วย

เกี่ยวกับประเด็นที่หนึ่ง: นี่คือรหัสปลอมใช่ไหม ดังนั้นตราบใดที่ความตั้งใจถูกสื่อไปยังผู้อ่านก็ไม่มีเหตุผลที่จะกำหนดสิ่งต่าง ๆ เช่นนั้น
sepp2k

@ sepp2k นั้นเป็นจริงและความคิดเห็นของฉันอาจจะเกินไปจู้จี้จุกจิกสำหรับหลอกรหัส ฉันเดาว่าประเด็นของฉันคือเราต้องเข้าใจความหมายของการเปรียบเทียบสองโหนด ประเด็นของคุณคือเราควรเข้าใจแล้วโดยปริยาย
Joe

ถูกต้องแน่นอน
sepp2k
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.