【数据结构】二叉树

本文详细介绍了二叉树在链式存储下的结构,包括节点创建、前序、中序、后序和层序遍历算法,以及计算节点总数、叶子节点数、特定层节点数、树的深度以及查找节点和判断是否为完全二叉树的方法。
摘要由CSDN通过智能技术生成

在上一节中,讲了二叉树的顺序结构的存储,顺序结构适合于完全二叉树,那么不是完全二叉树的二叉树在内存中要怎么存储呢?这时候需要用到链式存储。

1、二叉树结点的创建

在链式二叉树中,一个结点需要保存其数值,以及左孩子和右孩子的指针。

typedef char BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

2、二叉树的遍历

2、1二叉树的前序遍历

前序遍历也被称为先根遍历,也就是先遍历根,再左子树,最后右子树。

注意,这里当遍历完一个根后,不是遍历左孩子,而是左子树。

这里把空指针也打印出来,是为了能够更好的理解遍历的过程

void PrevOrder(BTNode* root)//前序遍历
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%c ", root->_data);
	PrevOrder(root->_left);
	PrevOrder(root->_right);
}

2、2二叉树的中序遍历

中序遍历也被称为中根遍历,也就是先左子树,再根,最后右子树

void InOrder(BTNode* root)//中序遍历
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->_left);
	printf("%c ", root->_data);
	InOrder(root->_right);
}

2、3二叉树的后序遍历

后序遍历也被称为后根遍历,也就是先左子树,再右子树,最后根

void PostOrder(BTNode* root)//后序遍历
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->_left);
	PostOrder(root->_right);
	printf("%c ", root->_data);
}

2、4二叉树的层序遍历

二叉树的前序遍历也就是一层一层的遍历二叉树,此时需要用到队列先进先出的性质。将队列中的结点树数据域存放二叉树结点的指针,首先将二叉树的根结点放入队列,然后出队列,出队列的同时,如果出的这个结点不为空,那么就将它的左右孩子也放进队列,直到二叉树结束。

void BinaryTreeLevelOrder(BTNode* root)//层序遍历,在队列中存放的是二叉树一个结点的指针,因为这样子才可以把左右子树带入队列
{
	Queue q;
	QueueInit(&q);
	if (root == NULL)
		return;
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			printf("%c ", front->_data);
			//带入下一层
			QueuePush(&q, front->_left);
			QueuePush(&q, front->_right);
		}
		else
		{
			printf("NULL ");
		}
	}
	QueueDestory(&q);
	printf("\n");
}

3、计算二叉树结点的个数

int TreeSize(BTNode* root)//返回总结点的个数
{
	if (root == NULL)
		return 0;
	else
		return 1 + TreeSize(root->_left) + TreeSize(root->_right);
}

注意,这里不是前序,而是后序

因为只有当左右子树的大小算出来后,才能算当前树,所以是后序

4、计算叶子结点的个数

int TreeLeafSize(BTNode* root)//返回叶子结点的个数
{
	if (root == NULL)
		return 0;
	if (root->_left == NULL && root->_right == NULL)
		return 1;
	else
		return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);
}

5、求第k层结点个数

int BinaryTreeLevelKSize(BTNode* root, int k)//求第K层结点个数
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}

6、计算树的深度

int TreeDepth(BTNode* root)//返回树的深度
{
	//if (root == NULL)
	//	return 0;
	//else
	//	return 1 + (TreeDepth(root->_left) > TreeDepth(root->_right) ? TreeDepth(root->_left) : TreeDepth(root->_right));
	但这样会造成重复递归
	if (root == NULL)
		return 0;
	int leftDepth = TreeDepth(root->_left);
	int rightDepth = TreeDepth(root->_right);
	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;//这样子就不会重复递归了
}

7、查找值x是否在二叉树中

BTNode* binaryTreeFind(BTNode* root, BTDataType x)//查找值为x的结点是否在二叉树中
{
	if (root == NULL)
		return NULL;
	if (root->_data == x)
		return root;
	BTNode* flag = binaryTreeFind(root->_left, x);//用一个flag来记录左子树有没有x,没有再到右子树取找
	if (flag == NULL)
		flag = binaryTreeFind(root->_right, x);
	return flag;
}

8、判断一颗二叉树是否是完全二叉树

利用了层序遍历

void BinaryTreeComplete(BTNode* root)//判断一棵树是不是完全二叉树,是返回1,不是返回0
{//是完全二叉树,则在队列中数值和NULL是分开的,不是完全二叉树则数值和NULL是在一起的
	Queue q;
	QueueInit(&q);
	if (root == NULL)
		return 1;
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front == NULL)
			break;
		QueuePush(&q, front->_left);
		QueuePush(&q, front->_right);
	}
	while (!QueueEmpty(&q))//取出队列中的所有元素,如果有非空的就不是完全二叉树,返回0
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
			return 0;
	}
	return 1;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值