แนวคิด
สำหรับต้นไม้ไบนารีที่กำหนด ภารกิจคือการกำหนดขนาดของทรีย่อยที่สมบูรณ์สูงสุดในต้นไม้ไบนารีที่กำหนด
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