剑指offer-第三章高质量代码(树的子结构)

题目:输入两个二叉树A和B,判断B是不是A的子结构。

思路:遍历A树找到B树的根节点,然后再判断左右子树是否相同。不相同再往下找。重复改过程。

子结构的描述如下图所示:

C++代码:

#include<iostream>
using namespace std;
struct BinaryTreeNode
{
    int m_nValue;
    BinaryTreeNode* m_pLeft;
    BinaryTreeNode* m_pRight;
};
BinaryTreeNode* ConstructCore(int* startPreorder,int* endPreorder,int* startInorder,int* endInorder)
{
    int rootValue=startPreorder[0];
    BinaryTreeNode* root=new BinaryTreeNode();
    root->m_nValue=rootValue;
    root->m_pLeft=root->m_pRight=NULL;
    if(startPreorder==endPreorder)
    {
        if(startInorder==endInorder&&*startPreorder==*startInorder)
        {
            return root;
        }
    else
        throw std::exception("Invalid put!");
    }
    //通过中序遍历序列找到根节点
    int* rootInorder=startInorder;
    while(rootInorder<=endInorder&&*rootInorder!=rootValue)
    {
        ++rootInorder;
    }
    if(rootInorder==endInorder&&*rootInorder!=rootValue)
    {
        throw std::exception("Invalid put");
    }
    int leftLength=rootInorder-startInorder;
    int rightLength=endInorder-rootInorder;
    int* leftPreorderEnd=startPreorder+leftLength;
    if(leftLength>0)
    {
        //递归构建左子树
        root->m_pLeft=ConstructCore(startPreorder+1,leftPreorderEnd,startInorder,rootInorder-1);
    }
    if(rightLength>0)
    {
        //递归构建右子树
        root->m_pRight=ConstructCore(leftPreorderEnd+1,endPreorder,rootInorder+1,endInorder);
    }
    return root;
}

BinaryTreeNode* Construct(int* preorder,int* inorder,int length)
{
    if(preorder==NULL||inorder==NULL||length<=0)
    {
    throw std::exception("Invalid put!");
    }
    return ConstructCore(preorder,preorder+length-1,inorder,inorder+length-1);
}
 bool DoesTree1HasTree2(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
    if(pRoot2==NULL)
        return true;
    if(pRoot1==NULL)
        return false;
    if(pRoot1->m_nValue !=pRoot2->m_nValue)
        return false;
    return DoesTree1HasTree2(pRoot1->m_pLeft,pRoot2->m_pLeft)&&DoesTree1HasTree2(pRoot1->m_pRight,pRoot2->m_pRight);
}
bool hasSubTree(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
    bool result=false;
    if(pRoot1!=NULL&&pRoot2!=NULL)
    {
        if(pRoot1->m_nValue==pRoot2->m_nValue)
            result=DoesTree1HasTree2(pRoot1,pRoot2);
        if(!result)
            result=hasSubTree(pRoot1->m_pLeft,pRoot2);
        if(!result)
            result=hasSubTree(pRoot1->m_pRight,pRoot2);
    }
    return result;
}
void PrintTreeNode(BinaryTreeNode* pNode)  

{
    if(pNode != NULL)
    {
        printf("value of this node is: %d\n", pNode->m_nValue);
        if(pNode->m_pLeft != NULL)
            printf("value of its left child is: %d.\n", pNode->m_pLeft->m_nValue);
        else
            printf("left child is null.\n");
        if(pNode->m_pRight != NULL)
            printf("value of its right child is: %d.\n", pNode->m_pRight->m_nValue);
        else
            printf("right child is null.\n");
    }
    else
    {
        printf("this node is null.\n");
    }
    printf("\n");
}  

//递归打印左右子树
void PrintTree(BinaryTreeNode* pRoot)
{
    PrintTreeNode(pRoot);
    if(pRoot != NULL)
    {
        if(pRoot->m_pLeft != NULL)
            PrintTree(pRoot->m_pLeft);
        if(pRoot->m_pRight != NULL)
            PrintTree(pRoot->m_pRight);
    }
}
 //递归删除左右子树

void DestroyTree(BinaryTreeNode* pRoot)
{
    if(pRoot != NULL)
    {
        BinaryTreeNode* pLeft = pRoot->m_pLeft;
        BinaryTreeNode* pRight = pRoot->m_pRight;
        delete pRoot;
        pRoot = NULL;
        DestroyTree(pLeft);
        DestroyTree(pRight);
    }
}  

