二叉树的遍历——深度优先遍历与广度优先遍历

一、二叉树的遍历

  二叉树遍历是按照一定的次序访问二叉树中的所有结点,并且每个结点仅被访问一次。
  一颗二叉树是由三个部分构成(根结点、左子树和右子树)构成,因此在遍历二叉树时也可以从任何部分开始遍历,所以有3!种遍历方法。但是我们约定在遍历二叉树时,先遍历左子树再遍历右子树,则对于非空二叉树,可以得到三种递归遍历方法,而这三种方法我们统称为深度优先遍历法。而广度遍历法则是以另一个角度来遍历二叉树,通过根结点来引出左右子树,最终实现遍历。

二、深度优先遍历法(递归)

2.1 先序(先根)遍历法

  先根遍历法顾名思义就是先遍历根节点,再按照约定往下去遍历左子树和右子树。其遍历过程如下:

  1. 先访问根节点;
  2. 在遍历左子树;
  3. 最后遍历右子树。
      在遍历过程中依旧是采用分治算法的思想,将大问题分解为小问题,再使用递归遍历整棵树。如下图,从根节点A开始,依次到左子树B,再通过递归以B为根继续向下遍历,最后遍历右子树C。
A
B
NULL
C
D
NULL
E
NULL
NULL
F
NULL
NULL
G
NULL
NULL

最终遍历的整一个流程为:A->B->D->NULL->G->NULL->NULL->NULL->C->E->NULL->NULL->F->NULL->NULL

该算法程序如下(C语言):

void PreOrder(BTNode* root)
{
	if(root !=NULL)
	{
		printf("%c ",root->data);//先访问根节点
		PreOrder(root->left);//再遍历左子树
		PreOrder(root->right);//最后遍历右子树
	}
}

2.2 中序(中根)遍历法

  中根遍历思路与先根遍历的思路大同小异,只不过根要放到第二个遍历。按照约定先遍历左子树,再遍历根,最后遍历右子树。
  如下图,依然采用分治的思想将这棵树分解为若干二叉树,首先从A结点开始发现A并不是做左子树,则继续往下走,走到B时发现还可以继续分,直到走到D的左子树时发现不可再分,然后开始往回走。依次这样递归下去,就可以遍历整棵树。

A
B
NULL
C
D
NULL
E
NULL
NULL
F
NULL
NULL
G
NULL
NULL

最终遍历的整个流程为:NULL->D->NULL->G->NULL->B->NULL->A->NULL->E->NULL->C->NULL->F->NULL

该算法程序如下(C语言)

void InOrder(BTNode* root)
{
	if(root != NULL)
	{
		InOrder(root->left);//遍历左子树
		printf("%c ",root->data);//访问根结点
		InOrder(root->right);//遍历右子树
	}
}

2.3后序(后根)遍历法

  后根遍历就是将根放到最后去访问,先遍历左子树和右子树。这种方法与上述两种方法相同,均是采用分治算法的思想来进行遍历。
  如下图所示,从根结点A进入程序后,要一直向下走直到左/右子树不可再分,才会返回访问根结点。

A
B
NULL
C
D
NULL
E
NULL
NULL
F
NULL
NULL
G
NULL
NULL

最终遍历的整个流程为:NULL->NULL->NULL->G->D->NULL->B->NULL->NULL->E->NULL->NULL->F->C->A

该算法程序如下(C语言)

void PostOrder(BTNode* root)
{
	if(root != NULL)
	{
		PostOrder(root->left);//遍历左子树
		PostOrder(root->right);//遍历右子树
		printf("%c ",root->data);//访问根结点
	}
}

三、广度优先遍历法(非递归)

  广度优先遍历法也称层次遍历法,这种遍历与深度优先遍历法存在一定的区别。首先,广度优先遍历法是一层一层的从左到右的访问所有结点,直到一层访问完之后,再向下访问;其次,广度优先遍历法没有用到递归这种思想,且在使用广度优先遍历法时需要使用队列这一数据结构。但二者均使用了分治算法的思想。
  其核心思想就是采用了队列的先进先出这一优势,通过根节点出队,带左右子树入队,来实现遍历整棵树。如下图,首先将根结点A传入队列中,然后进行根结点A出队,左右子树B、C分别入队;紧接着继续以分治的思想,让左子树B出队,B的左右子树继续入队;C也如此。重复该操作,直到该队列为空则完成遍历

A
B
NULL
C
D
NULL
E
NULL
NULL
F
NULL
NULL
G
NULL
NULL

最终结果为:
A B C D E F G

核心算法代码如下

void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);//初始化一个队列
	if(root != NULL)//判断是否为空树
	{
		QueuePush(&q,root);//将根节点入队
	}
	while(QueueEmpty != NULL)//判断队是否为空
	{
		BTNode* front = QueueFront(&q);//将队头指针指向根节点
		QueuePop(&q);	//将根结点出队
		printf("%c ",front->data);

		if(front->left)//若左子树不为空则入队
		{
			QueuePush(&q,front->left);
		}
		if(front->right)//判断右子树
		{
			QueuePush(&q,front->right);
		}
	}
	printf("\n");

	QueueDestory(&q);//销毁队列
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值