(注:父节点P 左子树L 右子树R)
结论:只有中序遍历+前序遍历 或者 中序遍历+后序遍历能得出树的构造,而前序遍历+后序遍历不能构造出树
原因
以下是任何一棵二叉树的三种遍历结果
先序遍历 P L R
中序遍历 L P R
后序遍历 L R P
构造出一棵树的重点在于分清左右子树,而先序和后序遍历中左右子树的序列是连接在一起的,不能被划分开,只要有中序遍历能将左右子树分开
具体的构造方法
先序遍历+中序遍历
先序遍历 P L R
中序遍历 L P R
先序遍历的第一个节点就是根节点,然后通过根节点可以将中序遍历的结果划分为左右子树,而后可以递归创建左孩子和右孩子。
后序遍历+中序遍历
后序遍历 L R P
中序遍历 L P R
后序遍历的最后一个节点就是根节点,然后通过根节点可以将中序遍历的结果划分为左右子树,而后可以递归创建左孩子和右孩子。
测试实例
(0代表NULL)
第一棵树
先序遍历 124783569
中序遍历 748215369
后序遍历 784259631
测试结果一:
测试结果二:
实现代码:
#include<stdio.h>
#include<stdlib.h>
const int MAX_LENGTH = 100;
struct Node
{
char data;
Node* Leftchild;
Node* Rightchild;
};
int findParent(char parent,char midTraversal[])
{
int i = 0;
for (i = 0;; i++)
{
if (parent == midTraversal[i])
break;
}
return i;
}
Node* preorder_midorder(char preTraversal[],char midTraversal[],int currentLength)
{
/*示例
根节点P 左子树L 右子树R
先序遍历 P L R
中序遍历 L P R
*/
int parentpos=findParent(preTraversal[0],midTraversal);//根节点在中序遍历中位置
int leftLength=0, rightLength=0;
Node* currentRoot = (Node*)malloc(sizeof(Node));
currentRoot->data = preTraversal[0];//这是当前的该子树的根节点
currentRoot->Leftchild = NULL;
currentRoot->Rightchild = NULL;
if (currentLength != 1)//说明这不是叶子节点,至少有一棵子树
{
//递归创建左子树
if (parentpos == 0)//中序遍历的结果中父节点在首位,说明此时只有右子树,没有左子树
currentRoot->Leftchild = NULL;
else
{
leftLength=parentpos; //左子树遍历序列的长度可以有中序遍历中根节点的位置确定
char leftMid[MAX_LENGTH]; //左子树的中序遍历结果
char leftPre[MAX_LENGTH]; //左子树遍先序遍历结果
for (int i = 0; i < leftLength; i++)
{
leftPre[i] = preTraversal[i+1];
leftMid[i] = midTraversal[i];
}
currentRoot->Leftchild = preorder_midorder(leftPre,leftMid,leftLength);
}
//递归创建右子树
if (parentpos == currentLength - 1)//中序遍历的结果中父节点在末位,说明此时只有左子树,没有右子树
currentRoot->Rightchild = NULL;
else
{
rightLength = currentLength - (parentpos+1);//右子树遍历序列的长度可以有中序遍历中根节点的位置确定
char rightMid[MAX_LENGTH]; //右子树中序遍历结果
char rightPre[MAX_LENGTH]; //右子树先序遍历结果
for (int i = 0; i < rightLength; i++)
{
rightPre[i] = preTraversal[i+1+leftLength];
rightMid[i] = midTraversal[i + parentpos+1];
}
currentRoot->Rightchild = preorder_midorder(rightPre, rightMid, rightLength);
}
}
return currentRoot;//结束递归,返回当前的根节点
}
Node* postorder_midorder(char postTraversal[], char midTraversal[], int currentLength)
{
/*示例
根节点P 左子树L 右子树R
中序遍历 L P R
后序遍历 L R P
*/
int parentpos = findParent(postTraversal[currentLength-1], midTraversal);//根节点在中序遍历中位置
int leftLength = 0, rightLength = 0;
Node* currentRoot = (Node*)malloc(sizeof(Node));
currentRoot->data = postTraversal[currentLength - 1];
currentRoot->Leftchild = NULL;
currentRoot->Rightchild = NULL;
if (currentLength != 1)//说明这不是叶子节点,至少有一棵子树
{
//递归创建左子树
if (parentpos == 0)//中序遍历的结果中父节点在首位,说明此时只有右子树,没有左子树
currentRoot->Leftchild = NULL;
else
{
leftLength = parentpos; //左子树遍历序列的长度可以有中序遍历中根节点的位置确定
char leftMid[MAX_LENGTH]; //左子树的中序遍历结果
char leftPost[MAX_LENGTH]; //左子树遍后序遍历结果
for (int i = 0; i < leftLength; i++)
{
leftPost[i] = postTraversal[i];//复制左子树后序遍历子序列
leftMid[i] = midTraversal[i]; //复制左子树中序遍历子序列
}
currentRoot->Leftchild = postorder_midorder(leftPost, leftMid, leftLength);
}
//递归创建右子树
if (parentpos == currentLength - 1)//中序遍历的结果中父节点在末位,说明此时只有左子树,没有右子树
currentRoot->Rightchild = NULL;
else
{
rightLength = currentLength - (parentpos + 1);//右子树遍历序列的长度可以有中序遍历中根节点的位置确定
char rightMid[MAX_LENGTH]; //右子树中序遍历结果
char rightPost[MAX_LENGTH]; //右子树先序遍历结果
for (int i = 0; i < rightLength; i++)
{
rightPost[i] = postTraversal[i + leftLength];
rightMid[i] = midTraversal[i + parentpos + 1];
}
currentRoot->Rightchild = postorder_midorder(rightPost, rightMid, rightLength);
}
}
return currentRoot;
}
void pre(Node* root)
{
printf("%c ",root->data);
if (root->Leftchild!=NULL)
pre(root->Leftchild);
if (root->Rightchild!=NULL)
pre(root->Rightchild);
}
void post(Node* root)
{
if (root->Leftchild != NULL)
post(root->Leftchild);
if (root->Rightchild != NULL)
post(root->Rightchild);
printf("%c ",root->data);
}
int main()
{
int length,cases;
Node *root = (Node*)malloc(sizeof(Node));
char preTraversal[MAX_LENGTH],midTraversal[MAX_LENGTH],postTraversal[MAX_LENGTH];
printf("选择类型:1、先序中序找后序. 2、后序中序找先序:");
scanf("%d",&cases);
if (cases == 1){
printf("输入先序遍历的结果:");
scanf("%s", preTraversal);
printf("输入中序遍历的结果:");
scanf("%s", midTraversal);
printf("输入遍历结果的长度:");
scanf("%d", &length);
root = preorder_midorder(preTraversal, midTraversal, length);
printf("后序遍历的结果为:");
post(root);
}
else if (cases == 2)
{
printf("输入后序遍历的结果:");
scanf("%s", postTraversal);
printf("输入中序遍历的结果:");
scanf("%s", midTraversal);
printf("输入遍历结果的长度:");
scanf("%d", &length);
root = postorder_midorder(postTraversal, midTraversal, length);
printf("先序遍历的结果为:");
pre(root);
}
printf("\n");
return 0;
}