数据结构————二叉树的遍历和应用

本文详细探讨了数据结构中的二叉树概念,重点讲解了二叉树的前序、中序和后序遍历方法,并通过C语言实现。此外,还介绍了二叉树在实际问题中的应用,包括搜索、排序和文件系统等场景。
摘要由CSDN通过智能技术生成
typedef char BTDataType;



typedef struct BinaryTreeNode

{

	BTDataType _data;

	struct BinaryTreeNode* _left;

	struct BinaryTreeNode* _right;

}BTNode;
//函数声明``
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树

BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);

// 二叉树销毁

void BinaryTreeDestory(BTNode** root);

// 二叉树节点个数

int BinaryTreeSize(BTNode* root);

// 二叉树叶子节点个数

int BinaryTreeLeafSize(BTNode* root);

// 二叉树第k层节点个数

int BinaryTreeLevelKSize(BTNode* root, int k);

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

BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

// 二叉树前序遍历 

void BinaryTreePrevOrder(BTNode* root);

// 二叉树中序遍历

void BinaryTreeInOrder(BTNode* root);

// 二叉树后序遍历

void BinaryTreePostOrder(BTNode* root);

// 层序遍历

void BinaryTreeLevelOrder(BTNode* root);

// 判断二叉树是否是完全二叉树

int BinaryTreeComplete(BTNode* root);
 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
//前序创建,#代表NULL
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{//a为数组,n为数组长度,pi是我们在调用当前函数的函数作用域内定义的变量,用来控制当前a所指向的数据
 //为什么要在外面定义变量传变量地址过来?
//因为这个函数用的是递归,递归是函数内部调用自己,而调用函数就会开辟新的栈帧,如果我们在函数内定义变量
 //每次调用自己的时候就开辟一个新的空间,然后再创建另一个pi,两个变量作用域不同,地址也不同
 //值的改变也不影响对方,那我们在使用函数的时候,数组a就有可能取不到后面的数据
	assert(a);
	if (*pi > n)//判断是否越界
		return NULL;
	if (a[*pi] == '#')
	{//为空表示当前节点为NULL,结束函数,并返回NULL
		(*pi)++;//解引用再++,让指针指向下一个数据
		return NULL;
	}
	//不为空
	BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));//创建根
	if (newNode == NULL)
	{
		exit(-1);//申请失败
	}
	newNode->_data = a[(*pi)++];//把数组当前数据放入_data
	newNode->_left = BinaryTreeCreate(a, n, pi);//把当前根的左子节点重复上面的步骤
	newNode->_right = BinaryTreeCreate(a, n, pi);//把当前根的右子节点重复上面的步骤
	return newNode;//返回树的根
}
//打印
void BinaryTreePrint(BTNode* root)
{
	if (root == NULL)
		return;
	printf("%c ",root->_data);
	BinaryTreePrint(root->_left);
	BinaryTreePrint(root->_right);
}
// 二叉树销毁

void BinaryTreeDestory(BTNode** root)
{
	if (root == NULL)
		return;

	BinaryTreeDestory((*root)->_left);
	BinaryTreeDestory((*root)->_right);
	free(root);
	root = NULL;
	
}
// 二叉树节点个数

int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
		//返回根加它的子节点数量,当前根节点为空就返回0
	return BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right) + 1;
}
// 二叉树叶子节点个数

int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
		//叶子定义:无子节点
	if (root->_left == NULL&&root->_right == NULL)
		return 1;
		//返回左子节点加右子节点的叶子数量
	return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}
// 二叉树查找值为x的节点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	//利用前序遍历的思想来找
	if (root == NULL)
		return NULL;
	if (root->_data == x)
		return root;
		//分别沥遍左右子节点,在每次拿到返回值后就判断,避免已找到但树还没遍历完情况下还在继续找
	struct BinaryTreeNode* newleft = BinaryTreeFind(root->_left, x);
	if (newleft)
		return newleft;
	struct BinaryTreeNode* newright= BinaryTreeFind(root->_right, x);
	if (newright)
		return newright;
	return NULL;

}
// 二叉树第k层节点个数

