众所周知只有前序遍历和后序遍历是不可能推出中序遍历的,所以我就不废话了
1.由树的前序遍历和中序遍历推后序遍历
假设树是酱婶的
首先前序遍历为 123456,中序遍历为324165,没什么问题,如果不会求前序或中序百度一下就好
定义函数原型postorder(int root,int start,int end)
root是前序遍历中当前树的根节点索引(单看中序遍历找不到根节点,前序遍历就可以)
start为当前树在中序遍历中的起点索引
end为当前树在中序遍历中的终点索引
所以函数入口为(0,0,5)
因为整个树的根节点在前序遍历的索引为0,整个树的起点在中序遍历中的起点为0,终点为最后一个点下标即5
void postorder(int root, int start, int end)
{
if (start > end)//如果左区间大于右区间,直接返回函数,当这个区间只有一个元素之后的下一个递归函数就是在这里弹出
{
return;
}
int rot = preorder[root];//当前根节点
int index;//index找到inorder中对应根节点的索引
for (int i = 0; i < inorder.size(); i++)
{
if (inorder[i] == rot)
{
index = i;
break;
}
}
post(root + 1, start, index - 1);//递归左子树,root+1就是左子树的根节点在preorder中的索引
post(root + 1 + index - start, index + 1, end);//递归右子树,第一个参数中index-start是指左子树的个数,root+1+左子树的个数就是右子树的根节点在preorder中的索引
postorder.push_back(preorder[root]);//将当前根节点放入postorder中(后序遍历是左右根的顺序)
}
}
注意:preorder,inorder,postorder分别是前序遍历,中序遍历和后序遍历的向量。
2.由树的中序遍历和后序遍历推前序遍历
基本思想跟上述一样,只不过根节点每次都是从后序遍历中从后往前找(1中是从前序遍历中从前往后找,所以总的函数基本一样,只不过后面递归函数参数以及将当前根节点放入向量中的顺序不太一样)
函数入口为(5,0,5)
因为整个树的根节点在后序遍历的索引为5(后序遍历最后一个值),整个树的起点在中序遍历中的起点为0,终点为最后一个点下标即5
void preorder(int root, int start, int end)
{
if (start > end)//如果左区间大于右区间,直接返回函数,当这个区间只有一个元素之后的下一个递归函数就是在这里弹出
{
return;
}
int rot = postorder[root];//当前根节点
int index;//index找到inorder中对应根节点的索引
for (int i = 0; i < inorder.size(); i++)
{
if (inorder[i] == rot)
{
index = i;
break;
}
}
preorder.push_back(postorder[root]);//将当前根节点放入preorder中(后序遍历是根左右的顺序)
post(root-(end-index)-1, start, index - 1);//递归左子树,第一个参数中end-index是指右子树的个数,root-右子树的个数-1就是左子树的根节点在preorder中的索引
post(root-1, index + 1, end);//递归右子树,root-1就是右子树的根节点在preorder中的索引
}
}
注意:preorder,inorder,postorder仍然分别是前序遍历,中序遍历和后序遍历的向量。
其次,最难的部分就是函数中第一个参数,只要找准左子树跟右子树的根节点索引即可
因为前序遍历是根左右,所以左子树的根节点是root+sth(这里是加号)
因为后序遍历是左右根,所以得左右子树根节点时是root-sth(这里是减号)
同时注意:前序遍历中root+1先得到的是左子树根节点(因为是根左右),其次加上右子树的个数就是右子树根节点。而后序遍历中root-1先得到的是右子树根节点(因为是左右根),其次减上左子树的个数就是左子树根节点。
成了,以上就是简单模式下的由树的前序遍历和中序遍历推后序遍历&&由树的中序遍历和后序遍历推前序遍历,简单模式下假定树的所有节点的值都是不相同的,所以困难模式下还有树中有相等的值,此时会有一些变式,有时间我会在写下来。