首先简单给一段序列:
pre [] = {A, B, D, E, C, F}
in [] = {D, B, E, A, C, F }
原树:{A, B, C, D, E, NULL, F}
先序序列的首个结点一定为根节点,然后我们又从中序遍历知,其序列的根的左侧为左树,右侧为根的右树;
将树按先左后右依次创建,在左树中又可存在左子树;由前序序列性质知,根结点后为左侧结点,然后为右侧根节点,右侧子树,因此由前序和中序可以还原一棵原二叉树。
下面讲解一下代码实现原理,主要为递归创建,首先创建根节点引用传入,防止被复制,导致无法对一个根节点进行操作,传入存放前序和中序的数组,方便起见默认我们起始坐标为0,指明区间范围
判断区间是否符合要求,不符合将传入结点置空,此外判断是否存在左右子树,到时再做分析;
遍历创建左子树:
mid:代表左侧根节点在中序序列中的下标,值代表以in[mid]为根结点的左侧结点数量
intLeft:中序序列首下标不动
preLeft = preLeft + 1 移动到根后一个单位,即左孩子(当preLeft > preRight时,即左侧节点创建完成是,终止,将当前节点置为null表示上一个调用该函数的左孩子为空)
preRight:: preLeft + mid - inLeft:前序中左树的最后一个下标
inRight = mid - 1 中序表中左树最后一位
及传入左孩子之后的序列(第一次创建完根结点后传入per[1-3], 及根的左子树所有节点),然后开始构建根结点左侧的树,先左孩子后有孩子
然后递归传入
mid:代表中序中根的下标,mid值表示以in[mid]为根左侧的结点数量
preLeft = preLeft + 1 移动到根后一个单位
preLeft + mid - inLeft 前序中左树的最后一位下标
inLeft:中序第一位,不动
inRight = mid - 1 中序表中左树最后一位
template<typename T>
void CreateBinaryTreeHelp(BinTreeNode<T> *&r, T pre[], T in[], int preLeft, int preRight, int inLeft, int inRight) {
if (preLeft > preRight || inLeft > inRight) {
r = nullptr;
} else {
r = new BinTreeNode<T>(pre[preLeft]);
int mid = inLeft;
while (in[mid] != pre[preLeft]) {
mid++;
}
//mid:代表中序中根的下标,mid值表示以in[mid]为根左侧的结点数量
//preLeft = preLeft + 1 移动到根后一个单位 preLeft + mid - inLeft 前序中左树的最后一位下标 inLeft:中序第一位,不动 inRight = mid - 1 中序表中左树最后一位
CreateBinaryTreeHelp(r->leftChild, pre, in, preLeft + 1, preLeft + mid - inLeft, inLeft, mid - 1);
CreateBinaryTreeHelp(r->rightChild, pre, in, preLeft + mid - inLeft + 1, preRight, mid + 1, inRight);
}
}
template<typename T>
BinaryTree<T> CreateBinaryTree(T pre[], T in[], int n) {
BinTreeNode<T> *r;
CreateBinaryTreeHelp<T>(r, pre, in, 0, n - 1, 0, n - 1);
return BinaryTree<T>(r);
}