通过中序和先序/后序序列创建二叉树

本文介绍了如何根据二叉树的先序和中序遍历,或者后序和中序遍历序列来构建二叉树。通过分析遍历序列,确定根节点并递归构建左右子树,最终形成完整的二叉树结构。同时提到,仅凭先序和后序遍历序列无法唯一确定二叉树。

在二叉树的相关题目中,我们经常会碰到这样的问题,给出一颗二叉树的前序遍历和中序遍历,或者是给出它的后序遍历和中序遍历,让我们画出这个二叉树或者是用代码实现如何用上面两种情况来创建这个二叉树。

首先我们来看看给出先序遍历序列和中序遍历序列如何画出这颗二叉树:
在这里插入图片描述
首先,先序遍历序列中的第一个字母肯定是这颗二叉树的根节点,然后在中序遍历的序列中找到这个根节点,以这个根节点作为分割,在中序遍历序列中找到二叉树根节点的左右子树。
如下图所示:

在这里插入图片描述
接着我们将左子树的先序遍历序列和中序遍历序列单独拿出来研究,跟上一步一样,线序遍历序列中第一个字母为左子树的根节点,然后在中序遍历序列中找到根节点并以它作为分割找到此时的根节点的左右子树。如下图所示;

在这里插入图片描述
同样的再将B节点的右子树单独拿出来分析我们就可以很容易得到以B为根节点的二叉树如下:

在这里插入图片描述
然后再分析A节点的右子树,它的右子树只有G和H两个节点,根据先序遍历和中序遍历的规则可以容易推出G为根节点,H为G的右子树,G的左子树为空,所以得到最终的二叉树:

在这里插入图片描述
上面是由先序遍历序列和中序遍历序列推出二叉树的过程,由后序遍历序列和中序遍历序列同样的过程也可以画出一颗二叉树,但我们需要知道的是,如果只给出了先序遍历序列和后序遍历序列,我们无法画出一颗确定的二叉树,因为先序遍历和后序遍历的根节点是在最前面和最后面,因此我们无法推断出这个根节点的左右子树到底有哪些。所以说如果没有给出中序遍历序列,我们将无法得到一颗二叉树。

接下来我们用代码实现用先序遍历序列和后序遍历序列创建一颗二叉树。

//找到中序序列中的根节点
int FindIs(char* Is, int n, char val)
{
	int pos = -1;
	for (int i = 0; i < n; i++)
	{
		if (Is[i] == val)
		{
			pos = i;
			break;
		}
	}
	return pos;
}

BtNode* CreatePI(char* ps, char* Is, int n)
{
	BtNode* s = NULL;
	if (n > 0)
	{
		s = Buynode();
		s->data = ps[0];
		int pos = FindIs(Is, n, ps[0]);//找到中序序列中根节点的位置
		if (pos == -1)exit(EXIT_FAILURE);//没有找到就结束程序
		s->leftchild = CreatePI(ps + 1, Is, pos);
		s->rightchild = CreatePI(ps + 1 + pos, Is + 1 + pos, n - pos - 1);
	}
	return s;
}
BtNode* CreateTreePI(char* ps, char* Is, int n)
{
	BtNode* s = NULL;
	if (ps != NULL && Is != NULL && n > 0)
	{
		s = CreatePI(ps, Is, n);
	}
	return s;
}

我们给出需要进行测试的主函数代码如下:

int main()
{
	BinaryTree root = NULL;
	char pstr[] = "ABCDEFGH";//先序序列
	char Istr[] = "CBEDFAGH";//中序序列
	int psn = strlen(pstr);
	int Isn = strlen(Istr);
	if (psn == Isn)//中序序列和先序序列的长度必须相等
	{
		root = CreateTreePI(pstr,Istr,Isn);
	}
	PreOrder(root);
	cout << endl;
	InOrder(root);
	cout << endl;
	EndOrder(root);
	cout << endl;
	return 0;
}

通过运行结果我们可以看到这颗二叉树通过给出的先序序列和中序序列被创建出来了:

在这里插入图片描述
通过中序序列和后序序列来创建二叉树:

//找到中序序列中的根节点
int FindIs(char* Is, int n, char val)
{
	int pos = -1;
	for (int i = 0; i < n; i++)
	{
		if (Is[i] == val)
		{
			pos = i;
			break;
		}
	}
	return pos;
}

BtNode* CreateIL(char* Ls, char* Is, int n)
{
	BtNode* s = NULL;
	if (n > 0)
	{
		s = Buynode();
		s->data = Ls[n-1];
		int pos = FindIs(Is, n, Ls[n-1]);
		if (pos == -1)exit(EXIT_FAILURE);
		s->leftchild = CreateIL(Ls, Is, pos);
		s->rightchild = CreateIL(Ls + pos, Is + 1 + pos, n - pos - 1);
	}
	return s;
}
BtNode* CreateTreeIE(char* Ls, char* Is, int n)
{
	BtNode* s = NULL;
	if (Ls != NULL && Is != NULL && n > 0)
	{
		s = CreateIL(Ls, Is, n);
	}
	return s;
}
int main()
{
	BinaryTree root = NULL;
	char Istr[] = "CBEDFAGH";
	char Lstr[] = "CEFDBHGA";
	int Lsn = strlen(Lstr);
	int Isn = strlen(Istr);
	if (Lsn = Isn)
	{
		root = CreateTreeIE(Lstr,Istr,Isn);
	}
	EndOrder(root);
	cout << endl;
	InOrder(root);
	cout << endl;
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值