问题: 给定两个binary trees, check 第一个二叉树是否为第二个二叉树的子树。
例如, 如下:
Tree S 10 / \ 4 6 \ 30
Tree T 26 / \ 10 3 / \ \ 4 6 3 \ 30则 S是T的子树。
解决办法:
(simple solution)对T进行preorder的traversal, 对于每一个visited node, 我们检查以这个节点为node的根的subtree 是否和S 是identical的。 程序如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
// a binary tree node has data, left child,
// and right child
struct node {
int data;
node* left;
node* right;
};
// a utility function to check whether trees with
// roots as root1 and root2 are identical
bool areIdentical(node* root1, node* root2) {
// base case
if(root1 == NULL && root2 == NULL)
return true;
if(root1 == NULL || root2 == NULL)
return false;
// check if the data of both roots is the same and
// data on left and right subtrees are identical or not
return (root1 -> data == root2 -> data &&
areIdentical(root1 -> left, root2 -> left) &&
areIdentical(root1 -> right, root2 -> right));
}
// this function returns if S is subtree of T,
// otherwise, false
bool isSubtree(node* T, node* S) {
// base case
if(S == NULL)
return false;
if(T == NULL)
return false;
// check the tree with root as the current node
if(areIdentical(T, S))
return true;
// if the tree with root as current node doesnot
// match them, try left ans right subtree one by one
return isSubtree(T -> left, S) || isSubtree(T -> right, S);
}
// helper function that allocates a new node with
// with given data
node* newNode(int data) {
node* Node = new node;
Node -> data = data;
Node -> left = NULL;
Node -> right = NULL;
return Node;
}
/* Driver program to test above function */
int main()
{
/* Construct the following tree
26
/ \
10 3
/ \ \
4 6 3
\
30
*/
struct node *T = newNode(26);
T->right = newNode(3);
T->right->right = newNode(3);
T->left = newNode(10);
T->left->left = newNode(4);
T->left->left->right = newNode(30);
T->left->right = newNode(6);
/* Construct the following tree
10
/ \
4 6
\
30
*/
struct node *S = newNode(10);
S->right = newNode(6);
S->left = newNode(4);
S->left->right = newNode(30);
if (isSubtree(T, S))
printf("Tree S is subtree of tree T");
else
printf("Tree S is not a subtree of tree T");
return 0;
}
运行结果:
Time complexity: worst case: O(mn), 其中m, n分别是给定的两棵树的节点数。
注意, 上面的算法的复杂度太高了。 我们下面采用一个更加高效的办法。
这个简单的方法的时间复杂度为O(n)。
思路是基于这样的一个事实。
中序遍历(in order traversal) + 前序遍历/后序遍历 能够唯一的identify一个二叉树。 也就是说, 当对S进行中序遍历和前序遍历(或者换成后续遍历)得到两个字符串, 分别是对T进行对应遍历得到的两个字符串的子字符串的时候, 那么S是T的子树。 具体实现步骤如下:
(1)对T进行前序和中序遍历, 将遍历的结果分别存放在两个辅助数组 inT[] 和 preT[]。
(2)对待检测的子树S进行前序和中序遍历, 将遍历的结果分别存放在 inS[] 和 perS[]。
(4) 如果 inS 是 inT[] 的子数组, 并且 preS[] 是 preT[] 的子数组, 那么我们就说S是T的子树。
Inorder and Preorder traversals of the big tree are. inT[] = {a, c, x, b, z, e, k} preT[] = {z, x, a, c, b, e, k} Inorder and Preorder traversals of small tree are inS[] = {a, c, x, b} preS[] = {x, a, c, b} We can easily figure out that inS[] is a subarray of inT[] and preS[] is a subarray of preT[].
EDIT
The above algorithm doesn't work for cases where a tree is present in another tree, but not as a subtree. Consider the following example. Tree1 x / \ a b / c Tree2 x / \ a b / \ c d Inorder and Preorder traversals of the big tree or Tree2 are. Inorder and Preorder traversals of small tree or Tree1 are The Tree2 is not a subtree of Tree1, but inS[] and preS[] are subarrays of inT[] and preT[] respectively.程序代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int MAX = 100;
// structure of a tree node
struct Node {
char key;
Node* left;
Node* right;
};
// a utility function to create a new
// binary tree node
Node* newNode(char data) {
Node* temp = new Node;
temp -> key = data;
temp -> left = NULL;
temp -> right = NULL;
return temp;
}
// a utility function to store inorder traversal
// of tree rooted with root in an array arr[].
// note that i is pass by reference
void storeInorder(Node* root, char arr[], int&i) {
if(root == NULL) {
arr[i++] = '$';
return;
}
storeInorder(root -> left, arr, i);
arr[i++] = root -> key;
storeInorder(root -> right, arr, i);
}
// a utility function to store preorder traversal
// of tree rooted with root in an arr[]. Note that
// i is passed by reference
void storePreoder(Node* root, char arr[], int &i) {
if(root == NULL) {
arr[i++] = '$';
return;
}
arr[i++] = root -> key;
storePreoder(root -> left, arr, i);
storePreoder(root -> right, arr, i);
}
// this function returns true if S is a subtree of T,
// otherwise, false
bool isSubtree(Node* T, Node*S) {
// base case
if(S == NULL) return true;
if(T == NULL) return false;
// store Inoder traversals of T and S in
// inT[0..m] and inS[0..n]
int m = 0;
int n = 0;
char inT[MAX], inS[MAX];
storeInorder(T, inT, m);
storeInorder(S, inS, n);
inT[m] = '\0';
inS[n] = '\0';
// if inS[] is not a substring of inT[], return false
if(strstr(inT, inS) == NULL)
return false;
// store preoder traversal of T and S in preT[0..m-1]
// preS[0.. n-1]
m = 0, n = 0;
char preT[MAX], preS[MAX];
storePreoder(T,preT, m);
storePreoder(S, preS, n);
preT[m] = '\0';
preS[n] = '\0';
if(strstr(preT, preS) == NULL)
return false;
return true;
}
// Driver program to test above function
int main()
{
Node *T = newNode('a');
T->left = newNode('b');
T->right = newNode('d');
T->left->left = newNode('c');
T->right->right = newNode('e');
Node *S = newNode('a');
S->left = newNode('b');
S->left->left = newNode('c');
S->right = newNode('d');
if (isSubtree(T, S))
cout << "Yes: S is a subtree of T";
else
cout << "No: S is NOT a subtree of T";
return 0;
}
运行结果如下: