根据先序序列和中序序列构造二叉树,最关键是确认根节点 左子树和右子树在序列中的具体位置。
首先,对于先序序列,根节点总是第一个,然后在中序序列中寻找到该根节点的位置,该位置的左右两边便是该根节点的左右子树,这便是根据先序序列和中序序列构造二叉树的原理。利用该原理继续对左右子树进行递归,便可构造完整的二叉树。
我们将写一个构造二叉树的函数,传递参数为先序序列A中子树的起点A_b和中点A_e,中序序列B中子树的起点B_b和中点B_e,这样做的原因是我们要实现递归构造,比如一开始从整棵树的根节点出发,那么四个参数是A_b = 1, A_e = n, B_b =1, B_e =n,(即从A[1]到A[n],从B[1]到B[n])。此时A[ A_a ]为根节点,即root = &A[ A_a ],我们将在B中寻找到它的位置,然后记录下根节点相对B[ B_b ]的位置,什么意思呢,即找到 i 使 B[ B_b + i ].num = root -> num(我们是通过判断节点的值是否相等来寻找节点的),i 就是相对位置,那么在B中,根节点的左子树为从B[ B_b] 到 B[ B_b + i - 1 ],右子树为从B[ B_b + i + 1 ]到 B[ B_e ]。然后我们也将左右子树在A中的位置也确定下来,A[ A_b ]是根节点,这一点刚才已经说了,然后该根节点的左子树是从A[ A_b + 1 ]到A[ A_b + i ],右子树是从A[ A_b + i + 1 ]到A[ A_e ]。
比较麻烦的地方就是上面确定左右子树分别在序列中的起点和终点。= = 要细心点
还有就是要利用相对位置 i 来判断左右子树是否为空的情况,我们知道 B_b + i 代表根节点在B中的位置,其左右就刚好是左右子树。但是,若B_begin + i == B_begin,则说明左子树为空,同理,若B_begin + i == B_end,则说明右子树为空,因此千万别忘了判断是否为空的情况。
^O^ 下面将给出c++代码
该函数的功能:调用该函数后,先序序列A中的节点的 left 和 right 指针都将正确指向其左右子节点
struct node{
int num;
struct node* left;
struct node* right;
};
//里面放着按先序序列排序的节点
node A[LEN];
//里面放着按中序序列排序的节点
node B[LEN];
/***搜索根在B中相对B_begin的位置***/
void search(node* T, const int B_begin, const int B_end, int &location)
{
for (int i = B_begin; i <= B_end; i++)
{
if (T->num == B[i].num){
location = i - B_begin;
break;
}
}
}
/***根据先序序列和中序序列构造二叉树***/
void build_tree(int A_begin, int A_end, int B_begin, int B_end)
{
node* T = &A[A_begin];
int i = 0;
//记录根在B中相对B_begin的位置,即( B_begin + i )代表着根节点在B中的位置
search(T, B_begin, B_end, i);
//A[A_begin + 1] 和 A[A_begin + i + 1]分别为左右子树的根节点
//B是中序序列,( B_begin + i )代表着根节点的位置,左右子树位于它的左右两边,但是,若B_begin + i == B_begin,
//则说明左子树为空,同理,若B_begin + i == B_end,则说明右子树为空,千万别忘了判断是否为空的情况。
if(B_begin + i != B_begin )
T->left = &A[A_begin + 1];
else T->left = NULL;
if( B_begin + i != B_end )
T->right = &A[A_begin + i + 1];
else T->right = NULL;
//递归左子树,能递归的条件是B_Begin < B_begin + i - 1;
//若 !( B_Begin < B_begin + i - 1 ),此时剩一个节点,为叶子节点。又或者左子树为空
if(B_begin < B_begin + i - 1)
build_tree(A_begin + 1, A_begin + i, B_begin, B_begin + i - 1);
else{
A[A_begin + i].left = NULL;
A[A_begin + i].right = NULL;
}
//递归右子树,能递归的条件是B_Begin + i + 1 < B_end;
//若 !( B_Begin + i + 1 < B_end ),此时剩一个节点,为叶子节点。又或者右子树为空
if(B_begin + i + 1 < B_end)
build_tree(A_begin + i + 1, A_end, B_begin + i + 1, B_end);
else
{
A[A_end].left = NULL;
A[A_end].right = NULL;
}
}