二叉树 详解

文章目录

  • 二叉树
    • 树 概念及结构
      • 树的概念
      • 树的相关概念
      • 树的表示
    • 二叉树概念及结构
      • 概念
      • 特殊的二叉树
      • 二叉树的性质
      • 二叉树的存储结构
      • 二叉树链式结构的实现
      • 二叉树的遍历
        • 前序遍历(先序遍历)
        • 中序遍历
        • 后序遍历
        • 层序遍历
      • 二叉树的应用
        • 二叉树节点个数
        • 二叉树叶子节点的个数
        • 二叉树第K层节点个数
        • 二叉树的深度
        • 二叉树查找值为x的节点
        • 判断二叉树是不是完全二叉树
        • 通过前序遍历数组来构建二叉树
      • 二叉树OJ
        • 单值二叉树
        • 检查两棵树是否相同
        • 对称二叉树
        • 另一棵树的子树

二叉树

树 概念及结构

树的概念

树是一种非线性 的数据结构,它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一颗倒挂的树,也就是说它是根朝上,而叶朝下。
二叉树 详解_第1张图片

  • 有一个特殊的节点,称为根节点,根节点没有前驱节点
  • 除根节点外,其余节点被分为M(M>0)个互不相交的集合T1、T2、…、Tm,其中每一个集合Ti(1<=i<=m) 又是一棵与树类似的子树。每棵子树的根节点有且只有一个前驱,可以有0个或多个后继
  • 因此,树 是递归定义的

注意:树形结构中,子树之间不能有交集,否则就不是树形结构

树的相关概念

二叉树 详解_第2张图片
节点的度: 一个节点含有的子树的个数称为该节点的度;如上图:F点的度为3
叶节点或终端节点: 度为0的节点称为叶节点;如上图:B、C、H、I、P、Q…都是叶节点
非终端节点或分支节点: 度不为0的节点;如上图J、D、E…
双亲节点或父节点: 若一个节点含有子节点,则称这个节点为其子节点的父节点
孩子节点或子节点: 一个节点含有的子树根节点称为该节点的子节点;如图:B是A的孩子节点
兄弟节点: 具有相同父节点的节点互称为兄弟节点;如图:B、C、D、E、F、G是兄弟节点
树的度: 一棵树中最大节点的度称为树的度;如上图:树的度为6
节点的层次: 从根开始定义起,根为第一层,根的子节点为第二层,以此类推;
树的高度或深度: 树中节点的最大层次;如上图:树的高度为4.
堂兄弟节点: 双亲在同一层的节点互为堂兄弟节点,如图:H、I互为堂兄弟节点
节点的祖先: 从根到该节点所经分支上的所有节点;如图:A是所有节点的祖先
子孙: 以某节点为根的子树中的任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
森林: 由m(m>0)棵互补相交的树的集合称为森林;

树的表示

树结构相对线性表就比较复杂了,要储存表示起来比较麻烦,既要保存值域,也要保存节点和节点之间的关系 这里介绍一下孩子兄弟表示法


typedef int DataType;
struct Node
{
	struct Node* _fistchild1;   //第一个孩子的节点
	struct Node* _NextBrother;   //指向其下一个兄弟的节点
	DataType _data;               //节点中的数据域
};

二叉树 详解_第3张图片

二叉树概念及结构

概念

一棵二叉树是节点的一个有限集合,该集合:

  1. 或者为空
  2. 由一个根节点加上两棵别称为左子树和右子树的二叉树组成
    二叉树 详解_第4张图片
    从上可以发现:
  3. 二叉树不存在度大于2的节点
  4. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

注意:二叉树都是由一下几种情况组合而成:

二叉树 详解_第5张图片

特殊的二叉树

  1. 满二叉树: 一个二叉树,如果每一层的节点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且节点总数为2^k - 1 ,则他就是满二叉树
  2. 完全二叉树: 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个节点的二叉树,当且仅当其每一个节点都与深度为K的满二叉树中编号从1到n的节点一一对应时称为完全二叉树。注意满二叉树是一种特殊的完全二叉树。
