用C语言判断一个二叉树是否为另一个的子结构_C 语言

1、问题描述:

     如何判断一个二叉树是否是另一个的子结构?
     比如:

        2
      /   \
     9    8
    / \    /
   2  3  5
  /
6

   有个子结构是
   9
  / \
2  3

2、分析问题:
    有关二叉树的算法问题,一般都可以通过递归来解决。那么写成一个正确的递归程序,首先一定要分析正确递归结束的条件。

拿这道题来讲,什么时候递归结束。

<1>第二个二叉树root2为空时,说明root2是第一棵二叉树的root1的子结构,返回true。

<2>当root1为空时,此时root2还没为空,说明root2不是root1的子结构,返回false。

<3>递归下面有两种思路:

    方法一:现在root1中找结点值与root2的值相等的结点,如果找到就判断root2是不是这个结点开头的子结构。所以,首先IsSubTree()判断。

    方法二:就是直接判断,相同就递归判断root2左右子树是不是也是相应的子结构。如果值不相同,就分别递归到root1的左右子树寻找。尤其要注意最后两句递归的逻辑判断。

3、习题实例

    题目描述:  
    输入两颗二叉树A,B,判断B是不是A的子结构。 
    输入: 
    输入可能包含多个测试样例,输入以EOF结束。 
    对于每个测试案例,输入的第一行一个整数n,m(1<=n<=1000,1<=m<=1000):n代表将要输入的二叉树A的节点个数(节点从1开始计数),m代表将要输入的二叉树B的节点个数(节点从1开始计数)。接下来一行有n个数,每个数代表A树中第i个元素的数值,接下来有n行,第一个数Ki代表第i个节点的子孩子个数,接下来有Ki个树,代表节点i子孩子节点标号。接下来m+1行,与树A描述相同。 
    输出: 
    对应每个测试案例, 
    若B是A的子树输出”YES”(不包含引号)。否则,输出“NO”(不包含引号)。 
    样例输入: 
    7 3 
    8 8 7 9 2 4 7 
    2 2 3 
    2 4 5 
    0 
    0 
    2 6 7 
    0 
    0 
    8 9 2 
    2 2 3 
    0 
    0 

    实现
    第一步,在A树中查找和B树根节点一样的值,其实就是树的前序遍历,建议递归,方便(ps:非递归无非就是用个栈存储结点而已,没什么技术含量)

  

 /**
   * 第一步判断,遍历A树查找是否有等于B树根结点的子树
   */
  int judgeChildTree(struct btree *ahead, int numa, struct btree *bhead, int numb)
  {
    int flag = 0; 

    if (numa != -1 && numb != -1) {
      if (ahead[numa].value == bhead[numb].value)
        flag = doesTree1HasTree2(ahead, numa, bhead, numb); 

      if (! flag && ahead[numa].lchild != -1)
        flag = judgeChildTree(ahead, ahead[numa].lchild, bhead, numb); 

      if (! flag && ahead[numa].rchild != -1)
        flag = judgeChildTree(ahead, ahead[numa].rchild, bhead, numb);
    } 

    return flag;
  }

    第二步,进一步判断A中以R为根节点的子树是不是与B树具有相同的结点

  /**
   * 第二步判断,判断A树是否有B树的子结构
   */
  int doesTree1HasTree2(struct btree *ahead, int numa, struct btree *bhead, int numb)
  {
    if (numb == -1)
      return 1;
    if (numa == -1)
      return 0; 

    if (ahead[numa].value != bhead[numb].value)
      return 0; 

    return (doesTree1HasTree2(ahead, ahead[numa].lchild, bhead, bhead[numb].lchild) &&
      doesTree1HasTree2(ahead, ahead[numa].rchild, bhead, bhead[numb].rchild));
  } 

