您的位置:首页 > 其它

确定一个二叉树是另一个二叉树的子树

2015-03-12 21:56 393 查看
问题: 给定两个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
 = '\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
 = '\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;
}


运行结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