二叉树 详解_第6张图片 二叉树 详解_第7张图片

二叉树的性质

  1. 若规定根节点的层数为1,则一棵非空二叉树的的第i层上最多有2^(i-1) 个结点
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大节点数是2^h -1
  3. 对任何一棵二叉树,如果度为0的叶节点个数为x,度为2的节点个数为y,则有 x=y+1
  4. 对一个完全二叉树来说,他的度为1的节点只有两种肯能 1或0 ,结合上面的条件可以推出
  • 当完全二叉树有偶数个节点(2n)的时候,这时候必然有一个度为1的节点,且度为0的节点的个数是所有节点的一半(n)
  • 当完全二叉树有奇数个节点(2n-1)的时候,这时候必然有0个度为1的节点,且度为0的节点的个数是n
  1. 对于具有n个节点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的节点有:
  1. 若i>0,则i位置节点的双亲序号:(i-1)/2 ;i=0,i为根节点编号
  2. 若2i+12*i+1 ,否则就没有左孩子
  3. 若2i+22*i+2 ,否则就没有右孩子

二叉树的存储结构

二叉树的存储结构可以使用两种结构存储:顺序存储结构 和 链式存储结构

  1. 顺序存储

顺序存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中只有 才会使用数组来存储。
关于 的博客可以戳这里->数据结构:堆 的详解

  1. 链式存储

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个节点由三个域组成,数据域左右指针域 左右指针分别用来给出该节点左孩子和右孩子所在的链结点的存储地址。链式结构又分为二叉链和三叉链。

二叉树 详解_第8张图片

二叉树链式结构的实现

因为堆二叉树的了解还不够深入所以这里用最简单的方法创建一个二叉树


typedef int DataType;
typedef struct BinaryTree
{
	DataType x;
	struct BinaryTree* _left;
	struct BinaryTree* _right;
}BT;

BT* BinaryTreeCreate1(BT* root)
{
	BT* n1 = BuyNode(3);
	BT* n2 = BuyNode(5);
	BT* n3 = BuyNode(4);
	BT* n4 = BuyNode(1);
	BT* n5 = BuyNode(2);
	BT* n6 = BuyNode(0);


	n1->_left = n3;
	n1->_right = n2;
	n3->_left = n4;
	n3->_right = n5;
	n5->_left = n6;

	return n1;
}

二叉树的遍历

二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次

前序遍历(先序遍历)

访问根节点的操作发生在遍历其左右子树之前
二叉树 详解_第9张图片
前序遍历实际上也就是按 根 左 右 的顺序来进行遍历,但要注意的是这里的左和右 是左子树和右子树,而不是左节点和右节点
二叉树 详解_第10张图片

进行前序遍历先访问根节点的值,然后以左节点为新的根节点,左子树为新的树按照根 左的顺序遍历直到根节点为NULL(如果根节点为NULL则说明该子树已经被遍历完了),然后返回上一级遍历 遍历右子树 按照 ** 根 左**,周而复始。
注意我们这里都是判断根节点是否为空来确定时还要递归下去

leetcode-二叉树的前序遍历

二叉树 详解_第11张图片

以leetcode上的前序遍历为例,这里要注意一下给的函数的参数的意义a是一个数组里面存储的是二叉树里的值,而returnsize是一个输出型参数,也就是传入一个参数returnsize的地址在函数内部修改使函数结束的时候,返回a数组的大小
在这里插入图片描述
一这颗子树为例:

二叉树 详解_第12张图片
如上十二步就可以把ABC全部存入数组了

void Pre_order(struct TreeNode*root,int *a,int *returnSize)
{
    if(root!=NULL)
    {
        a[*returnSize]=root->val;
        (*returnSize)++;
    }
    else
    return;
    Pre_order(root->left,a,returnSize); //左子树进行递归
    Pre_order(root->right,a,returnSize); //右子树进行递归
}


int* preorderTraversal(struct TreeNode* root, int* returnSize){
    int *p=(int *)malloc(2000*sizeof(int));
    *returnSize=0;
    Pre_order(root,p,returnSize);
    return p;
}
中序遍历