完整代码

   

 #include <stdio.h>
  #include <stdlib.h> 

  // 二叉树结点定义
  struct btree
  {
    int value;
    int lchild, rchild;
  }; 

  // A树和B树的最多结点数
  int n, m; 

  /**
   * 第二步判断,判断A树是否有B树的子结构
   */
  int doesTree1HasTree2(struct btree *ahead, int numa, struct btree *bhead, int numb)
  {
    if (numb == -1)
      return 1;
    if (numa == -1)
      return 0; 

    if (ahead[numa].value != bhead[numb].value)
      return 0; 

    return (doesTree1HasTree2(ahead, ahead[numa].lchild, bhead, bhead[numb].lchild) &&
      doesTree1HasTree2(ahead, ahead[numa].rchild, bhead, bhead[numb].rchild));
  } 

  /**
   * 第一步判断,遍历A树查找是否有等于B树根结点的子树
   */
  int judgeChildTree(struct btree *ahead, int numa, struct btree *bhead, int numb)
  {
    int flag = 0; 

    if (numa != -1 && numb != -1) {
      if (ahead[numa].value == bhead[numb].value)
        flag = doesTree1HasTree2(ahead, numa, bhead, numb); 

      if (! flag && ahead[numa].lchild != -1)
        flag = judgeChildTree(ahead, ahead[numa].lchild, bhead, numb); 

      if (! flag && ahead[numa].rchild != -1)
        flag = judgeChildTree(ahead, ahead[numa].rchild, bhead, numb);
    } 

    return flag;
  } 

  int main(void)
  {
    int i, data, count, left, right, flag;
    struct btree *ahead, *bhead; 

    while (scanf("%d %d", &n, &m) != EOF) {
      // 获取A树的节点值
      ahead = (struct btree *)malloc(sizeof(struct btree) * n);
      for (i = 0; i < n; i ++) {
        scanf("%d", &data);
        ahead[i].value = data;
        ahead[i].lchild = ahead[i].rchild = -1;
      } 

      for (i = 0; i < n; i ++) {
        scanf("%d", &count);
        if (count == 0) {
          continue;
        } else {
          if (count == 1) {
            scanf("%d", &left);
            ahead[i].lchild = left - 1;
          } else {
            scanf("%d %d", &left, &right);
            ahead[i].lchild = left - 1;
            ahead[i].rchild = right - 1;
          }
        }
      } 

      // 获取B树的节点值
      bhead = (struct btree *)malloc(sizeof(struct btree) * m);
      for (i = 0; i < m; i ++) {
        scanf("%d", &data);
        bhead[i].value = data;
        bhead[i].lchild = bhead[i].rchild = -1;
      } 

      for (i = 0; i < m; i ++) {
        scanf("%d", &count);
        if (count == 0) {
          continue;
        } else {
          if (count == 1) {
            scanf("%d", &left);
            bhead[i].lchild = left - 1;
          } else {
            scanf("%d %d", &left, &right);
            bhead[i].lchild = left - 1;
            bhead[i].rchild = right - 1;
          }
        }
      } 

      // 判断B树是否为A的子树
      if (n == 0 || m == 0) {
        printf("NO\n");
        continue;
      } 

      flag = judgeChildTree(ahead, 0, bhead, 0);
      if (flag)
        printf("YES\n");
      else
        printf("NO\n"); 

      free(ahead);
      free(bhead);
    } 

    return 0;
  }

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c语言
二叉树
二叉树 c语言、c语言创建二叉树、c语言二叉树的建立、c语言二叉树遍历、二叉树c语言实现,以便于您获取更多的相关知识。

时间: 2024-09-20 06:00:21

用C语言判断一个二叉树是否为另一个的子结构_C 语言的相关文章

C语言判断字符是否为可打印字符的方法_C 语言

C语言isprint()函数:判断字符是否为可打印字符头文件: #include <ctype.h> isprint() 函数用来判断一个字符是否为打印字符,其原型为: int isprint(int c); [参数]c 为需要被检测的字符. [返回值]如果 c 为可打印字符,将返回非 0 值,否则返回 0. 可打印字符的ASCII码值大于 0x1f(除了0x7f(DEL)),这些字符可以显示到屏幕上,让我们看到:不能显示在屏幕上,我们看不到的,叫控制字符,ASCII码值为 0x00 ~ 0x

用C语言判断字符是否为空白字符或特殊字符的方法_C 语言

