二叉树的链式存储

1.二叉树的概念和性质

一,概念
1.五种形态:

  • 为空
  • 不为空
    • 根节点
    • 根节点+左子树
    • 根节点+右子树
    • 根节点+左子树+右子树

2.二叉树不存在度>2的节点
3.二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
在这里插入图片描述
二,性质

1.规定根节点的层数为1,则一棵非空二叉树的第k层上最多有2^(k-1)个节点
2.规定根节点的层数为1,则深度为h的二叉树的最大节点个数为2^h-1
3.对于任意一棵二叉树,n0(度为0的节点个数)=n2(度为2的节点个数)+1
4.规定根节点的层数是1,具有n个节点的满二叉树的深度,h=log(N+1).(ps:log是以2为底的对数)

2.二叉树的链式存储

typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType val;
	struct BinaryTreeNode* left;//左孩子
	struct BinaryTreeNode* right;//右孩子
}BTNode;

2.1二叉树的遍历

2.1.1前中后遍历

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

1.前序遍历:根节点 ,左子树, 右子树
2.中序遍历:左子树 ,根节点 ,右子树
3.后序遍历:左子树 ,右子树, 根节点

前,中,后序代码都是差不多的,唯一区别在于打印的位置不一样

前序遍历:void BinaryTreePrevOrder(BTNode* root);

//二叉树的前序遍历
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("#");
		return;
	}
	printf("%c", root->val);
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
}

在这里插入图片描述

中序遍历:void BinaryTreeInOrder(BTNode* root);

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("#");
		return;
	}
	BinaryTreeInOrder(root->left);
	printf("%c", root->val);
	BinaryTreeInOrder(root->right);
}

后序遍历:void BinaryTreePostOrder(BTNode* root);

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("#");
		return;
	}
	BinaryTreePostOrder(root->left);
	BinaryTreePostOrder(root->right);
	printf("%c", root->val);
}

2.1.2层次遍历

层次遍历是自上而下,自左至右逐层访问树的节点的过程
层次遍历需要借助队列来完成
思想:将根节点入队,然后再出队,出队时,将其根节点的左节点和右节点入队。后面操作与前面一样,直到队列为空表明层次遍历完成

// 层序遍历--需要建立一个队列
void BinaryTreeLevelOrder(BTNode* root)
{
	Queue q;
	QInint(&q);//初始化
	if (root)
		QPush(&q, root);//先将根节点入队
	while (!QEmpty(&q))
	{
		QDataType fornt = GetFront(&q);
		QPop(&q);

		printf("%c ", fornt->val);
		if (fornt->left)
			QPush(&q, fornt->left);
		if (fornt->right)
			QPush(&q, fornt->right);
	}
	Qdestroy(&q);//销毁队列
}

在这里插入图片描述

2.2求节点的个数

思路:
1.如果二叉树为空,返回0
2.二叉树不为空

分成三部分:根节点,左子树,右子树。返回左子树+右子树+1

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

2.3求叶子节点的个数

思路:
二叉树为空,返回0
二叉树不为空

只有一个节点,返回1.
多于一个节点,分成左子树和右子树递归
ps:叶子节点是左子树和右子树都为空的节点

// 二叉树叶子节点个数
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);
}

2.4求第k层节点个数

思路:
二叉树为空,返回0
二叉树不为空

如果k==1,返回1
k>1,左子树的k-1层+右子树的k-1层

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

2.5二叉树的销毁

// 二叉树销毁--后序销毁
void BinaryTreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	BinaryTreeDestory(root->left);
	BinaryTreeDestory(root->right);
	free(root);
}

2.6怎样通过前序遍历构建二叉树

//通过 前序 遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)//这里一定要是int*pi,或者全局变量
{
	if (a[*pi] == '#' || a[*pi] == '\0')
	{
		(*pi)++;
		return NULL;
	}

	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)//判断开辟空间是否成功
	{
		perror("malloc fail");
		exit(-1);
	}
	node->val = a[*pi];
	(*pi)++;
	node->left = BinaryTreeCreate(a,pi);
	node->right = BinaryTreeCreate(a,pi);
	return node;
}

2.7判断是否是满二叉树

需要借助队列来实现
先将根节点入队,然后出队时,将根节点的左子树和右子树入队,然后重复上述操作。当出队遇到第一个NULL时判断队列中是否还有不是空的,如果没有就表明改二叉树是满二叉树

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QInint(&q);//初始化
	if (root)
		QPush(&q, root);
	while (!QEmpty(&q))
	{
		QDataType fornt = GetFront(&q);
		QPop(&q);
		//遇到第一个空就可以开始判断了,如果队列不为空,就是非完全二叉树
		if (fornt == NULL)
		{
			break;
		}
			QPush(&q, fornt->left);
			QPush(&q, fornt->right);
	}

	while (!QEmpty(&q))
	{
		QDataType fornt = GetFront(&q);
		QPop(&q);
		//进入下面的if中就不是完全二叉树
		if (fornt)
		{
			Qdestroy(&q);
			return false;
		}
	}

	Qdestroy(&q);//销毁队列
	return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值