二叉树链式结构

一、介绍

对于一些非满二叉树的情况,使用顺序存储会造成一定的空间浪费,因此可以使用双向链表的形式来表示二叉树。

因为二叉树最多会有两个子树,所以对每个节点定义为含两个指针结构体。

每个节点的左指针指向该节点的左子树,右节点指向右子树。

二、遍历二叉树

对于链式存储实现的二叉树,其不像顺序存储那样可以通过下标访问,直接将整个树遍历完。

并且链表都是通过指针来访问下一节点的,再结合二叉树的特点,遍历整个二叉树,有以下方法:

1. ⭐前序遍历

采用递归的思想,我们知道根节点,就知道它的指向左右子树的指针,因此再调用该函数传递它的子树,直到子树为空。

其中前序遍历是指:访问根节点的操作发生在遍历其左右子树之前。

代码:

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
		return NULL;
    
	printf("%d ", root->data);
	BinaryTreePrevOrder(root->left);//对左子树遍历
	BinaryTreePrevOrder(root->right);//对右子树遍历

}

图示:
在这里插入图片描述

对图中的二叉树进行前序遍历输出的结果是A B D E H C F G

对于前序遍历的结果是比较好理解的,当遍历到一个节点时先输出它的数据,然后对它的左子树进行遍历,只有当遍历到空时,递归的函数才开始返回,然后执行调用该递归函数的下一条语句,即开始遍历右子树。

2. 中序遍历

中序遍历是指:访问根结点的操作发生在遍历其左子树之后,右子树之前;

代码:

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
		return NULL;
	BinaryTreePrevOrder(root->left);//对左子树遍历
	printf("%d ", root->data);
	BinaryTreePrevOrder(root->right);//对右子树遍历
}

图示:
在这里插入图片描述

对图中的二叉树进行中序遍历输出的结果是D B E H A F C G

对于中序遍历的理解:先对左子树进行遍历,直到空指针然后返回到调用该递归函数的地方,执行下一条语句,输出D,然后遍历该节点的右子树。只有遇到空或者节点的左右子树都遍历结束(函数语句都执行完)才会返回到调用该函数的地方。

3. 后续遍历

后序遍历是指:访问根节点的操作发生在遍历其左右子树之后。

代码:

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
		return NULL;
	BinaryTreePrevOrder(root->left);//对左子树遍历
	BinaryTreePrevOrder(root->right);//对右子树遍历
	printf("%d ", root->data);

}

图示:
在这里插入图片描述

对图中的二叉树进行中序遍历输出的结果是D H E B F G C A

对于后续遍历的理解:只有当左右子树都为空,或者都遍历结束后再输出该节点是数据。并且是先左后右。

4. ⭐层序遍历

层序遍历就是将二叉树一层一层的遍历,此时递归的思想就不适合了,我们可以发现如果按层序的顺序,其实也是按根节点->左子树->右子树,并且都是以顺序排序。因此可以开辟数组,依次记录下当前节点的两个指针,以先存的先出的顺序(队列的特点),可以循环的变量整个二叉树。

图示:
在这里插入图片描述

代码:

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	assert(root);
    //创建队列
	Queue* myQ = (Queue*)malloc(sizeof(Queue));
	QueueInit(myQ);
    //记录根节点指针
	QueuePush(myQ, root);
	while (!QueueEmpty(myQ))//当队列不为空
	{
        //取出队列第一个指针
		BTNode* temp = QueueFront(myQ);
		QueuePop(myQ);//并且去除该指针
		//输出数据
		printf("%c ", temp->data);
        //记录该节点的左右指针
		if(temp->left != NULL)
			QueuePush(myQ, temp->left);
		if(temp->right != NULL)
			QueuePush(myQ, temp->right);
	}
	printf("\n");
	QueueDestroy(myQ);//释放队列
}

输出的结果:A B C D E F G H

三、⭐二叉树其他问题求解

1. 求节点个数

简单点,可以通过递归的思想遍历。二叉树的节点个数 = 根节点个数+左右子树节点个数

代码:

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	//		左子树节点个数				+ 右子树节点个数  			+ 根节点的个数
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

2. 求叶子节点个数

叶子节点:度为0(左右子树为空)的节点。

和问题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);
}

3. 求第 k k k层节点个数

默认的话,认为根节点为第1层。

那么根节点的左右子树,就是第 2 2 2层,再向下层数继续 + 1 +1 +1,直到 k k k层就可以开始计数。

类似问题2,加一些判断,思想在转换一些:将根节点认为是第 k k k层,每向下一层就 − 1 -1 1,一直到第 1 1 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);
}

4. 是否为完全二叉树

完全二叉树是完全按顺序的特别的二叉树。

因为是按顺序的,其中只有层序遍历最符合要求。非完全二叉树的情况,即在某层中,前面有空指针,但是后面还有非空指针;而完全二叉树,则是开始有空指针,到结束都只有空指针。

代码:

// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
	assert(root);
  	//创建队列
	Queue* myQ = (Queue*)malloc(sizeof(Queue));
	QueueInit(myQ);
     //记录根节点指针
	QueuePush(myQ, root);
	while (!QueueEmpty(myQ))//当队列不为空
	{
        //取出队列第一个指针
		BTNode* temp = QueueFront(myQ);
		QueuePop(myQ);//并且去除该指针
        //存入该结点左右指针
		if (temp != NULL)
		{
			QueuePush(myQ, temp->left);
			QueuePush(myQ, temp->right);
		}
		else//遇到空指针结束遍历
		{
			break;
		}
	}
    //遍历整个队列的内容
	while (!QueueEmpty(myQ))
	{
		BTNode* temp = QueueFront(myQ);
		QueuePop(myQ);
        //遇到非空指针,则不是完全二叉树
		if (temp != NULL)
		{
			QueueDestroy(myQ);
			return 0;
		}
	}
	QueueDestroy(myQ);
    //是完全二叉树
	return 1;
}

四、🌟创建链式结构的二叉树

二叉树的遍历
在这里插入图片描述

分析:该问题主要还是需要根据一个字符串数组,来构建链式二叉树。

解题:因为该字符串是该二叉树先序遍历的结果,因此我们就用先序遍历来创建

BTNode* BuyNode(char c)
{
    BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));
    newNode->data = c;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}
//通过修改数组的下标的指针pi,可以保证数组按顺序向后遍历(类似静态变量了)
BTNode* BinaryTreeCreate(char* a, int* i)
{
	if (a[(*i)++] == '#')
		return NULL;
	
	BTNode* newNode = BuyNode(a[(*i)++]);
	newNode->left = BinaryTreeCreate(a, i);
	newNode->right = BinaryTreeCreate(a, i);
	return newNode;
}
//剩余部分还请自己试试吧

🦀🦀观看~

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值