给定一棵二叉树,前序遍历结果为:a b d c e f
中序遍历结果为:d b a e c g
二叉树为:
</pre><pre name="code" class="cpp">#include <iostream>
using namespace std;
#define TREELEN 6
//定义节点
typedef struct node NODE;
struct node
{
NODE* pLeft;
NODE* pRight;
char chValue;
};
//根据前序遍历和中旬遍历的重建函数
void Rebuild(char *pPreOrder, char *pInOrder, int nTreeLen, NODE** pRoot)
{
// 防止输入的前序/中序数组为空,只要两个数组不为空,这个判断不起作用
if(pPreOrder == NULL || pInOrder == NULL)
{
return;
}
// 新建一个节点pTemp,因为前序遍历第一个值就是中间节点,所以直接赋值给pTemp,这样pTemp就存储了中间节点
NODE* pTemp = new NODE;
pTemp->chValue = *pPreOrder;
pTemp->pLeft = NULL;
pTemp->pRight = NULL;
// 将中间节点pTemp赋值给外部接口pRoot
if(*pRoot == NULL)
{
*pRoot = pTemp;
}
// 递归的最终输出,当前序和中序数组长度均为1时,直接将节点输出即可
if(nTreeLen == 1)
{
return ;
}
// 准备寻找左子树的长度,预设参数
char* pOrgInOrder = pInOrder;
char* pLeftEnd = pInOrder;
int nTempLen = 0;
// 左子树的长度
while(*pPreOrder != *pLeftEnd)
{
if(pPreOrder == NULL||pLeftEnd == NULL)
{
return;
}
nTempLen++;
//记录临时长度,以免溢出
if( nTempLen > nTreeLen )
{
break;
}
pLeftEnd++;
}
int nLeftLen = 0;
nLeftLen = int(pLeftEnd - pOrgInOrder);
// 右子树长度通过总长度和左子树长度求出
int nRightLen = 0;
nRightLen = nTreeLen - nLeftLen - 1;
//重建左子树
if( nLeftLen > 0 )
{
Rebuild( pPreOrder + 1, pInOrder, nLeftLen, &((*pRoot)->pLeft) );
}
//重建右子树
if( nRightLen>0 )
{
Rebuild(pPreOrder + nLeftLen + 1, pInOrder + nLeftLen +1, nRightLen , &((*pRoot)->pRight) );
}
}
int main()
{
char szPreOrder[TREELEN] = {'a','b','d','c','e','f'};
char szInOrder[TREELEN] = {'d','b','a','e','c','f'};
NODE *pRoot = NULL;
Rebuild(szPreOrder, szInOrder, TREELEN, &pRoot);
return 0;
}
递归步骤分析:(红色代表左子树,蓝色代表右子树,黑色是中间节点)
1. 前序遍历 ab dc e f
中序遍历 d b a e c f
2 (左) 前序遍历 bd (右) 前序遍历 ce f
中序遍历 d b 中序遍历 e c f
3 (左) 前序遍历 d (右) 前序遍历 空 3 (左) 前序遍历 e (右)前序遍历 f
中序遍历 d 中序遍历 空 中序遍历 e 中序遍历 f
在1中,保存中间节点a,然后进入左右部分递归
在2(左)中,保存中间节点b;在2(右),保存中间节点e。然后进入各自的左右递归。
在3(左)(左)中,保存中间节点d;在3(左)(右)中,无节点,空。 在3(右)(左)中,保存中间节点e;在3(右)(右)中,保存中间节点f。
得到二叉树: