【二叉树构建与遍历3】先序遍历+后序遍历构建一个满二叉树并输出中序遍历 C++实现

注意:根据先序遍历与后序遍历 只有在满二叉树 的情况下才能确定一个唯一的树。这里介绍的是根据先序遍历+后序遍历构建一个满二叉树并输出中序遍历顺序。

思路:

先来一个例子:

先序遍历序列为:FDXEABG

后序遍历序列为:XEDBGAF

要根据先序序列和后序序列确定这个满二叉树,通用的步骤为:

1.根据先序序列的第一位或后序序列的最后一位确定这棵树的根root,但是不能用于确定它的左子树与右子树;

2.根据后序序列的倒数第二位确定右子树的根,这里命名为rRoot,这是用于定位的,用于确定根root的左子树与右子树;

3.在先序序列中找到右子树的根rRoot所在的位置,右子树的根rRoot的左边(除首位)就是该树的左子树的节点,右子树的根rRoot以及右边就是根root的右子树的节点;

4.根据左子树节点和右子树节点在后序序列中分别找到对应的子串;

5.对4中找到的两个子串分别重复1 2 3 4步,左子树节点用于构建左子树,右子树节点用于构建右子树,直到所有的节点都用于构建这棵树。

示例:

根据以上的案例走一遍:

1.由先序遍历序列为:FDXEABG可知,树root的根节点为F;

2.在后序遍历序列XEDBGAF中找到右子树的跟,这里命名为rRoot,也就是倒数第二个节点A

3.在先序遍历序列FDXEABG找到根root的右子树的跟A的索引为4,左边DXE(除首位)就是该树的左子树的节点,根A以及右边的ABG就是根root的右子树的节点;

4.根据树的左子树节点DXE和右子树节点ABG在后序序列中分别找到对应的子串,分别为:XED和BGA;

4.对XED和BGA(加上定位用的根节点A)分别重复步骤1 2 3,XED用于构建左子树,BGA用于构建右子树,直到所有的节点都用于构建树。

每执行完第一轮步骤1 2 3,所用的根节点已经用于构建树了,后续就不用再考虑了。例如,执行完第一轮步骤1 2 3,根节点F已经用过了,后续就不用再考虑了。

分析:

相信思路都很明确,步骤大概也明白了,接下来代码实现中一个非常注重细节的地方就是递归构建左子树和右子树的部分,再详细说就是在递归调用构建树的函数中,我们要传入的两个参数应该怎么确定。

本次主要介绍利用先序遍历序列和后序遍历序列构建一个二叉树并输出中序遍历的方法,我们在递归调用构建树的函数中,我们要传入的两个参数当然就是子树的先序遍历序列和后序遍历序列。创建左子树时就传入左子树的先序遍历序列和后序遍历序列,创建右子树时就传入右子树的先序遍历序列和后序遍历序列。

以下根据以上案例详细分析:对于:

cpp 复制代码
索 引:0123456

先序遍历序列为:FDXEABG

中序遍历序列为:XEDBGAF

将以上两个遍历序列分别命名为字符串s1,s2,即s1 = "FDXEABG", s2 = "XEDBGAF"。

根据s1可知树的根root为F,根据s2可知树右子树的根rRoot为A,在s1中寻找到A的索引(定义为pos)为4。

根据s1可得左子树包括的字符有:DXE(由s1.substr(1, pos-1)获得),右子树包括的字符有:ABG(由s2.substr(pos)获得),

在s2中对应的字符串分别为:XED(由s2.substr(0, pos-1)获得)和BGA(由s2.substr(pos-1, str1.size() - pos)获得)。

根据以上获得的四个参数,可以递归创建左子树和右子树。

源代码:

cpp 复制代码
//根据先序遍历和后序遍历确定一个二叉树,但必须是满二叉树
// 二叉树节点结构定义
struct TreeNode {
	char data;
	TreeNode* leftChild;
	TreeNode* rightChild;
	TreeNode(char c) : data(c), leftChild(NULL), rightChild(NULL) {}
};

// 根据先序遍历和后序遍历构建满二叉树
TreeNode* Build(string str1, string str2) {
	if (str1.size() == 0) {
		return NULL;
	}
	// 取先序遍历的第一个字符作为根节点
	//根节点可以根据先序遍历的第一个字符和后序遍历的最后一个字符直接获得
	TreeNode* root = new TreeNode(str1[0]);
	//当先序遍历中只剩下一个节点时,已经在前面的创建子树的作为根节点使用过了,就不需要再做处理了
	if (str1.size() > 1) {
		// 在后序遍历中找到左子树根节点的位置
		char c = str2[str2.size() - 2];
		// 在先序遍历中找到根节点的位置
		int pos = str1.find(c);
		// 递归构建左子树
		root->leftChild = Build(str1.substr(1, pos - 1), str2.substr(0, pos - 1));
		// 递归构建右子树
		root->rightChild = Build(str1.substr(pos), str2.substr(pos - 1, str1.size() - pos));
	}

	return root;
}

//中序遍历
void InOrder(TreeNode* root) {
	if (root == NULL) {
		return;
	}
	// 先遍历左子树
	InOrder(root->leftChild);
	//输出当前节点的值
	cout << root->data;
	// 再遍历右子树
	InOrder(root->rightChild);

	return;
}

int main()
{
	string s1, s2;
	while (getline(cin, s1)) {
		getline(cin, s2);
		// 根据先序遍历和后序遍历递归构建满二叉树
		TreeNode* root = Build(s1, s2);
		// 中序遍历该满二叉树
		cout << "中序遍历结果为:";
		InOrder(root);
		cout << endl;
	}

	return 0;
}

示例运行结果:

相关推荐
Gyoku Mint19 分钟前
深度学习×第4卷:Pytorch实战——她第一次用张量去拟合你的轨迹
人工智能·pytorch·python·深度学习·神经网络·算法·聚类
葫三生1 小时前
如何评价《论三生原理》在科技界的地位?
人工智能·算法·机器学习·数学建模·量子计算
pipip.1 小时前
UDP————套接字socket
linux·网络·c++·网络协议·udp
拓端研究室3 小时前
视频讲解:门槛效应模型Threshold Effect分析数字金融指数与消费结构数据
前端·算法
随缘而动,随遇而安5 小时前
第八十八篇 大数据中的递归算法:从俄罗斯套娃到分布式计算的奇妙之旅
大数据·数据结构·算法
孞㐑¥6 小时前
Linux之Socket 编程 UDP
linux·服务器·c++·经验分享·笔记·网络协议·udp
IT古董6 小时前
【第二章:机器学习与神经网络概述】03.类算法理论与实践-(3)决策树分类器
神经网络·算法·机器学习
水木兰亭9 小时前
数据结构之——树及树的存储
数据结构·c++·学习·算法
Jess0710 小时前
插入排序的简单介绍
数据结构·算法·排序算法
老一岁10 小时前
选择排序算法详解
数据结构·算法·排序算法