访问根节点的操作发生在遍历其左子树和右子树之间
中序遍历实际上就是先将左子树递归至空(NULL)然后再方位根节点和右子树

leetcode-中序遍历


 void postOrder(struct TreeNode*root,int *returnSize,int *a)
{
    if(root!=NULL)
    {
        postOrder(root->left,returnSize,a); //先将左子树遍历至NULL
    }
    else
    {
        return;
    }
    a[*returnSize]=root->val; // 存入根节点的值
    (*returnSize)++;
    postOrder(root->right,returnSize,a);  //遍历右子树 依然按照“左 根 右”
}
int* inorderTraversal(struct TreeNode* root, int* returnSize){
    int *p=(int *)malloc(2000*sizeof(int));
    int k=0;
    postOrder(root,&k,p);
    *returnSize=k;
    return p;
}
后序遍历

访问根节点的操作发生在遍历其左右子树之中
和上面的思路相同,后续遍历是先递归左子树至空 然后再递归右子树为空,最后返回空节点
leetcode-后续遍历

void postOrder(struct TreeNode*root,int *returnSize,int *a)
{
    if(root!=NULL)
    {
        postOrder(root->left,returnSize,a);  //左子树递归
    }
    else
    {
        return;
    }
    postOrder(root->right,returnSize,a); //右子树递归
    a[*returnSize]=root->val;    //存储根节点
    (*returnSize)++;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize){
    int *p=(int *)malloc(2000*sizeof(int));
    int k=0;
    postOrder(root,&k,p);
    *returnSize=k;
    return p;
}
层序遍历

层序遍历: 设二叉树的根节点所在层数为1,层数遍历就是从所在二叉树的根节点出发,首先访问第一层的节点,然后从左到右访问第二层上的节点,接着第三层的节点

leetcode-层序遍历

这个leetcode题用c语言写还是有点小复杂的,如果不是以数组的形式输出的话会简单不少,难点在于要以数组输出的话,你要控制二叉树每一层的数组大小,因为每一层的元素不一定是满的。
其实这题还有一个难点是看明白函数参数和返回值的意义:首先是返回值返回的是一个指针数组的数组名实际上是一个数组指针,然后** returnColumnSizes是一个输出型数组,分别存放的是 指针数组 每个 数组指针 指向数组的大小,而* returnSize是个输出型参数,存放的是返回的的指针数组的大小
如果要写main函数调用的话


int main()
{
	TreeNode* root;
	root = CreatBT();
	int* returnColumnSizes;
	int returnSize;
	int** b;
	b = levelOrder(root, &returnSize, &returnColumnSizes);
	for (int i = 0; i < returnSize; i++)                  //控制行数
	{
		for (int j = 0; j < returnColumnSizes[i]; j++)   // 控制每一行列的个数
		{
			printf("%d ", b[i][j]);
		}
		printf("\n");
	}
}

这里实现的基本思路是:

  • 创建一个存储二叉树节点的队列,将二叉树的祖先先入队
  • 然后进入循环,将队头元素的左右节点入队(这里要做检验 如果是NULL就不要入队了,同时还要设置一个参数记录有多少个NULL,来计算下一个数组的大小)最后将头节点出队列,循环的结束条件是队列为空

#include
 
typedef struct TreeNode* Datatype;
typedef struct listNode
{
	Datatype x;
	struct listNode* next;
}ListNode;

typedef struct Queue
{
	ListNode* head;
	ListNode* tail;
}Queue;

void QueueInit(Queue* q)
{
	ListNode* First = (ListNode*)malloc(sizeof(ListNode));
	q->head = q->tail = First;
	q->tail->next = NULL;
}
int QueueEmpty(Queue* q)
{
	return q->head == q->tail;
}
void QueuePush(Queue* q, Datatype x)
{
	assert(q);
	q->tail->x = x;
	ListNode* NewNode = (ListNode*)malloc(sizeof(ListNode));
	q->tail->next = NewNode;
	q->tail = NewNode;
	q->tail->next = NULL;
}

