问题分析
- 条件:已知前序遍历结果数组Pre[]和中序遍历结果数组Mid[]。
- 目标:确定后序遍历结果数组Post[]。
- 三种遍历结果之间的关联:
三种遍历结果的结构如下图所示:
对上图进行分析,可以确定Pre[]和Mid[]在求解Post[]中各自发挥的作用:Pre[]的作用为找到根节点root, Mid[]的作用为根据当前root划分左右子树用于递归求解。
算法思路
- 首先在Pre[]中找到root(即为pre的首元素),将root值填到Post[]中对应存放root的位置;
- 在Mid[]中找到root的位置,其左右两侧即为作、右子树;
- 递归求解左、右子树,直至子树节点数为0或1。
算法实现
/*
Parameters:
Pre, Mid: 存储PreOrder, MidOrder结果的数组(已知);
Post: 存储PostOrder结果的数组(目标);
PreL, MidL, PostL: 当前处理的子树节点在Pre[],Mid[],Post[]中分别对应的起始位置;
Length: 当前处理的子树具有的节点数目。
*/
void BinaryTree::CalPostOrder(int* Pre, int* Mid, int* Post, int PreL, int MidL, int PostL, int length) {
if (length == 0) return; // 子树节点数为0,结束递归
if (length == 1) { // 子树只有一个节点,Pre[PreL], Mid[MidL], Post[PostL]都对应相同的数据,直接赋值即可
Post[PostL] = Pre[PreL];
return;
}
int RootData = Pre[PreL]; //找到root
Post[PostL + length - 1] = RootData; //给Post[]赋值
int i = 0;
for (; i < length; i++) {
if (Mid[MidL + i] == RootData) break; //找到 Mid[]中root的位置
}
int LeftLength = i; //左子树节点数
int RightLength = length - 1 - i; //右子树节点数
CalPostOrder(Pre, Mid, Post, PreL + 1, MidL, PostL, LeftLength); //求解左子树
CalPostOrder(Pre, Mid, Post, PreL + 1 + LeftLength, MidL + 1 + LeftLength, PostL + LeftLength, RightLength); //求解右子树
}
算法测试
在0-100范围内随机产生10个正整数,将其插入树,分别进行前序、中序、后序遍历,再根据前序和中序的结果计算后序遍历结果,测试结果如下:
将两种后序遍历结果进行对比,可以看出两种方式得到的后序遍历结果是相同的。