树——二叉树的四种遍历方式

二叉树的遍历

我又又又又又来啦。这次我将带大家深入理解二叉树的4种遍历方式。大家赶紧先想一想是哪4种方式吧!

好的,就让我来揭晓答案吧!

  1. 先序遍历
  2. 中序遍历
  3. 后序遍历
  4. 层序遍历

在开始遍历前,我们需要进行几个准备。

  1. 给出树结构的声明
  2. 给出四种遍历函数的声明
  3. 包含遍历所需要容器所在的文件

在这些准备工作都已经就绪后,就要开始我们的第一个遍历也就是先序遍历啦。作为第一个,当然也是最简单的,请大家要专注,跟着我一起深入理解噢!

先在头文件中给出四个函数的声明

void PreOrderTraversal(TreeNode *BT);
void InOrderTraversal(TreeNode *BT);
void PostOrderTraversal(TreeNode *BT);
void LevelOrderTraversal(TreeNode *BT);

1.先序遍历

先序遍历的顺序是根节点->左节点->右节点,其实啊,这个前中后遍历就是根据根节点遍历的次序来确定名字的,先序遍历就是把根节点先遍历,大家是不是突然明白了点什么呢!

这里由于树可以通过递归来定义,所以树的一些操作啊大多都是通过递归来实现的,就比如求某一条路径总和啊,路径总和最大值啊,最先公共祖先啊······(扯远了~)

好!既然讲到了递归,大家有没有想起来一种执行方式跟递归非常相似的一种数据结构呢?没错!就是那什么!

栈,也称堆栈(曾经去了解过为什么加个堆字,后面好像看到说念起来好听emmm)实际上函数的递归使用,跟栈的实现原理是一样的,在我们使用过递归后,希望童鞋们可以再试试通过栈来实现遍历,这将非常有助于你对遍历过程的了解,但可能一时半会理解不了,没有关系!大家都是这么过来的,希望大家多花些时间!

void PreOrderTraversal(TreeNode *BT) {
	if (BT) {
		printf("%d\n", BT->Data);
		PreOrderTraversal(BT->lChild);
		PreOrderTraversal(BT->rChild);
	}
}

哇,同学们是不是发现,怎么就几行就完成了啊,那么接下来让我们看看栈的实现,栈的实现过程就是对这个递归过程的详细解读。

stack<TreeNode*> mystack;
	while (BT || !mystack.empty()) {
		while (BT) {					/*一直向左并将沿途结点打印后入栈*/
			printf("%d\n", BT->Data);
			mystack.push(BT);
			BT = BT->lChild;
		}
		if (!mystack.empty()) {
			BT = mystack.top();
			mystack.pop();
			BT = BT->rChild;
		}
	}

这里是把函数里面的内容全部替换成了这一段噢,童鞋们可要注意咯~

童鞋们慢慢品味里面的内容吧~ 接下来就会给出其他几个方式的代码了噢,中序遍历和后序遍历博主不太想讲了噢,因为就跟先序遍历一样的原理,只是遍历顺序改变了噢~

2.中序遍历

void InOrderTraversal(TreeNode *BT) {
	if (BT) {
		TreeTraversal::InOrderTraversal(BT->lChild);
		printf("%d\n", BT->Data);
		TreeTraversal::InOrderTraversal(BT->rChild);
	}
}

同样也能使用栈噢~

	stack<TreeNode*> mystack;
	while (BT || !mystack.empty()) {
		while (BT) {
			mystack.push(BT);
			BT = BT->lChild;
		}
		if (!mystack.empty()) {
			BT = mystack.top();
			mystack.pop();
			printf("%d\n", BT->Data);
			BT = BT->rChild;
		}
	}

3.后序遍历

void PostOrderTraversal(TreeNode *BT) {
	if (BT) {
		TreeTraversal::PostOrderTraversal(BT->lChild);
		TreeTraversal::PostOrderTraversal(BT->rChild);
		printf("%d\n", BT->Data);
	}
}

诶~到了这里,栈的应用与上面两种的差别就会大了一点噢。

要实现访问顺序为左节点->右节点->根节点,可以通过栈按照根节点、右节点、左节点的顺序压栈。所以我们要做的就是将先序遍历的左右先后顺序交换,然后通过另一个栈实现访问方式的打印。但缺点是空间占用较大,下面给出代码

stack<TreeNode*> mystack1;
	stack<TreeNode*> mystack2;
	while (BT || !mystack1.empty()) {
		while (BT) {
			mystack1.push(BT);
			mystack2.push(BT);
			BT = BT->rChild;
		}
		if (!mystack1.empty()) {
			BT = mystack1.top();
			mystack1.pop();
			BT = BT->lChild;
		}
	}
	while (!mystack2.empty()) {
		BT = mystack2.top();
		mystack2.pop();
		printf("%d\n", BT->Data);
	}

4.层序遍历

其实啊,二叉树遍历的核心问题是二维结构的线性化。在通过结点访问了左节点后,右节点应该如何访问呢?前面三种我们非递归的方式是通过堆栈实现的,事实上我们也能通过队列来保存。

这里就要讲一下队列实现的基本思路了:遍历从根节点开始,先根节点入队,然后执行循环:结点出队,访问根节点,左节点入队,右节点入队,直到队列为空的时候停止。
这种遍历的结果是将二叉树从上到下,从左至右一层一层遍历,即层序遍历,下面给出代码啦~

void LevelOrderTraversal(TreeNode *BT) {
	if (BT == nullptr) return;
	queue<TreeNode*> team;
	team.push(BT);
	while (!team.empty()) {
		BT = team.front();
		team.pop();
		printf("%d\n", BT->Data);
		if (BT->lChild) team.push(BT->lChild);
		if (BT->rChild) team.push(BT->rChild);
	}
}

好啦,四种二叉树的遍历就已经讲完啦~同学要是有什么问题可以给我留言或者评论噢,记得光看不行,还得练!!!可以去PAT上找一找类似题目做做噢,随时期待大家的提问噢!

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值