数据结构——确定一个二叉树是不是另一个二叉树的子树(2)

原文地址:Check if a binary tree is subtree of another binary tree | Set 2

已知两个二叉树,看一下第一个树是不是第二个树的子树。一个树T的子树是树S,这个树由是T中的一个节点及其它的下属节点组成的。

子树对应的是根节点的话,那就是整个树;子树对应的是任意其他节点的话叫做正常子树(proper subtree)。

例如,在下面的例子中,Tree1是Tree2的子树。

        Tree1
          x 
        /    \
      a       b
       \
        c


        Tree2
              z
            /   \
          x      e
        /    \     \
      a       b      k
       \
        c

我们已经讨论过了 O(n2) 对这个问题的解决方法。这章讨论的是O(n)的解决方法。这个思想是基于这样一个事实,中序遍历与先序遍历/后序遍历可以唯一确定一个树。如果S的中序遍历和先序遍历分别是T的中序遍历和先序遍历的子字符串,那么S就是T的一个子树。

下面是详细步骤:

1)得到T的中序遍历与先序遍历序列,保存在两个附加的数组inT[]与preT[]中。
2)得到S的中序遍历与先序遍历序列,保存在两个附加的数组inS[]与preS[]中。
3)如果inS[]是inT[]的子数组,preS[]是preT[]的子数组,那么S就是T的一个子树。否则不是。

我们可以在上述算法中用后序遍历代替先序遍历。

我们考虑下下面的例子。

中序和先序遍历那个大一点的树。
inT[]   =  {a, c, x, b, z, e, k}
preT[]  =  {z, x, a, c, b, e, k}

中序和先序遍历那个小一点的树。
inS[]  = {a, c, x, b}
preS[] = {x, a, c, b}

我们可以算出inS[]是inT[]的一个子数组,preS[]是preT[]的一个子数组。 

编辑:

如果一个树在另一个树中表示,但不是子树,那么上述算法就不起作用了,考虑下面的例子。

        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.

以上算法可以延伸到通过增加特别的字符处理这种情况,无论啥时候在中序遍历与先序遍历中遇到NULL。

下面是上述算法的代码实现。

// Java program to check if binary tree is subtree of another binary tree 
class Node {

    char data;
    Node left, right;

    Node(char item) {
        data = item;
        left = right = null;
    }
}

class Passing {

    int i;
    int m = 0;
    int n = 0;
}

class BinaryTree {

    static Node root;
    Passing p = new Passing();

    String strstr(String haystack, String needle) {
        if (haystack == null || needle == null) {
            return null;
        }
        int hLength = haystack.length();
        int nLength = needle.length();
        if (hLength < nLength) {
            return null;
        }
        if (nLength == 0) {
            return haystack;
        }
        for (int i = 0; i <= hLength - nLength; i++) {
            if (haystack.charAt(i) == needle.charAt(0)) {
                int j = 0;
                for (; j < nLength; j++) {
                    if (haystack.charAt(i + j) != needle.charAt(j)) {
                        break;
                    }
                }
                if (j == nLength) {
                    return haystack.substring(i);
                }
            }
        }
        return null;
    }

    // A utility function to store inorder traversal of tree rooted
    // with root in an array arr[]. Note that i is passed as reference
    void storeInorder(Node node, char arr[], Passing i) {
        if (node == null) {
            arr[i.i++] = '$';
            return;
        }
        storeInorder(node.left, arr, i);
        arr[i.i++] = node.data;
        storeInorder(node.right, arr, i);
    }

    // A utility function to store preorder traversal of tree rooted
    // with root in an array arr[]. Note that i is passed as reference
    void storePreOrder(Node node, char arr[], Passing i) {
        if (node == null) {
            arr[i.i++] = '$';
            return;
        }
        arr[i.i++] = node.data;
        storePreOrder(node.left, arr, i);
        storePreOrder(node.right, arr, i);
    }

    /* This function returns true if S is a subtree of T, otherwise false */
    boolean isSubtree(Node T, Node S) {
        /* base cases */
        if (S == null) {
            return true;
        }
        if (T == null) {
            return false;
        }

        // Store Inorder traversals of T and S in inT[0..m-1]
        // and inS[0..n-1] respectively
        char inT[] = new char[100];
        String op1 = String.valueOf(inT);
        char inS[] = new char[100];
        String op2 = String.valueOf(inS);
        storeInorder(T, inT, p);
        storeInorder(S, inS, p);
        inT[p.m] = '\0';
        inS[p.m] = '\0';

        // If inS[] is not a substring of preS[], return false
        if (strstr(op1, op2) != null) {
            return false;
        }

        // Store Preorder traversals of T and S in inT[0..m-1]
        // and inS[0..n-1] respectively
        p.m = 0;
        p.n = 0;
        char preT[] = new char[100];
        char preS[] = new char[100];
        String op3 = String.valueOf(preT);
        String op4 = String.valueOf(preS);
        storePreOrder(T, preT, p);
        storePreOrder(S, preS, p);
        preT[p.m] = '\0';
        preS[p.n] = '\0';

        // If inS[] is not a substring of preS[], return false
        // Else return true
        return (strstr(op3, op4) != null);
    }

    //Driver program to test above functions
    public static void main(String args[]) {
        BinaryTree tree = new BinaryTree();
        Node T = new Node('a');
        T.left = new Node('b');
        T.right = new Node('d');
        T.left.left = new Node('c');
        T.right.right = new Node('e');

        Node S = new Node('a');
        S.left = new Node('b');
        S.right = new Node('d');
        S.left.left = new Node('c');

        if (tree.isSubtree(T, S)) {
            System.out.println("Yes , S is a subtree of T");
        } else {
            System.out.println("No, S is not a subtree of T");
        }
    }
}

// This code is contributed by Mayank Jaiswal

输出:

No: S is NOT a subtree of T

时间复杂度:中序与先序遍历二叉树花费了O(n)的时间。函数strstr()可以用KMP字符串匹配算法实现O(n)时间的算法。

空间复杂度是:O(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值