void main()
{
    const int length1 = 8;
    const int length2 = 3;
    int preorder1[length1] = {1, 2, 4, 7, 3, 5, 6, 8};
    int inorder1[length1] = {4, 7, 2, 1, 5, 3, 8, 6};
    int preorder2[length2]={3,5,6};
    int inorder2[length2]={5,3,6};
    BinaryTreeNode *root1 = Construct(preorder1, inorder1, length1);
    BinaryTreeNode *root2 =Construct(preorder2, inorder2, length2);
    PrintTree(root1);
    PrintTree(root2);
    if(hasSubTree(root1,root2))
    cout<<"hello!"<<endl;
    else
        cout<<"world!"<<endl;
}  

Java代码:

public class IsSubTree {
public static class BinaryTreeNode
{
    int m_nValue;
    BinaryTreeNode m_pLeft;
    BinaryTreeNode m_pRight;
};
public static BinaryTreeNode ConstructBiTree(int[] preOrder,int start,int[] inOrder,int end,int length)
{
    //参数验证 ,两个数组都不能为空,并且都有数据,而且数据的数目相同
    if (preOrder == null || inOrder == null
            || inOrder.length != preOrder.length  || length <= 0) {
        return null;
    }
    int value=preOrder[start];
    BinaryTreeNode root=new BinaryTreeNode();
    root.m_nValue=value;
    root.m_pLeft=root.m_pRight=null;
  //递归终止条件:子树只有一个节点
    if (length == 1){
        if(inOrder[end]==value)
            return root;
         else
            throw new RuntimeException("Invalid input");
    }
    //分拆子树的左子树和右子树
    int i = 0;
    while (i < length) {
        if (value == inOrder[end - i]) {
            break;
        }
        i++;
    }
    if(i==length)
        throw new RuntimeException("Invalid input");
    //建立子树的左子树
    root.m_pLeft = ConstructBiTree(preOrder, start + 1, inOrder, end - i - 1, length - 1 - i);
    //建立子树的右子树
    root.m_pRight = ConstructBiTree(preOrder, start + length - i, inOrder, end, i );
    return root;
}
 public static boolean DoesTree1HasTree2(BinaryTreeNode pRoot1,BinaryTreeNode pRoot2)
{   //树A存在树B的根节点时,判断B的左右子树是否也存在A树中。
    if(pRoot2==null)
        return true;
    if(pRoot1==null)
        return false;
    if(pRoot1.m_nValue !=pRoot2.m_nValue)
        return false;
    return DoesTree1HasTree2(pRoot1.m_pLeft,pRoot2.m_pLeft)&&DoesTree1HasTree2(pRoot1.m_pRight,pRoot2.m_pRight);
}
public static boolean  hasSubTree(BinaryTreeNode pRoot1,BinaryTreeNode pRoot2)
{   //判断是否是子树
    boolean result=false;
    if(pRoot1!=null&&pRoot2!=null)
    {
        if(pRoot1.m_nValue==pRoot2.m_nValue)
            result=DoesTree1HasTree2(pRoot1,pRoot2);//树A存在树B的根节点时,判断B的左右子树是否也存在A树中。
        if(!result)
            result=hasSubTree(pRoot1.m_pLeft,pRoot2);//在左子树中找B的根节点。
        if(!result)
            result=hasSubTree(pRoot1.m_pRight,pRoot2);//在右子树中找B的根节点。
    }
    return result;
}
public static void PrintTreeNode(BinaryTreeNode pNode)
{
    if(pNode !=null)
    {
        System.out.println("the Node is:"+pNode.m_nValue);
         if(pNode.m_pLeft != null)             System.out.println( "left child is:"+pNode.m_pLeft.m_nValue);
        else
           System.out.println("left child is null.\n");
        if(pNode.m_pRight != null)
           System.out.println("right child is:"+pNode.m_pRight.m_nValue);
        else
            System.out.println("right child is null.\n");
    }
    else
    {
       System.out.println("this node is null.\n");
    }
   System.out.println();
}  

