先序中序后序的相互求解问题
一、问题描述
我们知道,二叉树有三种深度优先遍历方法:先序中序以及后序,那么,如何已知其中两种遍历序列,求解第三种遍历序列呢。
其实也没大家想得那么美好哈,已知先序、中序可以确定后序,已知中序,后序可以确定先序,但是已知先序和后序是不能确定中序的。究其原因,其实很简单,因为中序可以确定根节点的左孩子是哪块,右孩子是哪块,就是可以确定父子关系嘛。但是如果知道先序和后序的话,举一个例子,看下面的图:
先序为:1 2;后序为:2 1
先序为:1 2;后序为 2 1
所以,其实已知先序和后序时,是不能确定二叉树的,但是如果含有中序序列,那是可以的。
二、解决方案
我们看下如果手算是怎样的、、举个例子哈,先从先序中序开始:
先序:1 2 3 4 5 6
中序:3 2 4 1 6 5
(1)首先,从先序来看,我们知道1是先序的第一个元素,也是这棵二叉树的根节点。
(2)接着,我们找中序里面对应的1的位置,找到了之后,我们发现3 2 4是在1的左边,也就是说这些都是1的左孩子,先不管这些内部复杂的亲子兄弟关系了。6 5是在1的右边,也就是说这些都是1的右孩子。
(3)在先序中找2 3 4的第一个,是2,在中序里面对应的2左边是3,右边是4,分别是它的左右孩子。
(4)在先序中找6 5,发现第一个是5,在中序里面对应的5地左边是6,右边没有,也就是说,5只有一个左孩子,是6。
(5)由此得到的树为:
已知中序和后序的也很类似,就不详述了。
那么,下面介绍用算法实现的步骤是什么,其实就是简单的递归:
(1)确定根,确定左子树,确定右子树。
(2)在左子树中递归。
(3)在右子树中递归。
(4)打印当前根。
这样看上去似乎很简单,下面看代码好了三、代码实现
(1)已知先序中序求后序
<pre name="code" class="cpp">struct TreeNode{//每一个节点的属性:左节点、右节点、数据
int data;
TreeNode* left;
TreeNode* right;
};
void BinaryTreeFromOrderings(int *inorder,int *preorder,int length)//中序序列,先序序列,中序中需要寻找的字段长度
{
if(length==0)
return;
TreeNode* node=new TreeNode;//新建一个节点,节点的数据为先序的首个元素
node->data=*preorder;
int rootIndex;//根节点在中序数组中的下标
for(rootIndex=0;rootIndex<length;rootIndex++)
if(inorder[rootIndex]==*preorder)
break;
//后序遍历输出结果
BinaryTreeFromOrderings(inorder,preorder+1,rootIndex);//中序的左边一半长度作为新的需要寻找的字段长度
BinaryTreeFromOrderings(inorder+rootIndex+1,preorder+rootIndex+1,length-(rootIndex+1));//中序的后面一段长度作为需要寻找的字段长度
cout<<node->data;
}
(2)已知中序后序求先序
struct TreeNode{//每一个节点的属性:左节点、右节点、数据
int data;
TreeNode* left;
TreeNode* right;
};
void BinaryTreeFromOrderings(int *inorder,int *lastorder,int length)//中序序列,先序序列,中序中需要寻找的字段长度
{
if(length==0)
return;
TreeNode* node=new TreeNode;
node->data=lastorder+length-1;
int rootindex;
for(rootindex=0;rootindex<length;rootindex++)
if(inorder[rootindex]==node->data)
break;
cout<<node->data<<" ";
BinaryTreeFromOrderings(inorder,lastorder,rootindex);
BinaryTreeFromOrderings(inorder+rootindex+1,lastorder+rootindex,length-(rootindex+1));
}