面试题19:二叉树的镜像(来自《剑指Offer》)

题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。

二叉树结点的定义如下:


[cpp] view plain copy print ?

1. struct
2. {  
3. int
4.     BinaryTreeNode *Left;  
5.     BinaryTreeNode *Right;  
6. };


通过画图,可知二叉树的镜像如下图所示:

如何将两个镜像加入一个pod中_结点

根据画图可得到这样的思路:先序遍历树的每个结点,若遍历到的结点有子结点,则交换它的两个子结点。

有两种实现方法:

1.递归实现


[cpp] view plain copy print ?



    1. void
    2. {  
    3. if(NULL == pNode)  
    4. return;  
    5. if(NULL == pNode->Left && NULL == pNode->Right)  
    6. return;  
    7.       
    8.     BinaryTreeNode *pTemp = pNode->Left;  
    9.     pNode->Left = pNode->Right;  
    10.     pNode->Right = pTemp;  
    11.       
    12. if(pNode->Left)  
    13.         MirroRecursively(pNode->Left);  
    14. if(pNode->Right)  
    15.         MirroRecursively(pNode->Right);  
    16. }



    2.非递归实现,即使用循环实

    void MirrorNonRecurively(BinaryTreeNode *pNode)  
    {  
        if(NULL == pNode)  
            return;  
      
        stack<BinaryTreeNode *> stackTreeNode;  
        stackTreeNode.push(pNode);  
      
        while(stackTreeNode.size())  
        {  
            BinaryTreeNode *pNode = stackTreeNode.top();  
            stackTreeNode.pop();  
      
            if(NULL != pNode->Left || NULL != pNode->Right)  
            {  
                BinaryTreeNode *pTemp = pNode->Left;  
                pNode->Left = pNode->Right;  
                pNode->Right = pTemp;  
            }  
              
            if(NULL != pNode->Left)  
                stackTreeNode.push(pNode->Left);  
      
            if(NULL != pNode->Right)  
                stackTreeNode.push(pNode->Right);  
        }  
    }








    链表的逆置问题:

    利用链表的头插法和尾插法

    1,我们不应该使得链表断裂,也就是说:无论什嘛时候,我们都必须能访问到数据


    void Reverse(LinkList H)
    {
            LNode *p, *q;
            p = H->next;
            H->next = NULL;
            while(p)
            {
                    q = p;
                    p = p->next;
                    q->next = H->next;
                    H->next = q;
            }
    }





    合并两个排序的链表

    1,容易犯的两种错误:

      1,在写代码之前没有对合并的过程想清楚,最终合并出来的链表要么中间断开了要么并没有做到

        递增排序;

      2,代码在鲁棒性方面存在问题,程序一旦有特殊的输入(如:空链表)就会崩溃

        1,第一个链表是空链表,也就是头节点是一个空指针,那么它和第二个链表合并,显然合并

          的结果就是第二个链表;同样的,当输入的第二个链表的头节点是空指针的时候,我们把

          它和第一个链表合并得到的结果就是第一个链表;如果两个链表都是空的,那么合并的结

          果就是一个空链表。。。。。。。



    Node *ListMerge1(Node *head1,Node *head2)//采用递归的方法实现  
        {  
            if(head1==NULL)  
                return head2;  
            if(head2==NULL)  
                return head1;  
            Node *head=NULL;  
            if(head1->value < head2->value)  
            {  
                head=head1;  
                head->next=ListMerge1(head1->next,head2);  
            }  
            else  
            {  
                head=head2;  
                head->next=ListMerge1(head1,head2->next);  
            }  
            return head;  
        }





    算法的非递归实现如下:

    Node *ListMerge(Node *head1,Node *head2)
    {
    	if(!head1) return head2;
    	if(!head2) return head1;
    	Node *head=NULL;//合并后的头指针
    	Node *p1=head1;//p1用于扫描链表1
    	Node *p2=head2;//p2用于扫描链表2
    	if(head1->value<head2->value)
    	{
    		head=head1;
    		p1=head1->next;
    	}
    	else
    	{
    		head=head2;
    		p2=head2->next;
    	}
    	Node *p=head;//p永远指向最新合并的结点
    	while(p1 && p2)//如果循环停止,则p1或p2至少有一个为NULL
    	{
    		if(p1->value<p2->value)
    		{
    			p->next=p1;
    			p1=p1->next;
    		}
    		else
    		{
    			p->next=p2;
    			p2=p2->next;
    		}
    		p=p->next;
    	}
    	if(p1)//如果链1还没走完
    	{
    		p->next=p1;
    	}
    	else if(p2)//如果链2还没走完
    	{
    		p->next=p2;
    	}
    	return head;
    }