二叉树的遍历(递归思想)

目录

一、前、中,后序遍历

1.1基本思想

.2代码实现

1.3递归调用图

二、层序遍历

2.1基本思想

2.2代码实现

三、判断一棵树是否为完全二叉树

3.1完全二叉树的概念

3.2基本思路

3.3代码实现

四、求节点个数

4.1基本思路

4.2代码实现

五、求树的高度

5.1基本思想

5.2代码实现

六、求第k层的节点个数

6.1基本思想

6.2代码实现

七、寻找值为x的节点

7.1基本思想

7.2代码实现


一、前、中,后序遍历

1.1基本思想

前序遍历:先访问根节点,再依次访问左子树和右子树

中序遍历:先访问左子树,再依次访问根节点和右子树

后序遍历:先访问右子树,再依次访问左子树和根节点

以前序遍历为例:

前序遍历结果:1 2 3 4 5 6

中序遍历结果:3 2 1 5 4 6

后序遍历结果:3 2 5 6 4 1

1.2代码实现

前序遍历、中序遍历、后序遍历

void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);

}

void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);

}

void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);

}

1.3递归调用图

以前序遍历为例:

二、层序遍历

2.1基本思想

从上到下、从左到右逐层访问树的节点

二叉树的层序遍历采用队列的方式实现,根节点入队,出队时带入它的子节点入队(左孩子先入队,右孩子后入队),依次出队列。每次出队一个节点,就要带入它的子节点,直到所有的节点都出队完成,队列为空,循环结束。

2.2代码实现

void LevelOrder(BTNode* root)
{
	Queue Q;
	QInit(&Q);

	//第一个结点入队
	if (root)
	{
		QPush(&Q, root);
	}

	//遍历结点
	while (!QEmpty(&Q))
	{
		//队首元素
		BTNode* front = QFront(&Q);

		//队首元素出队
		QPop(&Q);

		//根结点的值
		printf("%d ", front->data);

		//左右孩子入队
		if (front->left)
			QPush(&Q, front->left);
		if (front->right)
			QPush(&Q, front->right);

	}

	QDestroy(&Q);

}

三、判断一棵树是否为完全二叉树

3.1完全二叉树的概念

前K-1层是满二叉树,第K层从左到右没有空节点,满二叉树是完全二叉树的一种特殊情况

3.2基本思路

结合层序遍历的思想,如果遇到空节点后还存在非空节点,那么就不是一棵完全二叉树。

首先,根节点入队列,出队时带左右节点入队列,依次入队,直到遇到NULL跳出循环。接着判断NULL节点之后是否有非空节点,依次将队头元素出队,若遇到非空节点就返回false,若队列出空了说明NULL节点之后全是空节点,返回true。

3.3代码实现

int isFullBinaryTree(BTNode* root)
{
	Queue Q;
	QInit(&Q);
	//第一个结点入队
	if (root)
	{
		QPush(&Q, root);
	}
	else
	{
		return false;
	}

	//遍历结点
	while (!QEmpty(&Q))
	{
		//队首元素
		BTNode* front = QFront(&Q);

		//队首元素出队
		QPop(&Q);
		if (front == NULL)
		{
			break;
		}

		//左右孩子入队
		else
		{
			QPush(&Q, front->left);
			QPush(&Q, front->right);
		}

	}
	//判断
	while (!QEmpty(&Q))
	{
		//队首元素
		BTNode* front = QFront(&Q);

		//队首元素出队
		QPop(&Q);

		//说明空节点是不连续的
		if (front != NULL)
		{
			QDestroy(&Q);
			return false;
		}

	}

	return true;
	QDestroy(&Q);

}

四、求节点个数

4.1基本思路

遍历节点,遇到一个节点就统计,再依次遍历它的左右节点。

4.2代码实现

值得注意的是,函数不带返回值的时候,由于每一次函数调用结束后栈帧会被销毁,如果size是定义在函数内部的话,它就不能把结果带回上一层函数调用了,所以要在函数外部创建一个变量size,通过指针对它进行改变。

void BinaryTressSize1(BTNode* root, int* psize)
{
	if (root == NULL)
	{
		return;
	}
	(*psize)++;
	BinaryTressSize1(root->left, psize);
	BinaryTressSize1(root->right, psize);
}

不带返回值的函数用起来比较麻烦,我们可以改进用带返回值的函数来简化代码。

采用分治的思想,每一棵树的节点个数都等于左右子树相加再加1

int BinaryTressSize2(BTNode* root)
{
	return root == NULL ? 0 : BinaryTressSize2(root->left) + BinaryTressSize2(root->right) + 1;
}

五、求树的高度

5.1基本思想

树的高度为左右子树最大的高度+根节点(1) 

同样采用分治的思想,递归调用计算每一个节点左右子树的高度,再返回给上一层的函数调用

5.2代码实现

int BinaryTreeHeight(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftHeight = BinaryTreeHeight(root->left);
	int rightHeight= BinaryTreeHeight(root->right);
	if (leftHeight > rightHeight)
	{
		return leftHeight + 1;
	}
	else
	{
		return rightHeight + 1;
	}
}

六、求第k层的节点个数

6.1基本思想

计算二叉树第k层的节点个数,由于我们无法直接找到第k层的位置,所以要采用相对位置的思想,即根节点所在的位置为第k层,递归访问左右子树,每访问一次k--,直到k=1,就找到了我们实际要的第k层,如果此时遇到的节点不为NULL就返回1,遇到NULL就返回0

6.2代码实现

int BinaryTreeKLevel(BTNode* root, int k)
{
	if (root==NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}

	int leftk = BinaryTreeKLevel(root->left, k - 1);
	int rightk = BinaryTreeKLevel(root->right, k - 1);
	return leftk+rightk;
}

七、寻找值为x的节点

7.1基本思想

采用遍历的思想,遍历树的每一个节点,如果遍历过程中找到目标节点就返回节点指针,如果遍历结束后仍然没有找到目标节点就返回NULL。

假设树不存在目标节点,当且仅当左右子树都遍历结束了才能判断出该结果,也就是说NULL只能在左右子树都遍历完后才返回。

7.2代码实现

BTNode* BinaryTreeFind(BTNode* root, BTDatatype x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	BTNode* lret = BinaryTreeFind(root->left, x);
	if (lret)
		return lret;
	BTNode* rret = BinaryTreeFind(root->right, x);
	if (rret)
		return rret;

	return NULL;
}

  • 15
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值