二叉树的镜像(反转二叉树)

题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。
二叉树结点的定义如下:

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
二叉树的深度优先遍历和广度优先遍历

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值