0
点赞
收藏
分享

微信扫一扫

前中后序遍历的递归与非递归算法,层序遍历

转角一扇门 2022-02-25 阅读 42

文章目录

前言:

思维导图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vOghesek-1645797380622)(%E9%81%8D%E5%8E%86.assets/202202252155405.png)]

建议

递归的3要素

二叉树的遍历

前序遍历

递归

思路

完整代码

//前序遍历是根在左右孩子前,先访问二叉树根结点。
void PreOrder(BTNode* root)
{
	if(root==NULL)
	{
		printf("NULL ");
		return ;
	}
	printf("%c ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

非递归

思路

代码

void PreOrderNoR(BTNode* root)// 二叉树前序遍历---非递归法
{
	assert(root);
	stack st;
	StackInit(&st);
	//我们需要根结点来进入右子树,因此要存根结点
	//同时一旦左子树访问完后,再进入右子树时需要根结点,后面就不需要了。因此pop
	SDateType p = root;
	while (1)
	{
		if (p != NULL)
		{
			printf("%c->", p->data);
			StackPush(&st, p);
			p = p->left;
		}
		else
		{
			printf("NULL->");
			break;
		}
	}

	while (!StackEmpty(&st)||p)//空树或者栈空结束
	{
		/
		//p为空说明,根和左子树遍历完毕。
		
		if (!StackEmpty(&st))
		{
			p = StackTop(&st);
			StackPop(&st);
			p = p->right;
			while (1)
			{
				if (p != NULL)
				{
					printf("%c->", p->data);
					StackPush(&st, p);
					p = p->left;
				}
				else
				{
					printf("NULL->");
					break;
				}
			}
		}
	}
	printf("\n");

	StackDestroy(&st);

}

中序遍历

递归

思路

代码

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

非递归

思路

代码

void InOrderNoR(BTNode* root)// 二叉树中序遍历---递归法
{
	assert(root);
	stack st;
	StackInit(&st);
	//我们需要根结点来进入右子树,因此要存根
	SDateType p = root;
	//遍历到左子树最低端.
	while (1)
	{
		if (p != NULL)
		{
			StackPush(&st, p);
			p = p->left;
		}
		else
		{
			printf("NULL->");
			break;
		}
	}
	while (!StackEmpty(&st) || p)//空树或者栈空结束
	{
		 
		if (!StackEmpty(&st))
		{
			SDateType  tmp= StackTop(&st);
			printf("%c->", tmp->data);
			StackPop(&st);
			p = tmp->right;
			//根结点已经遍历玩比,后续的遍历就不需要它了。
			//无论右子树是否为空,即使回来也不需要根结点。
			//遍历到左子树最低端.
			while (1)
			{
				if (p != NULL)
				{
					StackPush(&st, p);
					p = p->left;
				}
				else
				{
					printf("NULL->");
					break;
				}
			}
		}
	}
	printf("\n"); 
	StackDestroy(&st);
}

后序遍历

递归

思路

代码

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

非递归

思路

代码

void PostOrderNoR(BTNode* root)// 二叉树后序遍历---非递归法
{
	//思路:1.只有当左右子树访问完后,才能访问根结点。
	//      因此要有一个pVisist指针来记录已访问的左或右子树。当pVisit=p->right||p->right==NULL时,访问根结点。
	//      2.我们访问存在的右子树时,仍把它看作一棵二叉树,因此仍需要压栈与出栈,
	//      3.这里我打印NULL来帮助更好理解,
	assert(root);
	assert(root);
	stack st;
	StackInit(&st);
	SDateType p = root;
	SDateType pVisit = NULL;//标记左右子树的
	//简化版--只是将Top赋值给p了,但是要注意当右子树不为空,一定要直接进行左子树入栈。因为p的值并不是空。
	while (1)//先将左子树压栈,当左子树为空后,开始访问右子树。
	{
		if (p == NULL)
		{
			printf("NULL->");
			break;
		}
		else
		{
			StackPush(&st, p);
			p = p->left;
		}
	}
	while (!StackEmpty(&st) || p)//空树或者栈空结束
	{

		if (!StackEmpty(&st))
		{
			 p = StackTop(&st);
			//只有当右子树为空或者右子树已访问才访问根结点,才能删除根结点.
			if (p->right == NULL || p->right == pVisit)
			{
				if (p->right == NULL)
				{
					printf("NULL->");

				}
				StackPop(&st);
				printf("%c->", p->data);
				pVisit = p;
				//这一部代表该子树已访问,但是不确实是左子树还是右子树,因此需要 p->right == pVisit
			}
			else
			{
				p = p->right;//下次循环将是右子树的遍历。
				while (1)
				{
					if (p == NULL)
					{
						printf("NULL->");
						break;
					}
					else
					{
						StackPush(&st, p);
						p = p->left;
					}
				}
			}
		}
	}
	printf("\n");


	StackDestroy(&st);
}

层序遍历

代码

void LevelOrder(BTNode* root)// 层序遍历
{
	if (root == NULL)
	{
		return;
	
	}
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* tmp = QueueTop(&q);
		printf("%c ", tmp->data);
		QueuePop(&q);
		if (tmp->left != NULL)
		{
			QueuePush(&q, tmp->left);
		
		}
		if (tmp->right != NULL)
		{
			QueuePush(&q, tmp->right);
		}

	}
	QueueDestroy(&q);
}
举报

相关推荐

0 条评论