void QueuePop(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	if (!QueueEmpty(q))
	{
		ListNode* temp = q->head->next;
		free(q->head);
		q->head = temp;
	}

}

Datatype QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->head->x;
}



void QueueDestroy(Queue* q)
{
	ListNode* cur = q->head;
	while (cur != q->tail)
	{
		ListNode* temp = cur->next;
		free(cur);
		cur = temp;
	}
	free(cur);
	cur = NULL;
	q->head = NULL;
	q->tail = NULL;

}
//前面的都是队列的操作的函数
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes) {
	if (root == NULL)
    {
        *returnSize=0;
        *returnColumnSizes=NULL;
        return NULL;
    }
	int** p = (int**)malloc(sizeof(int*));
	*p = NULL;
	int* q = (int*)malloc(sizeof(int*));
	Queue Q1;
	QueueInit(&Q1);
	QueuePush(&Q1, root);
	int colsize = 0;          //数组的个数,也就是行数
	int index = 1;   //每次数组的理论大小
	while (!QueueEmpty(&Q1))
	{
		int m = 0; //每一个数组实际上存了几个数,因为是NULL是不会进入数组的
        int k=0;

		for (int i = 0; i < index; i++)
		{
			if (!QueueEmpty(&Q1)&&QueueFront(&Q1))
			{
				p[colsize] = (int*)realloc(p[colsize], (m + 1) * sizeof(int)); //为新的元素重新调整数组的大小
				p[colsize][m] = QueueFront(&Q1)->val;
				m++;
				struct TreeNode* temp = QueueFront(&Q1);
                if(temp->left)
				QueuePush(&Q1, temp->left);
                if(temp->right)
				QueuePush(&Q1, temp->right);
                if(temp->left==NULL)
                k++;
                if(temp->right==NULL)
                k++;
			}

			if (!QueueEmpty(&Q1))
				QueuePop(&Q1);
			else
				break;
		}
		q = (int*)realloc(q, (colsize + 1) * sizeof(int));  //把每一行的元素个数存入数组
		q[colsize] = m;
        index=index*2-k;  //数组的理论大小要减去这一层空指针的个数
		colsize++;
		p = (int**)realloc(p,(colsize+1)*sizeof(int*));  //开辟下一行
		p[colsize] = NULL;
	}
	QueueDestroy(&Q1);
	*returnSize = colsize;
	*returnColumnSizes = q;
	return p;
}

例一:
如果一个二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK 中序遍历:HFIEJKG请画出这个二叉树:

二叉树 详解_第13张图片
首先通过先序遍历找到根节点然后在中序遍历里就可以找出对应的左子树右子树序列,再在根节点里画出相应的左子树和右子树序列,这样下一个子树的根节点也就找到了

二叉树的应用

二叉树节点个数

这其实如果对二叉树的遍历比较了解的话很简单,这里提供两种写法


typedef int DataType;
typedef struct BinaryTree
{
	DataType x;
	struct BinaryTree* _left;
	struct BinaryTree* _right;
}BT;
//二叉树节点个数
void BinaryTreeSize1(BT* root, int* x) //使用输出型参数,但要注意使用指针
{
	if (root == NULL)
		return;
	else
		*x+=1;
	BinaryTreeSize1(root->_left, x);
	BinaryTreeSize1(root->_right, x);
}

int BinaryTreeSize2(BT* root)  //直接递归的方法
{
	if (root == NULL)
		return 0;
	return BinaryTreeSize2(root->_left) + BinaryTreeSize2(root->_right) + 1; 

}
二叉树叶子节点的个数

这里的思路是把叶节点的个数分为:左子树的叶节点个数+右子树的叶节点的个数


typedef int DataType;
typedef struct BinaryTree
{
	DataType x;
	struct BinaryTree* _left;
	struct BinaryTree* _right;
}BT;
//二叉树叶子节点的个数
int BinaryTreeLeafSize(BT* root)
{
	if (root == NULL)
		return 0;
	if (root->_left == NULL&&root->_right==NULL)
		return 1;
	return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
	
}
二叉树第K层节点个数

