题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。
二叉树结点的定义如下:
struct BinaryTreeNode
{
int data;
BinaryTreeNode *Left;
BinaryTreeNode *Right;
};
树的镜像,可通过下图来直观的展示:
这两棵树,就是互为镜像的二叉树。
由图分析可知,求二叉树镜像的思路如下:
先序遍历树的每个结点,若遍历到的结点有子结点,则交换它的两个子结点。
解决方案:
1、递归方法:如果左子树和右子树都已经完成了镜像转换,则直接将它们在根节点下的顺序交换一下,整棵树就完成了镜像转换;
void MirroRecursively(BinaryTreeNode *pNode)
{
if((pNode == NULL) || (pNode->Left == NULL && pNode->Right == NULL))
return;
BinaryTreeNode *pTemp = pNode->Left;
pNode->Left = pNode->Right;
pNode->Right = pTemp;
if(pNode->Left)
MirroRecursively(pNode->Left);
if(pNode->Right)
MirroRecursively(pNode->Right);
}
2、非递归方法:题目的本意就是将每个节点的左右孩子交换一下顺序,所以用广度优先的顺序遍历即可,求解过程中需要队列作为辅助数据结构。
// 借助队列来实现
void MirroLoop(BinaryTreeNode* root)
{
if((root == NULL || (root->Left == NULL && root->Right == NULL))
return;
queue<BinaryTreeNode*> q;
q.push(root);
while(!q.empty())
{
BinaryTreeNode* r = q.front();
q.pop();
if(r->Left != NULL) q.push(r->Left);
if(r->Right != NULL) q.push(r->Right);
if(r->Left != NULL || r->Right != NULL)
{
BinaryTreeNode* temp = r->Left;
r->Left = r->Right;
r->Right = temp;
}
}
}
知识点补充:
1、非递归的另一种实现(借助栈作为辅助数据结构)
void MirroLoop(BinaryTreeNode *root)
{
if ((root == NULL || (root->Left == NULL && root->Right == NULL))
return;
stack<BinaryTreeNode *> s;
s.push(root);
while(s.size())
{
BinaryTreeNode *r = s.top();
s.pop();
if(r->Left != NULL) s.push(r->Left);
if(r->Right != NULL) s.push(r->Right);
if(r->Left != NULL || r->Right != NULL)
{
BinaryTreeNode *temp = r->Left;
r->Left = r->Right;
r->Right = temp;
}
}
}
2、 二叉树的深度优先遍历和广度优先遍历
(1)深度优先遍历,也就深入的遍历,沿着每一个分支直到走到最后,然后才返回来遍历剩余的节点。二叉树不同于图,图需要标记节点是否已经访问过,因为可能会存在环,而二叉树不会出现环,所以不需要标记。那么,我们只需要一个栈空间,来压栈就好了。因为深度优先遍历,遍历了根节点后,就开始遍历左子树,所以右子树肯定最后遍历。我们利用栈的性质,先将右子树压栈,然后再对左子树压栈。此时,左子树节点是在top上的,所以可以先去遍历左子树。
如下是二叉树的深度优先遍历代码:
void DepthFirstTravel(Tree *root)
{
stack<Tree *> s;
s.push(root);
while(!s.empty())
{
root = s.top();
cout << root->data << " ";
s.pop();
if(root->rchild != NULL) s.push(root->rchild);
if(root->lchild != NULL) s.push(root->lchild);
}
}
(2)广度优先遍历二叉树,即按层次的去遍历。依次遍历根节点,然后是左孩子和右孩子。所以要遍历完当前节点的所有孩子。此时我们不能用栈这个数据结构了,因为栈只能在栈顶操作。在这里,我们需要根据左右孩子的顺序来输出,所以就是先进先出的原则,那么应该用队列这个数据结构。可以在rear依次插入左右孩子,在front依次读取并删除左右孩子,这样就保证了层次的输出。
如下是二叉树的广度优先遍历代码:
void BreadthFirstTravel(Tree *root)
{
queue<Tree *> q;
q.push(root);
while(!q.empty())
{
root = q.front();
cout << root->data << " ";
q.pop();
if(root->lchild != NULL) q.push(root->lchild);
if(root->rchild != NULL) q.push(root->rchild);
}
}
参考资料:
剑指offer
二叉树的深度优先遍历和广度优先遍历