C语言isspace()函数:判断字符是否为空白字符头文件: #include <ctype.h> 定义函数: int isspace(int c); 函数说明:检查参数c是否为空格字符,也就是判断是否为空格(' ').定位字符(' \t ').CR(' \r ').换行(' \n ').垂直定位字符(' \v ')或翻页(' \f ')的情况. 返回值:若参数c 为空白字符,则返回非 0,否则返回 0. 附加说明:此为宏定义,非真正函数. 范例:将字符串str[]中内含的空格字符找出,并显示

利用简洁的C语言代码解决跳台阶问题与约瑟夫环问题_C 语言

跳台阶问题 题目: 一个台阶总共有 n 级,如果一次可以跳 1 级,也可以跳 2 级. 求总共有多少总跳法,并分析算法的时间复杂度. 分析: 也是比较基础的题目,通过递归可以方便的求解 代码实现如下(GCC编译通过): #include "stdio.h" #include "stdlib.h" int function(int n); int main(void) { int tmp; tmp = function(5); printf("%3d\n&q

C语言单向链表的表示与实现实例详解_C 语言

1.概述: C语言中的单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始. 链表中最简单的一种是单向链表,它包含两个域,一个信息域和一个指针域.这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值. 如下图所示: 一个单向链表包含两个值: 当前节点的值和一个指向下一个节点的链接 一个单向链表的节点被分成两个部分.第一个部分保存或者显示关于节点的信息,第二个部分存储下一个节点的地址.单向链表只可向一个方向遍历. 链表最基本的结构是在每个节点

c语言中数组名a和&amp;amp;a详细介绍_C 语言

最近又把学习c语言提上日程上来了~~~先把我打算看的书都写下来吧,<C语言深度剖析>,<c和指针>系类,<c语言陷阱和缺陷> 先说说a和&a的区别(有三点,三个方向):1.是a和&a的本质,都是什么类型的.2.从2维数组的角度看.3.从指针运算的角度看. 声明:虽然数组名不是指针,但是用的很像指针,我们暂且把它叫做一个指针吧. 第一个问题:int a[10];  a ,&a和&a[0] 都是分别是什么?先说明a ,&a和&

C语言中的数组和指针汇编代码分析实例_C 语言

今天看<程序员面试宝典>时偶然看到讲数组和指针的存取效率,闲着无聊,就自己写了段小代码,简单分析一下C语言背后的汇编,可能很多人只注重C语言,但在实际应用当中,当出现问题时,有时候还是通过分析汇编代码能够解决问题.本文只是为初学者,大牛可以飘过~ C源代码如下: 复制代码 代码如下: #include "stdafx.h" int main(int argc, char* argv[]) {        char a=1;        char c[] = "

C语言中对字母进行大小写转换的简单方法_C 语言

C语言tolower()函数:将大写字母转换为小写字母头文件: #include <ctype.h> 定义函数: int toupper(int c); 函数说明:若参数 c 为小写字母则将该对应的大写字母返回. 返回值:返回转换后的大写字母,若不须转换则将参数c 值返回. 范例:将s 字符串内的小写字母转换成大写字母. #include <ctype.h> main(){ char s[] = "aBcDeFgH12345;!#$"; int i; print

C语言中结构体struct编写的一些要点解析_C 语言

一.关于结构体的声明1.匿名声明.如: struct { int i,j; }point; 说明: 这段代码的含义是,声明一个无名(anonymous)的结构体,并创建了一个结构体变量point.如果这段声明是放在全局域(在任意函数(比如main函数)外)内,那么point内的变量将被初始化为默认值,换句话说,以这种方式声明结构体变量时就已经为它分配了内存空间. 适用于该结构体只需要产生一个变量!本例中,该匿名结构体将有且仅有point这个结构体变量! 不同的匿名结构体变量,类型是不同的!如 s

在C语言中比较两个字符串是否相等的方法_C 语言

C语言strcmp()函数:比较字符串(区分大小写) 头文件:#include <string.h> strcmp() 用来比较字符串(区分大小写),其原型为: int strcmp(const char *s1, const char *s2); [参数]s1, s2 为需要比较的两个字符串. 字符串大小的比较是以ASCII 码表上的顺序来决定,此顺序亦为字符的值.strcmp()首先将s1 第一个字符值减去s2 第一个字符值,若差值为0 则再继续比较下个字符,若差值不为0 则将差值返回.例