1.题目
请完成一个函数,输入一棵二叉树,该函数输出它的镜像。二叉树结点的定义如下。
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;;
};
2.就题论题
树的镜像对很多人来说是一个新的概念,我们未必能够一下子想出求树的镜像的方法。为了能够形成直观的印象,我们可以自己画一棵二叉树,然后根据照镜子的经验画出它的镜像。如图一所示中右边的二叉树就是左边的树的镜像。
仔细分析这两棵树的特点,看看能不能总结出求镜像的步骤。这两棵树的根结点相同,但它们的左、右两个子结点交换了位置。因此,我们不妨先在树中交换根结点的两个子结点,就得到图二中的第二棵树。
交换根结点的两个子结点之后,我们注意到值为10、6的结点的子结点仍然保持不变,因此我们还需要交换这两个结点的左、右子结点。交换之后的结果分别是图二中的第三棵树和第四棵树。做完这两次交换之后,我们已经遍历完所有的非叶结点。此时变换之后的树刚好就是原始树的镜像。
总结上面的过程,我们得出求一棵树的镜像的过程:先前序遍历这棵树的每个结点,如果遍历到的结点有子结点,就交换它的两个子节点。当交换完所有非叶子结点的左、右子结点之后,就得到了树的镜像。
想清楚了这种思路,我们就可以动手写代码了。参考代码如下:
void MirrorRecursively(BinaryTreeNode *pNode)
{
if(pNode==nullptr)
return ;
if(pNode->m_pLeft==nullptr&&pNode->m_pRight==nullptr)
return ;
BinaryTreeNode *pTemp=pNode->m_pLeft;
pNode->m_pLeft=pNode->m_pRight;
pNode->m_pRight=pTemp;
if(pNode->m_pLeft)
MirrorRecursively(pNode->m_pLeft);
if(pNode->m_pRight)
MirrorRecursively(pNode->m_pRight);
}
看懂这题之后,我们再来看看另外一道和它相似的题目。
3.题目
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。例如,在图三所示的3棵二叉树中,第一棵二叉树是对称的,而另外两棵不是。
4.就题论题
三棵二叉树,其中第一棵二叉树是对称的,另外两棵不是。如果这题想用上题的思路的话估计有点难实现,因为考虑的是对称,需要比较的两个点并不是同一个双亲结点。那我们就换种思路,通常我们有3种不同的二叉树遍历算法,即前序遍历、中序遍历和后续遍历。在这3种遍历算法中,都是先遍历左子结点再遍历右子结点。我们是否可以定义一种遍历算法,先遍历右子结点再遍历左子结点?比如我们针对前序遍历定义一种对称的遍历算法(千万不要认为和前序遍历对称的是后序遍历)。先遍历父结点,再遍历它的右子结点,最后遍历它的左子结点。
如果用前序遍历算法遍历图三种的第一棵二叉树,则遍历序列是{8,6,5,7,6,7,5}。如果用我们定义的针对前序遍历的对称遍历算法,则得到的遍历序列是{8,6,5,7,6,7,5}。我们注意到这两个序列是一样的。
图三种第二棵二叉树的前序遍历序列为{8,6,5,7,9,7,5},而相应的对称前序遍历序列为{8,9,5,7,6,7,5}。在这两个序列中,第二步和第五步是不一样的。
第三棵二叉树有些特殊,它的所有结点的值都是一样的。它的前序遍历序列是{7,7,7,7,7,7},前序遍历的对称遍历序列也是{7,7,7,7,7,7}。这两个序列是一样的,可显然第三棵二叉树不是对称的。怎样才能正确地判断这种类型的二叉树呢?只要我们在遍历二叉树时把遇到的nullptr指针也考虑进来就行了。
比如第三棵二叉树的前序遍历在考虑nullptr指针之后为{7,7,7,nullptr,nullptr,7,nullptr,nullptr,7,7,nullptr,nullptr,nullptr}。前序的前面3个7对应的是从根结点开始沿着指向左子结点的指针遍历经过的3个结点,接下来两个nullptr指针对应的是第三层第一个结点的两个子结点,其他的结点请读者自己分析。 前序遍历的对称遍历序列为{7,7,nullptr,7,nullptr,nullptr,7,7,nullptr,nullptr,7,nullptr,nullptr}。这两个序列从第三步开始就不一致了。
我们发现可以通过比较二叉树的前序遍历序列和对称前序遍历序列来判断二叉树是不是对称的。如果两个序列是一样的,那么二叉树就是对称的。
bool isSymmetrical(BinaryTreeNode* pRoot)
{
return isSymmetrical(pRoot,pRoot);
}
bool isSymmetrical(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
{
if(pRoot1==nullptr&&pRoot2==nullptr)
return true;
if(pRoot1==nullptr||pRoot2==nullptr)
return false;
if(pRoot1->m_nValue!=pRoot2->m_nValue)
return false;
return isSymmetrical(pRoot->m_pLeft,pRoot->m_Right)&&isSymmetrical(pRoot->pRight,pRoot->_pLeft);
}