本题思路:
把 第K层节点个数= 左子树第K层个数 + 右子树第K层的个数


typedef int DataType;
typedef struct BinaryTree
{
	DataType x;
	struct BinaryTree* _left;
	struct BinaryTree* _right;
}BT;
//二叉树第K层节点个数
int BinaryTreeLevelKSize(BT* root, int k)
{
	if (root == NULL)
		return 0;
	else
	{
		if (k == 1)
			return 1;
		else
			return  BinaryTreeLevelKSize(root->_left, k-1) + BinaryTreeLevelKSize(root->_right, k-1);
	}
}
二叉树的深度

本题思路:
把 二叉树的高度 = 左子树和右子树高度的最大值 +1

typedef int DataType;
typedef struct BinaryTree
{
	DataType x;
	struct BinaryTree* _left;
	struct BinaryTree* _right;
}BT;
//二叉树的深度
int Max(int x, int y)
{
	if (x > y)
		return x;
	else
		return y;
}
int BinaryTreeHeight(BT* root)
{
	if (root == NULL) //递归二叉树的终止条件
		return 0;

	return Max(BinaryTreeHeight(root->_left), BinaryTreeHeight(root->_right)) + 1;

}
二叉树查找值为x的节点

本题思路:
一直递归直到根节点为NULL,此时返回NULL表示没有找到
然后先在左子树递归,如果在左子树上找到了就直接返回,如果没有找到就返回右子树递归的结果

typedef int DataType;
typedef struct BinaryTree
{
	DataType x;
	struct BinaryTree* _left;
	struct BinaryTree* _right;
}BT;

BT* BinaryTreeFind(BT* root, DataType x)
{
	if (root == NULL)  //递归到root==NULL还没有找到就说明这棵树上没有
		return NULL;
	else
	{
		if (root->x == x)
			return root;
		else
		{
			BT* left = BinaryTreeFind(root->_left, x); 
			if (left)   //对左子树返回的值进行判断,如果不为空那么该值在左子树上
				return left;
			return BinaryTreeFind(root->_right, x);//走到这说明左子树上没有,那么一定在右子树上或者就根本没有
		}
	}
}
判断二叉树是不是完全二叉树

二叉树 详解_第14张图片
如果是一棵完全二叉树,用上面层序递归的思想进行入 队列 和出 队列 的操作,当队列里面出现第一个NULL指针时,后面必须全部是NULL指针直至队列为空。 根据这个条件,我们还是按照原来的循环写法,只不过在前面加一个判断条件,让其在第一个NULL时停下来,接下来再写一个循环判断后面是否有非空的指针。

typedef int DataType;
typedef struct BinaryTree
{
	DataType x;
	struct BinaryTree* _left;
	struct BinaryTree* _right;
}BT;
//判断二叉树是不是完全二叉树
bool BinaryTreeComplete(BT* ps)
{
	int ret = 1;
	Queue p;
	QueueInit(&p);
	if (ps != NULL)
	{
		QueuePush(&p, ps);

	}
	while (!QueueEmpty(&p))
	{
		BT* front = QueueFront(&p);
		QueuePop(&p);
		if (front == NULL)
			break;
		QueuePush(&p, front->_left);
		QueuePush(&p, front->_right);
	}
	while (!QueueEmpty(&p))
	{
		BT* front = QueueFront(&p);
		QueuePop(&p);
		if (front != NULL)
			return false;
	}
	QueueDestroy(&p);
	return true;
}
通过前序遍历数组来构建二叉树

牛客网原题

二叉树 详解_第15张图片
这题的难点在于如何将线序遍历的数组转换成二叉树
这其实和线序遍历是一样的 ,按照“根 左 右”的顺序创建节点就可以了,当遇到’#'时,左子树就建立完成了,接着要创建右子树(右子树还是按上面的步骤建立)


#include
#include

typedef char DataType;
typedef struct BinaryTree
{
    DataType x;
    struct BinaryTree* _left;
    struct BinaryTree* _right;
}BT;

