二叉树的拷贝和释放操作

2021-03-08 12:19:26 浏览数 (1)

思路:先通过递归一直找到叶子(即最后一层结点),再回溯,拷贝叶子的左子树,再右子树,然后重复往上面根结点回溯,直到最上层的根结点

释放:释放在堆区创建的结点

代码语言:javascript复制
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
//二叉树的递归遍历
struct BinaryNode 
{
	//数据域
	char ch;
	//指针域
	BinaryNode* lchild; //指向左孩子的指针
	BinaryNode* rchild; //指向右孩子的指针
};
//二叉树拷贝:返回新拷贝的二叉树根
//拷贝注意深拷贝和浅拷贝
BinaryNode* copyTree(BinaryNode* root)
{
	if (root == NULL)
		return NULL;
	//先拷贝左子树下面的所有结点
	BinaryNode* lchild = copyTree(root->lchild);
	//再拷贝右子树下面的所有结点
	BinaryNode* rchild = copyTree(root->rchild);

	//拷贝根结点:每一次递归都要在堆区开辟一块空间来存储当前的结点
	BinaryNode* newNode = (BinaryNode*)malloc(sizeof(BinaryNode));
	//把值拷贝到新的根
	newNode->ch = root->ch;
	//每次递归,把当前结点根下的左子树和右子树拷贝过来
	newNode->lchild = lchild;
	newNode->rchild = rchild;
	//每一次递归返回当前根结点
	return newNode;
}
//递归遍历
void output_node(BinaryNode* root)
{
	//如果当前根为空,说明1:传入的根结点为空
	//2:递归到叶子结点下一层,为空结点,返回上一层的根结点函数内部
	if (root == NULL)
		return;
    //先序遍历
	printf("%c ", root->ch);
	//每次递归查看左子树下面有没有结点可以打印
	output_node(root->lchild);
	//每次递归查看右子树下面有没有结点可以打印
	output_node(root->rchild);
}
//求叶子数量:如果一个根结点的左右子树都为空,说明是叶子
int getLeafNum(BinaryNode* root)
{
	if (root == NULL)
		return NULL;
	//叶子的数量:静态变量只会初始化一次
	static int num;
	//获取左子树
	BinaryNode *lchild = root->lchild;
	//获取右子树
	BinaryNode* rchild = root->rchild;
	//找到一个叶子
	if (lchild == NULL && rchild == NULL)
	{
		num  ;
	}
	//递归:查看当前根的左子树和右子树是否是叶子
	getLeafNum(root->lchild);
	getLeafNum(root->rchild);
	return num;
}
//求二叉树的高度(深度):一个根结点中左右子树中最大层数加一
int getTreeHeight(BinaryNode* root)
{
	//如果当前结点为空,1.传入根结点为空,说明当前二叉树的层数为0
	//2.为叶子的下一层:层数为0
	if (root == NULL)
		return 0;
	//获取当前根结点左子树高度
	int lheight = getTreeHeight(root->lchild);
	//获取当前根结点右子树高度
	int rheight = getTreeHeight(root->rchild);
	//判断左右子树谁大,取大加一
	return lheight > rheight ? lheight 1 : rheight 1;
}
//二叉树的释放
void freeTree(BinaryNode* root)
{
	//如果根结点为空:1.传入的根结点为空或
	//2.为叶子结点下一层
	if (root == NULL)
	{
		return;
	}
	//先通过递归找到叶子层,再往上一层层释放根节点,直到最上层根结点
	//先释放左子树的所有结点
	freeTree(root->lchild);
	//再释放右子树所有的结点
	freeTree(root->rchild);
	//释放过程演示
	printf("%c结点被释放n", root->ch);
	//释放
	free(root);
}
void output()
{
	BinaryNode Anode = { 'A',NULL,NULL };
	BinaryNode Bnode = { 'B',NULL,NULL };
	BinaryNode Cnode = { 'C',NULL,NULL };
	BinaryNode Dnode = { 'D',NULL,NULL };
	BinaryNode Enode = { 'E',NULL,NULL };
	BinaryNode Fnode = { 'F',NULL,NULL };
	BinaryNode Hnode = { 'H',NULL,NULL };
	BinaryNode Gnode = { 'G',NULL,NULL };
	//建立关系
	Anode.lchild = &Bnode;
	Anode.rchild = &Fnode;

	Bnode.rchild = &Cnode;
	Cnode.lchild = &Dnode;
	Cnode.rchild = &Enode;

	Fnode.rchild = &Gnode;
	Gnode.lchild =&Hnode;
   //二叉树的拷贝:传入最上层的根结点,通过根结点一层层往下找到叶子,再往上面进行回溯
	BinaryNode* newNode =copyTree(&Anode);
	//打印
	output_node(newNode);
	//叶子
	printf("n叶子数量:%dn", getLeafNum(newNode));
	//树高
	printf("树的高度:%dn", getTreeHeight(newNode));
	//释放二叉树:释放在堆区创建的二叉树
	freeTree(newNode);
}
int main()
{
	output();
	return 0;
}

拷贝函数简化版

代码语言:javascript复制
//二叉树拷贝:返回新拷贝的二叉树根
//拷贝注意深拷贝和浅拷贝
BinaryNode* copyTree(BinaryNode* root)
{
	if (root == NULL)
		return NULL;

	//拷贝根结点:每一次递归都要在堆区开辟一块空间来存储当前的结点
	BinaryNode* newNode = (BinaryNode*)malloc(sizeof(BinaryNode));
	//每次递归,把当前结点根下的左子树和右子树拷贝过来
	newNode->lchild = copyTree(root->lchild);
	newNode->rchild = copyTree(root->rchild);
	//把值拷贝到新的根
	newNode->ch = root->ch;
	//每一次递归返回当前根结点

或者

代码语言:javascript复制
//二叉树拷贝:返回新拷贝的二叉树根
//拷贝注意深拷贝和浅拷贝
BinaryNode* copyTree(BinaryNode* root)
{
	if (root == NULL)
		return NULL;

	//拷贝根结点:每一次递归都要在堆区开辟一块空间来存储当前的结点
	BinaryNode* newNode = (BinaryNode*)malloc(sizeof(BinaryNode));
	//把值拷贝到新的根
	newNode->ch = root->ch;
	//每次递归,把当前结点根下的左子树和右子树拷贝过来
	newNode->lchild = copyTree(root->lchild);
	newNode->rchild = copyTree(root->rchild);
	//每一次递归返回当前根结点

0 人点赞