แนวคิด
สำหรับต้นไม้ไบนารีที่กำหนด ภารกิจคือการกำหนดขนาดของทรีย่อยที่สมบูรณ์สูงสุดในต้นไม้ไบนารีที่กำหนด
Complete Binary Tree – ต้นไม้ไบนารีจะถือว่าเป็นต้นไม้ไบนารีที่สมบูรณ์ หากระดับทั้งหมดถูกเติมเต็มโดยสมบูรณ์โดยไม่มีระดับสุดท้ายและระดับสุดท้ายมีคีย์ทั้งหมดที่เหลืออยู่เท่าที่จะเป็นไปได้ มีข้อสังเกตว่าต้นไม้ไบนารีที่สมบูรณ์แบบทั้งหมดเป็นต้นไม้ไบนารีที่สมบูรณ์ แต่ ย้อนกลับในไม่จริง จะเห็นได้ว่าถ้าต้นไม้ไม่สมบูรณ์ มันก็จะไม่ใช่ Perfect Binary Tree ด้วย
ป้อนข้อมูล
2 / \ 3 4 / \ / \ 5 6 7 8 / \ / 9 10 11
ผลผลิต
Size : 10 Inorder Traversal : 9 5 10 3 11 6 2 7 4 8 The above given tree is a complete binary tree.
ป้อนข้อมูล
51 / \ 31 61 / \ / \ 6 21 46 71 / 11
ผลผลิต
Size : 4(With respect of right subtree) Inorder Traversal : 11 46 61 71 The above given tree is not a complete binary tree.
วิธีการ
เพียงแค่เยี่ยมชมต้นไม้ในลักษณะจากล่างขึ้นบน ต่อไปเกี่ยวกับการเรียกซ้ำจาก child ไปยัง parent เราสามารถถ่ายโอนข้อมูลเกี่ยวกับ sub-tree ไปยัง parent พาเรนต์สามารถใช้ข้อมูลที่ถ่ายโอนเพื่อทำการทดสอบทรีสมบูรณ์ (สำหรับโหนดพาเรนต์) ในเวลาคงที่เท่านั้น ในกรณีนี้ ต้นไม้ย่อยทั้งซ้ายและขวาจำเป็นต้องบอกข้อมูลพาเรนต์ว่าสมบูรณ์หรือไม่สมบูรณ์หรือไม่ และยังต้องส่งคืนขนาดสูงสุดของต้นไม้ไบนารีที่สมบูรณ์ที่พบจนถึงปัจจุบัน
เราควรสังเกตว่าแผนผังย่อยจำเป็นต้องถ่ายโอนข้อมูลต่อไปนี้ขึ้นบนทรีเพื่อกำหนดโครงสร้างย่อยที่สมบูรณ์ที่ใหญ่ที่สุด เพื่อให้เราสามารถเปรียบเทียบขนาดสูงสุดกับข้อมูลของพาเรนต์เพื่อตรวจสอบคุณสมบัติ Complete Binary Tree
-
ควรมีตัวแปรบูลเพื่อตรวจสอบว่าทรีย่อยด้านซ้ายหรือแผนผังย่อยย่อยที่ถูกต้องสมบูรณ์และสมบูรณ์หรือไม่
-
อีกครั้ง เราต้องตรวจสอบอีกครั้งว่าจากการเรียกลูกซ้ายและขวาในการเรียกซ้ำ เราจะพบว่าทรีย่อยพาเรนต์เสร็จสมบูรณ์หรือไม่โดยทำตาม 3 กรณี -
-
จะเห็นได้ว่าหากทรีย่อยด้านซ้ายสมบูรณ์และด้านขวาสมบูรณ์ และมีความสูงเท่ากัน รูทของทรีย่อยก็จะถือว่าเป็นทรีย่อยแบบไบนารีที่สมบูรณ์ด้วยขนาดเท่ากับผลรวมของทรีย่อยด้านซ้ายและขวาบวกหนึ่ง (สำหรับรูทปัจจุบัน)
-
จะเห็นได้ว่าถ้าทรีย่อยด้านซ้ายสมบูรณ์และด้านขวาสมบูรณ์ และความสูงของด้านซ้ายมากกว่าด้านขวาทีละหนึ่ง รูทของทรีย่อยย่อยก็จะเป็นทรีย่อยแบบไบนารีที่สมบูรณ์โดยมีขนาดเท่ากับผลรวมของทรีย่อยด้านซ้ายและขวา บวกหนึ่ง (สำหรับรูทปัจจุบัน) . แต่ไม่สามารถประกาศทรีย่อยของรูทเป็นทรีย่อยไบนารีที่สมบูรณ์แบบได้ เพราะในกรณีนี้ ลูกด้านซ้ายของมันไม่สมบูรณ์แบบ
-
มิฉะนั้นทรีย่อยนี้ไม่สามารถถือเป็นไบนารีทรีที่สมบูรณ์ได้ และเพียงแค่ส่งคืนทรีย่อยที่สมบูรณ์ที่มีขนาดที่ใหญ่ที่สุดเท่าที่พบจนถึงขณะนี้ในทรีย่อยทางซ้ายหรือขวา ดังนั้นสรุปได้ว่าหากทรีไม่สมบูรณ์ ก็ไม่เป็นเช่นนั้น สมบูรณ์แบบอีกด้วย
-
ตัวอย่าง
//This is a C++ implementation of the approach #include <bits/stdc++.h> using namespace std; // Node structure of the tree struct node1 { int data; struct node1* left; struct node1* right; }; // For creating a new node struct node1* newNode(int data){ struct node1* node1 = (struct node1*)malloc(sizeof(struct node1)); node1->data = data; node1->left = NULL; node1->right = NULL; return node1; }; // Shows structure for return type of // function findPerfectBinaryTree struct returnType { // For storing if sub-tree is perfect or not bool isPerfect; // For storing if sub-tree is complete or not bool isComplete; // Indicates size of the tree int size1; // Root of biggest complete sub-tree node1* rootTree; }; // Shows helper function that returns height // of the tree given size int getHeight(int size1){ return ceil(log2(size1 + 1)); } // Shows function to return the biggest // complete binary sub-tree returnType findCompleteBinaryTree(struct node1* root){ // Declaring returnType that // needs to be returned returnType rt1; // If root is NULL then it is considered as both // perfect and complete binary tree of size 0 if (root == NULL) { rt1.isPerfect = true; rt1.isComplete = true; rt1.size1 = 0; rt1.rootTree = NULL; return rt1; } // Shows recursive call for left and right child returnType lv1 = findCompleteBinaryTree(root->left); returnType rv1 = findCompleteBinaryTree(root->right); // CASE - A // It has been seen that if left sub-tree is perfect and right is // complete and there height is also same then sub-tree root // is also complete binary sub-tree with size equal to // sum of left and right subtrees plus one for current root if (lv1.isPerfect == true && rv1.isComplete == true && getHeight(lv1.size1) == getHeight(rv1.size1)) { rt1.isComplete = true; // It has been seen that if right sub-tree is perfect then // root is also perfect rt1.isPerfect = (rv1.isPerfect ? true : false); rt1.size1 = lv1.size1 + rv1.size1 + 1; rt1.rootTree = root; return rt1; } // CASE - B // It has been seen if left sub-tree is complete and right is // also perfect and the left height is greater than height of right by one // then sub-tree root will be a complete binary sub-tree with the size equal to // sum of left and right subtrees plus one for current root. // But sub-tree cannot be perfect binary sub-tree. if (lv1.isComplete == true && rv1.isPerfect == true && getHeight(lv1.size1) == getHeight(rv1.size1) + 1) { rt1.isComplete = true; rt1.isPerfect = false; rt1.size1 = lv1.size1 + rv1.size1 + 1; rt1.rootTree = root; return rt1; } // CASE - C // Otherwise this sub-tree cannot be a complete binary tree // and simply return the biggest sized complete sub-tree // found till now in the left or right sub-trees rt1.isPerfect = false; rt1.isComplete = false; rt1.size1 = max(lv1.size1, rv1.size1); rt1.rootTree = (lv1.size1 > rv1.size1 ? lv1.rootTree : rv1.rootTree); return rt1; } // Shows function to print the inorder traversal of the tree void inorderPrint(node1* root){ if (root != NULL) { inorderPrint(root->left); cout << root->data << " "; inorderPrint(root->right); } } // Driver code int main(){ // Creating the tree struct node1* root = newNode(50); root->left = newNode(30); root->right = newNode(60); root->left->left = newNode(5); root->left->right = newNode(20); root->right->left = newNode(45); root->right->right = newNode(70); root->right->left->left = newNode(10); // Getting the biggest sized complete binary sub-tree struct returnType ans1 = findCompleteBinaryTree(root); cout << "Size : " << ans1.size1 << endl; // Printing the inorder traversal of the found sub-tree cout << "Inorder Traversal : "; inorderPrint(ans1.rootTree); return 0; }
ผลลัพธ์
Size : 4 Inorder Traversal : 10 45 60 70