BT* CreatTree(char* s, int* i)  //这里传地址是因为  要保证递归再回溯的过程中,s[i]不会倒退
{
    if(s[*i]!='\0')
    {
        BT *p=(BT *)malloc(sizeof(BT));
        if(s[*i]!='#')
        {
            p->x=s[*i];
            *i+=1;
            p->_left=CreatTree(s, i);
            *i+=1;
            p->_right=CreatTree(s, i);
        }
        else{
            return NULL;
        }
        return p;
    }
    return NULL;
}

void Inorder(BT* root)
{
    if (root != NULL)
    {
        Inorder(root->_left);
    }
    else
    {
        return;
    }
    printf("%c ", root->x);
    Inorder(root->_right);
}
int main()
{
    char s[100];
    scanf("%s", s);
    BT *ps;
    int i = 0;
    ps=CreatTree(s,&i );
    Inorder(ps);
    return 0;
}

二叉树OJ

单值二叉树

Leetcode-单值二叉树

本题思路:
如果能判断到root为NULL就说明该子树为单值二叉树,做这种题一般 一个最终终止条件若干个题目条件(一般判断的都是不满足的情况,这样到最后的终止条件就一定满足情况)
这里的题目条件就是在左右节点都存在的情况下,根节点与左右节点的值相等。
最终二叉树是否为单值二叉树 = 左子树是否为单值二叉树 && 左子树是否为单值二叉树


bool isUnivalTree(struct TreeNode* root){
    if(root==NULL)  //终止条件
    return true;
    
    if(root->right&&root->val!=root->right->val) //题目条件
    return false;

    if(root->left&&root->val!=root->left->val)   //题目条件
    return false;

    return isUnivalTree(root->left)&&isUnivalTree(root->right); //左子树和右子树是否为单值二叉树是 与 的关系
 
}
检查两棵树是否相同

leetcode-原题

思路:
两颗树的节点 有三种情况:

  1. 两个节点都为空,这是终止条件
  2. 题目条件:一个为空一个不为空,这是return false
  3. 题目条件:两个都不为空,但是节点的值不相同,这里 return false

最后 如果根节点是相同的 ,那么如果他的左子树和右子树也是相同的,整个树也就是相同的
所以最后的条件是&&

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p==NULL && q==NULL)
    return true;

    if(p==NULL || q==NULL)
    return false;

    if(p->val!=q->val)
    return false;

    return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);

}
对称二叉树

leetcode-对称二叉树
思路:
这里可以用上面的函数,但注意因为对称二叉树,所以在递归时候参数要稍微改一下
如果根节点存在 且 左子树与右子树对称 则返回True 否则就返回false


bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p==NULL && q==NULL)
    return true;

    if(p==NULL || q==NULL)
    return false;

    if(p->val!=q->val)
    return false;

    return isSameTree(p->left,q->right)&&isSameTree(p->right,q->left);
}

bool isSymmetric(struct TreeNode* root){
    
    if(root&&isSameTree(root->left,root->right))
    return true;
    return false;
}
另一棵树的子树

leetcode 原题
思路:
这里可以用上面的函数,
终止条件: root为空也就是找到根节点为空时,还没找到相同的子树,所以要返回false
题目条件:

  1. 如果root与subroot相同,就返回true,否则就返回false
  2. 如果不相等就继续向下递归,但是这里要注意两个子树的逻辑的关系,只要在一棵树上找到与subroot相同的子树,返回的就是true,所以要用||

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p==NULL && q==NULL)
    return true;

    if(p==NULL || q==NULL)
    return false;

    if(p->val!=q->val)
    return false;

    return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);

}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
    if(root==NULL)
    return false;

    if(isSameTree(root,subRoot))
    {
        return isSameTree(root,subRoot);
    }
    return isSubtree(root->left,subRoot) || isSubtree(root->right ,subRoot);
}

后续还会更新,博客有问题的地方欢迎指正!

你可能感兴趣的:(数据结构和算法,数据结构,算法,二叉树)