题目大意是:将一个存储了操作数和操作符的树转换成中缀表达式。
其核心在于树的中序遍历和中缀表达式中括号的添加。
比如下图:
将其转化为中缀表达式即为:(A+(B*(C-D)))+(E/F)
算法思想:如果结点是根节点,则直接输出对应操作符;如果结点是叶子结点,则直接输出对应操作数;如果都不是,即结点为有子结点的分支结点,则在输出其左子树之前加上“(”,在输出其右子树之后加上“)”。
伪代码描述:
void BtreeToE(BTree *root){
BtreeToExp(root,1); //根的高度为1
}
void BtreeToExp(BTree *root,int deep)
{
if(root==NULL) return; //空结点返回
else if(root->left==NULL&&root->right==NULL) //若为叶结点
cout<<root->data; //输出操作数,不加括号
else{
if(deep>1) cout<<"("; //若有子表达式则加1层括号
BtreeToExp(root->left,deep+1);
cout<<root->data; //输出操作符
BtreeToExp(root->right,deep+1);
if(deep>1) cout<<")"; //若有子表达式则加1层括号
}
}
接下来我们根据代码来过一遍样例。
首先根结点“+”传入BtreeToE函数,调用BtreeToExp函数,形参为(根结点“+”,1),进入第二个else,此时deep=1,不输出左括号,调用BtreeToExp函数对其左子节点“+”进行访问。
结点“+”进入第二个else,它的deep=2>1,因此输出“(”,再调用BtreeToExp函数对其左子节点“A”进行访问。
结点“A”是叶结点,直接输出,此时输出为“ (A ”。
结点“+”的左子树访问完成,执行输出,此时输出为“ (A+ ”。再调用BtreeToExp函数对其右子节点“*”进行访问。
结点“*”进入第二个else,它的deep=3>1,因此输出“(”,此时输出为“ (A+( ”。再调用BtreeToExp函数对其左子节点“B”进行访问。
结点“B”是叶结点,直接输出,此时输出为“ (A+(B ”。
结点“*”的左子树访问完成,执行输出,此时输出为“ (A+(B* ”。再调用BtreeToExp函数对其右子节点“-”进行访问。
结点“-”进入第二个else,它的deep=4>1,因此输出“(”,此时输出为“ (A+(B*( ”。再调用BtreeToExp函数对其左子节点“C”进行访问。
结点“C”是叶结点,直接输出,此时输出为“ (A+(B*(C ”。
结点“-”的左子树访问完成,执行输出,此时输出为“ (A+(B*(C- ”。再调用BtreeToExp函数对其右子节点“D”进行访问。
结点“D”是叶结点,直接输出,此时输出为“ (A+(B*(C-D ”。
结点“-”的右子树访问完成,而它的deep=4>1,因此输出“)”,此时输出为“ (A+(B*(C-D) ”。
结点“*”的右子树访问完成,而它的deep=3>1,因此输出“)”,此时输出为“ (A+(B*(C-D)) ”。
结点“+”的右子树访问完成,而它的deep=2>1,因此输出“)”,此时输出为“ (A+(B*(C-D))) ”。
根结点“+”的左子树访问完成,执行输出,此时输出为“ (A+(B*(C-D)))+ ”。再调用BtreeToExp函数对其右子节点“/”进行访问。
结点“/”进入第二个else,它的deep=2>1,因此输出“(”,此时输出为“ (A+(B*(C-D)))+( ”。再调用BtreeToExp函数对其左子节点“E”进行访问。
结点“E”是叶结点,直接输出,此时输出为“ (A+(B*(C-D)))+(E ”。
结点“/”的左子树访问完成,执行输出,此时输出为“ (A+(B*(C-D)))+(E/ ”。再调用BtreeToExp函数对其右子节点“F”进行访问。
结点“F”是叶结点,直接输出,此时输出为“ (A+(B*(C-D)))+(E/F ”。
结点“/”的右子树访问完成,而它的deep=2>1,因此输出“)”,此时输出为“ (A+(B*(C-D)))+(E/F) ”。
根结点“+”的右子树访问完成,而它的deep=1,不输出右括号,最终所得输出为“ (A+(B*(C-D)))+(E/F) ”。
函数执行完毕,结果正确。
算法分析:
此算法采用递归思想和树的中序遍历思想,每个结点都遍历且只遍历了一遍,因此其时间复杂度为O(n)。