二叉树的增删查改

本节复习二叉树的增删查改, 二叉树的知识相对于前面的循序表, 链表, 以及栈和队列都要多一些。 同时二叉树的增删查改理解起来相对来说要困难一些。 本节来好好复习一下二叉树的增删查改。

2024-5-12——子树不能相交

目录

准备文件

创建结构体蓝图

二叉树的前序遍历

二叉树的后序遍历

二叉树的中序遍历

二叉树的节点个数

二叉树的叶子节点个数

二叉树的深度

判断二叉树是否为平衡二叉树

二叉树节点销毁


准备文件

首先准备好三个文件:

一个文件用于main.c调试, 一个文件用于二叉树函数的声明, 还有一个.c文件用于二叉树函数的实现。 

创建结构体蓝图

首先包含一下头文件和重新定义一下我们要保存的数据类型。 这样做是为了便于维护我们的代码

///二叉树的增删查改/
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
#include<assert.h>


typedef int TNDataType;

然后创建结构体

///二叉树的增删查改/
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
#include<assert.h>


typedef int TNDataType;

typedef struct TreeNode 
{
	struct TreeNode* left;
	struct TreeNode* right;
	TNDataType data;
}TNode;

二叉树的前序遍历

.h函数声明

二叉树的遍历方式分为前序遍历,中序遍历, 后续遍历,层序遍历三种方式。 这里先来前序遍历。同时这里也会利用图画来展示遍历的过程。 中序遍历和后续遍历和前序遍历方式类似。 就不画了。

///二叉树的增删查改/
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
#include<assert.h>


typedef int TNDataType;

typedef struct TreeNode 
{
	struct TreeNode* left;
	struct TreeNode* right;
	TNDataType data;
}TNode;

///接口函数的声明///

//二叉树的前序遍历
void PrevOrder(TNode* root);

.c函数实现

递归的代码写起来都比较简单。 但是要注意结束的条件。 以及递归的条件。

//前序遍历
void PrevOrder(TNode* root) 
{

	if (root == NULL) 
	{
		return;
	}
	printf("%d ", root->data);//每一个根节点都有左子树和右子树,这三行代码的意思是先访问根节点。 
								//然后访问左子树, 再访问右子树。然后访问左右子树的时候, 又先访问根节点, 再访问该子树的左右子树
	PrevOrder(root->left);
	PrevOrder(root->right);
}

二叉树的后序遍历

.h函数声明

///二叉树的增删查改/
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
#include<assert.h>


typedef int TNDataType;

typedef struct TreeNode 
{
	struct TreeNode* left;
	struct TreeNode* right;
	TNDataType data;
}TNode;

///接口函数的声明///

//二叉树的前序遍历
void PrevOrder(TNode* root);

//二叉树的后序遍历
void PostOrder(TNode* root);

.c函数实现

//后序遍历
void PostOrder(TNode* root) 
{
	if (root == NULL) 
	{
		return;
	}
	PostOrder(root->left);     //每一个根节点都有左右子树, 这三行代码的意思是先访问左右子树, 最后在访问根节点, 然后
							   //在访问每一棵左右子树的时候又先访问该子树的左右子树, 然后层层递归
	PostOrder(root->right);
	printf("%d ", root->data);

}

二叉树的中序遍历

.h函数声明

///二叉树的增删查改/
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
#include<assert.h>


typedef int TNDataType;

typedef struct TreeNode 
{
	struct TreeNode* left;
	struct TreeNode* right;
	TNDataType data;
}TNode;

///接口函数的声明///

//二叉树的前序遍历
void PrevOrder(TNode* root);

//二叉树的后序遍历
void PostOrder(TNode* root);

//二叉树的中序遍历
void MidOrder(TNode* root);

.c函数实现

//中序遍历
void MidOrder(TNode* root)
{
	if (root == NULL) 
	{
		return;
	}
	MidOrder(root->left);		//在每一个根节点都有左右子树, 这三行代码的意思是先访问左子树, 
								//再访问根节点, 最后再访问右子树, 然后, 当访问左子树的时候, 左子树又有左子树, 就又访问
								// 该子树的左子树, 直到遇到子树为空。  
	printf("%d ", root->data);
	MidOrder(root->right);
}

二叉树的节点个数

二叉树的节点个数,可以利用指针参数的形式。 每递归进一个函数,就让指针指向的参数加一。 然后遍历整颗二叉树就能得到节点个数。 也可以使用返回值的方式,如下就是返回值方式

我们可以这样想。 如果左树或者右树是空树,那么就返回0.

如果不是空树就返回1。 

.h函数声明

///二叉树的增删查改/
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
#include<assert.h>


typedef int TNDataType;

typedef struct TreeNode 
{
	struct TreeNode* left;
	struct TreeNode* right;
	TNDataType data;
}TNode;

///接口函数的声明///

//二叉树的前序遍历
void PrevOrder(TNode* root);

//二叉树的后序遍历
void PostOrder(TNode* root);

//二叉树的中序遍历
void MidOrder(TNode* root);

//二叉树的层序遍历层序遍历
void LevelOrder(TNode* root);

//二叉树计算节点个数
int SumTree(TNode* root);

.c函数实现


//二叉树计算节点个数
int SumTree(TNode* root) 
{
	if (root == NULL)//空节点代表着0个节点, 所以返回0个节点 
	{
		return 0;
	}
	//代码走到这, 说明不是空节点, 不是空节点那么节点就应该加一
	return SumTree(root->left) + SumTree(root->right) + 1;//节点加1, 同时遍历左右两棵子树。
}

二叉树的叶子节点个数

想要看叶子节点个数, 只要左树为空, 右树为空。 那么就是叶子节点个数。 

碰到叶子节点就可以返回了, 不需要再往下遍历, 因为继续遍历一定是空树。 所以可以使用前序遍历来计算叶子节点个数。 

.h函数声明

///二叉树的增删查改/
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
#include<assert.h>


typedef int TNDataType;

typedef struct TreeNode 
{
	struct TreeNode* left;
	struct TreeNode* right;
	TNDataType data;
}TNode;

///接口函数的声明///

//二叉树的前序遍历
void PrevOrder(TNode* root);

//二叉树的后序遍历
void PostOrder(TNode* root);

//二叉树的中序遍历
void MidOrder(TNode* root);

//二叉树的层序遍历层序遍历
void LevelOrder(TNode* root);

//二叉树计算节点个数
int SumTree(TNode* root);

//二叉树计算叶子个数
int LeafSumTree(TNode* root);

.c函数实现


//二叉树计算叶子个数
int LeafSumTree(TNode* root) 
{
	if (root->left == NULL && root->right == NULL) 
	{
		return 1;
	}
	int left = LeafSumTree(root->left);//查看左子树
	int right = LeafSumTree(root->right);//查看右子树, 为什么要用right?因为返回值带着计算的节点个数, 如果这两个递归函数
										//不接收返回值, 那么就相当于只有遍历到叶子节点的时候返回节点,接收到叶子节点返回值
										//的节点不能继续将值返回给父节点。 
	return left + right;
}

二叉树的深度

计算二叉树的深度需要比较左右子树的深度。哪个深, 二叉树的深度就是哪一个的深度加上1.

同样是空树就返回1.不是空树就返回左右树大的那个的值的加1.

.h函数声明

///二叉树的增删查改/
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
#include<assert.h>


typedef int TNDataType;

typedef struct TreeNode 
{
	struct TreeNode* left;
	struct TreeNode* right;
	TNDataType data;
}TNode;

///接口函数的声明///

//二叉树的前序遍历
void PrevOrder(TNode* root);

//二叉树的后序遍历
void PostOrder(TNode* root);

//二叉树的中序遍历
void MidOrder(TNode* root);

//二叉树的层序遍历层序遍历
void LevelOrder(TNode* root);

//二叉树计算节点个数
int SumTree(TNode* root);

//二叉树计算叶子个数
int LeafSumTree(TNode* root);

//二叉树的深度
int TallTree(TNode* root);

.c函数实现


//计算树的深度
int TallTree(TNode* root) //计算树的深度的核心就是左右子树哪个高, 在他的基础上加1。
{
	if (root == NULL) 
	{
		return 0;
	}
	//
	int left = TallTree(root->left);
	int right = TallTree(root->right);
	return (left > right) ? (left + 1) : (right + 1);
}

判断二叉树是否为平衡二叉树

.h函数声明

///二叉树的增删查改/
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
#include<assert.h>


typedef int TNDataType;

typedef struct TreeNode 
{
	struct TreeNode* left;
	struct TreeNode* right;
	TNDataType data;
}TNode;

///接口函数的声明///

//二叉树的前序遍历
void PrevOrder(TNode* root);

//二叉树的后序遍历
void PostOrder(TNode* root);

//二叉树的中序遍历
void MidOrder(TNode* root);

//二叉树的层序遍历层序遍历
void LevelOrder(TNode* root);

//二叉树计算节点个数
int SumTree(TNode* root);

//二叉树计算叶子个数
int LeafSumTree(TNode* root);

//二叉树的深度
int TallTree(TNode* root);

//判断是否为平衡二叉树
bool TreeEqual(TNode* root);

.c函数实现

//计算树的深度
int TallTree(TNode* root) //计算树的深度的核心就是左右子树哪个高, 在他的基础上加1。
{
	if (root == NULL) 
	{
		return 0;
	}
	//
	int left = TallTree(root->left);
	int right = TallTree(root->right);
	return (left > right) ? (left + 1) : (right + 1);
}

二叉树节点销毁

节点销毁就是free掉节点。 需要使用后续遍历销毁。 因为如果是前序或者中序的话。 先销毁节点。 那么左右树就找不到了。

.h函数声明

///二叉树的增删查改/
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
#include<assert.h>


typedef int TNDataType;

typedef struct TreeNode 
{
	struct TreeNode* left;
	struct TreeNode* right;
	TNDataType data;
}TNode;

///接口函数的声明///

//二叉树的前序遍历
void PrevOrder(TNode* root);

//二叉树的后序遍历
void PostOrder(TNode* root);

//二叉树的中序遍历
void MidOrder(TNode* root);

//二叉树的层序遍历层序遍历
void LevelOrder(TNode* root);

//二叉树计算节点个数
int SumTree(TNode* root);

//二叉树计算叶子个数
int LeafSumTree(TNode* root);

//二叉树的深度
int TallTree(TNode* root);

//判断是否为平衡二叉树
bool TreeEqual(TNode* root);

//二叉树销毁
void TreeDestroy(TNode* root);

.c函数实现


//二叉树的销毁
void TreeDestroy(TNode* root) //二叉树的销毁应该是一个后序遍历
{
	if (root->left == NULL && root->right == NULL)
	{
		free(root);
		root = NULL;
		return;
	}
	else 
	{
		if (root->left != NULL) 
		{
			TreeDestroy(root->left);

		}
		else if (root->right != NULL)
		{
			TreeDestroy(root->right);

		}
	}
	

}

  • 34
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值