如何理解二叉树中的前序遍历、中序遍历和后序遍历(递归!)

从宏观来讲,二叉树的遍历归结为两类:深度优先遍历和广度优先遍历。深度优先遍历包括前序遍历、中序遍历和后序遍历,广度优先遍历主要指层序遍历,这篇文章主要介绍深度优先遍历。

在介绍如何理解二叉树递归之前,我们回顾一下三种方式遍历二叉树的顺序。

前序:根左右

中序:左根右

后序:左右根

1.根据上面的遍历顺序,我们给出一个简单的例子。已知:前序遍历序列为{1,2,4,7,3,5,6,8},中序遍历序列为{4,7,2,1,5,3,8,6},请画出这颗二叉树。

毫无疑问,我们的二叉树应该长下面这样。接下来我们会以这个例子为例来说明二叉树中的递归。

2.二叉树的结构体定义: 

struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
};

下面我们开始介绍二叉树中的递归。 

一、前序遍历

我们先看前序遍历输出二叉树的代码。简单解释一下:r为要遍历的二叉树的根节点指针,用p指针来指向每次要输出的节点,二叉树的前序遍历为:根左右,先打印根节点,然后前序遍历左子树,再前序遍历右子树。

void pre_order(TreeNode *r) {
	TreeNode *p = r;
	if (p != NULL) {
		cout << p->val << " ";
		pre_order(p->left);
		pre_order(p->right);
	}
}

还是以上面的那颗二叉树为例来说明,前序遍历的执行顺序如下图所示。我们以每次递归为一层,用蓝色数字表示输出,实线箭头表示实际的执行顺序,虚线箭头表示等待执行。这里只画出根节点的左子树的执行顺序,右子树同理即可。我们看到当左子树为空时,便遍历右子树,当右子树也为空时,返回到上上层的右子树继续遍历,此处返回时2的右子树已经为空,所以开始遍历根节点的右子树,然后右子树又可以按这样的方式继续遍历...

 

二、中序遍历 

中序遍历的代码如以下所示,当根节点非空时,先中序遍历左子树,再打印根节点,最后中序遍历右子树。

void vin_order(TreeNode* r) {
	TreeNode* p = r;
	if (p != NULL) {
		vin_order(p->left);
		cout << p->val << " ";
		vin_order(p->right);
	}
}

 同样我们画出中序遍历根节点的左子树的执行顺序图。当遍历到左子树为空时,便输出节点值,接着遍历右子树;当右子树没有叶子节点时便返回上一层,并输出上一层节点值。

 三、后序遍历

在解释后序遍历前我们不妨先算出上面的二叉树的后序遍历结果!后序遍历:{7,4,2,5,8,6,3,1} 

后序遍历执行顺序为:左右根。后序遍历左子树,后序遍历右子树,输出根节点。只需记住,根节点一定在最后输出。

void post_order(TreeNode* r) {
	TreeNode* p = r;
	if (p != NULL) {
		post_order(p->left);
		post_order(p->right);
		cout << p->val << " ";
	}
}

我们将后序顺序完整画出,执行时候一定是按照左右根的顺序,当左子树遍历完毕后一定是返回的上层的右子树继续遍历,在输出上层的节点值。图中黄色虚线表示上层的右子树为空,直接输出节点值。


说明:本文以牛客网上的剑指Offer的第四题重建二叉树进行知识回顾。下面给出该题的实现以及遍历的代码。

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

using namespace std;
#include <vector>;
#include <iostream>;

struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {} //初始化TreeNode(int x),把x赋值给val,left和right都置为空
};

/*
思想:先找到根节点,然后依据根节点,又划分左子树前序和左子树中序;右子树前序和右子树中序,然后递归调用重建二叉树的方法
*/
class Solution {
public:
	TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin) {
		if (pre.size() == 0 || vin.size() == 0)
			return NULL;
		TreeNode* p = new TreeNode(pre[0]);
		int i;
		for (i = 0; i < vin.size(); i++)
			if (pre[0] == vin[i])
				break;
		vector<int> left_pre, left_vin, right_pre, right_vin;
		for (int j = 0; j < i; j++)
		{
			left_pre.push_back(pre[j + 1]);
			left_vin.push_back(vin[j]);
		}

		for (int j = i + 1; j < pre.size(); j++)
		{
			right_pre.push_back(pre[j]);
			right_vin.push_back(vin[j]);
		}
		p->left = reConstructBinaryTree(left_pre, left_vin);
		p->right = reConstructBinaryTree(right_pre, right_vin);
		return p;

	}
};

void pre_order(TreeNode *r) {
	TreeNode *p = r;
	if (p != NULL) {
		cout << p->val << " ";
		pre_order(p->left);
		pre_order(p->right);
	}
}

void vin_order(TreeNode *r) {
	TreeNode* p = r;
	if (p != NULL) {
		vin_order(p->left);
		cout << p->val << " ";
		vin_order(p->right);
	}
}

void post_order(TreeNode *r) {
	TreeNode* p = r;
	if (p != NULL) {
		post_order(p->left);
		post_order(p->right);
		cout << p->val << " ";
	}
}

int main() {
	vector<int> pre = { 1,2,4,7,3,5,6,8 };
	vector<int> vin = { 4,7,2,1,5,3,8,6 };
	Solution s;
	TreeNode *p = s.reConstructBinaryTree(pre, vin); //重建二叉树
	pre_order(p); //前序遍历输出
	cout << endl;
	vin_order(p); //中序遍历输出
	cout << endl;
	post_order(p); //后序遍历输出
	return 0;
}

 

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
叉树和后的原理都是归,是因为二叉树的结构本身就是归的。每个节点都有左右子树,而左右子树本身也是一个二叉树。因此,我们可以通过归的方式来遍整个二叉树。 给出二叉树,可以通过以下步骤求出后: 1. 根据确定根节点,假设根节点为root。 2. 在找到根节点的位置,假设根节点在的位置为i。 3. 根据的性质,i左边的节点都是root的左子树,i右边的节点都是root的右子树。 4. 归求解root的左子树的后,假设结果为left_postorder。 5. 归求解root的右子树的后,假设结果为right_postorder。 6. 将left_postorder和right_postorder合并,再加上root节点,即为整个二叉树的后。 下面是一个Python实现的例子: ```python def get_postorder(preorder, inorder): if not preorder: return [] root = preorder[0] i = inorder.index(root) left_inorder = inorder[:i] right_inorder = inorder[i+1:] left_preorder = preorder[1:i+1] right_preorder = preorder[i+1:] left_postorder = get_postorder(left_preorder, left_inorder) right_postorder = get_postorder(right_preorder, right_inorder) return left_postorder + right_postorder + [root] ``` 其,preorder表示的结果,inorder表示的结果。函数返回后的结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值