  //递归打印左右子树
public static void PrintTree(BinaryTreeNode pRoot)
{
    PrintTreeNode(pRoot);
    if(pRoot !=null)
    {
        if(pRoot.m_pLeft != null)
            PrintTree(pRoot.m_pLeft);
        if(pRoot.m_pRight != null)
            PrintTree(pRoot.m_pRight);
    }
}  

public static void main(String[] args)
{
    int preorder1[] = {1, 2, 4, 7, 3, 5, 6, 8};
    int inorder1[] = {4, 7, 2, 1, 5, 3, 8, 6};
    int preorder2[]={3,5,6};
    int inorder2[]={5,3,6};
    BinaryTreeNode root1 = ConstructBiTree(preorder1,0, inorder1,7, preorder1.length);
    BinaryTreeNode root2 = ConstructBiTree(preorder2,0, inorder2,2, preorder2.length);
    PrintTree(root1);
    PrintTree(root2);
    if(hasSubTree(root1,root2)
        System.out.println("存在子树关系!");
    else
        System.out.println("不存在子树关系!");}  }
时间: 2024-10-14 20:35:43

剑指offer-第三章高质量代码(树的子结构)的相关文章

剑指offer—第三章高质量代码(o(1)时间删除链表节点)

题目:给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点,链表节点与函数的定义如下:struct ListNode{int m_nValue;ListNode* m_pValue;};void DeleteNode(ListNode** pListNode,ListNode * pToBeDeleted){} 思路:将要删除的节点的下一个节点的值赋值给i,删除下一个节点,但要考虑到删除的节点是最后一个节点并且该链表不止有一个节点的情况和该链表只有一个节点,该节点既是头节点也

剑指offer—第三章高质量代码(合并两个排序链表)

题目:输入员两个递增排序的链表,合并这两个链表并使新的链表中的结点仍然是按照递增排序的. 思路:首先,定义两个头节点分别为Head1和Head2的链表,然后比较第一个节点的值,如果是Head1->mValue比Head2->mValue小,那么头节点,就是Head1,递归实现后面的节点的排序. C++代码: #include<iostream> using namespace std; struct ListNode { int m_nValue; ListNode* m_pNex

剑指offer—第三章高质量的代码(按顺序打印从1到n位十进制数)

题目:输入一个数字n,按照顺序打印出1到最大n位十进制数,比如输入3,则打印出1,2,3直到最大的3位数999为止. 本题陷阱:没有考虑到大数的问题. 本题解题思路:将要打印的数字,看成字符串,不足位的,高位补0.打印字符串的时候要对数字进行判断,不要将高位的0打印出来.打印字符串的结束条件是,当最高位产生进位时结束. c++代码: #include<iostream> using namespace std; //字符串模拟加法 bool Increment(char* number) {

高质量代码-树的子结构

描述:输入两颗二叉树A,B,判断B是不是A的子结构. 思路: 没有难度,递归解决.关键是处理空指针. 解决: 1 public class Solution { 2 public boolean HasSubtree(TreeNode root1,TreeNode root2) { 3 if (root1 == null || root2 == null) { 4 return false; 5 } 6 return isSubTree(root1, root2); 7 } 8 9 boolea

剑指offer第4章

包含 \(min\) 函数的栈 ? 利用辅助栈,把每次的最小者(之前的最小元素和新压入栈的元素的两者中的较小值)都保存起来放到另一个辅助栈中. ? 栈的压入.弹出序列 ? 总结上述入栈.出栈的过程,我们可以找到判断个序列是不是栈的弹出序列的规律:如果下一个弹出的数字刚好是栈顶数字,那么直接弹出. 如果下一个弹出的数字不在栈顶,我们把压栈序列中还没有入栈的数字压 入辅助栈,直到把下一个需要弹出的数字压入栈顶为止.如果所有的数字 都压入栈了仍然没有找到下一个弹出的数字,那么该序列不可能是一个弹出序列

剑指offer-第三章高质量的代码(输出该链表中倒数第K个节点)

题目:输入一个链表,输出这个链表中倒数第K个节点.(代码的鲁棒性) 思路:用两个指针p1和p2,都指向头节点,开始的时候,p2不动,p1移动k-1次,指向第k个节点.此时,如果p1->next!=null,则同时移动P1和p2.直到p1指向最后一个节点.此时,P2指向倒数第k个节点. C++代码: #include<iostream> using namespace std; struct ListNode { int m_nValue; ListNode* m_pNext; }; Li

剑指offer第2章学习(2)

各种排序算法都有各自的使用范围.例如快速排序,如果数组本身已经排好序了,那么再使用它进行排序工作量为 O(n^2). //对公司所有员工的年龄进行排序 //假定,所有员工的年龄从15岁到60岁不等 //非常简单,没什么可说的 void SortAge(int data[], int length) { const int Youngest = 15, Oldest = 60; if (data == NULL || length <= 0) return; int Age[Oldest - Yo

剑指offer第8章

正则表达式的匹配 ?

剑指offer第3章

通常有3种方式把错误信息传递给函数调用者.? 函数用返回值来告知调用者是否出错. ?在错误发生的时候设置一个全局变量 ,此时可以用返回值来传递计算结果 ?异常方式:当程序出现错误的时候就抛出一个异常. ? 3种错误信息的处理方式的优缺点 ? ? ?