int BinaryTreeLevelKSize(BTNode* root, int k)
{//看有几个节点在k层,让节点往下走,递归传参的时候k-1,当k=1的时候说明这个节点在k层,返回1
//当节点为空是返回0,不再往下走
	assert(k >= 1);
	if (k == 1)
		return 1;
	if (root==NULL)
		return 0;
	
	return BinaryTreeLevelKSize(root->_left, k-1) + BinaryTreeLevelKSize(root->_right, k-1);
	
}
// 二叉树前序遍历 

void BinaryTreePrevOrder(BTNode* root)
{//先打印根节点再分别递归打印左右子节点
	if (root == NULL)
	{
		return;
	}
	printf("%c ", root->_data);
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);
}

// 二叉树中序遍历

void BinaryTreeInOrder(BTNode* root)
{//先打印左子节点再分别递归打印根节点和右子节点
	if (root == NULL)
	{
		return;
	}
	BinaryTreeInOrder(root->_left);
	printf("%c ", root->_data);
	BinaryTreeInOrder(root->_right);
	
}

// 二叉树后序遍历

void BinaryTreePostOrder(BTNode* root)
{//先递归把左右子节点打印好,再打印根节点
	if (root == NULL)
	return ;

	BinaryTreePostOrder(root->_left);
	BinaryTreePostOrder(root->_right);
	printf("%c ", root->_data);
}
// 层序遍历

void BinaryTreeLevelOrder(BTNode* root)
{//利用队列结构实现层序遍历,队列结构是一头用来出数据,一头用来入数据
//队列遵循先进先出,后进后出的规则,想拿到后面的数据就得把前面的先拿走
//我们先把根节点入进去,在取出来的时候把它的子节点入进去
	QuState qu;//创建队列
	QueueInit(&qu);//队列初始化
	QueuePush(&qu, root);//把根插入
	while (QueueEmpty(&qu))//判断队列是否为空
	{
		QDataType cur = QueueTop(&qu);//取对顶数据
		printf("%c ", cur->_data);//打印
		QueuePop(&qu);//删除对顶数据
		//子节点不为空就插入到队列中
		if (cur->_left)
			QueuePush(&qu, cur->_left);
		if (cur->_right)
			QueuePush(&qu, cur->_right);

	}
	printf("\n");
	QueueDestroyed(&qu);//记得销毁队列
}
// 判断二叉树是否是完全二叉树

bool BinaryTreeComplete(BTNode* root)
{//完全二叉数的特点:叶子节点只能出现在最下层和次下层,且最下层的叶子节点集中在树的左边
//层序遍历数,如果遇到空节点后队列还不为空,那此树就不是完全二叉树
	QuState qu;//创建对列
	QueueInit(&qu);//对列初始化
	QueuePush(&qu, root);//插入根
	while (QueueEmpty(&qu))//队列是否为空
	{
		BTNode* cur = QueueTop(&qu);//取对顶
		QueuePop(&qu);//出对顶
		if (cur == NULL)//为空结束循环
		{
			break;
		}
		else
		{//反之入左右子节点
			QueuePush(&qu,cur->_left);
			QueuePush(&qu,cur->_right);
		}
	}
//走到这里后会有两种情况,一种是队列为空了,一种是走到树的空节点了
	//
	while (QueueEmpty(&qu))//判断队列是否为空
	{//一直出对顶数据,直至对为空
		QDataType* cur = QueueTop(&qu);
		QueuePop(&qu);
		if (cur)//不为NULL,则说明不是完全二叉树
		{
			QueueDestroy(&qu);//销毁队列
			return false;//返回假
		}
	}
	QueueDestroy(&qu);//销毁队列
	return true;//返回真
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值