您的位置:首页 > 职场人生

【剑指Offer面试题】 九度OJ1521:二叉树的镜像

2015-07-31 11:29 447 查看
题目链接地址:

http://ac.jobdu.com/problem.php?pid=1521

题目1521:二叉树的镜像

时间限制:1 秒内存限制:128 兆特殊判题:否提交:2075解决:564

题目描述:

输入一个二叉树,输出其镜像。

输入:

输入可能包含多个测试样例,输入以EOF结束。

对于每个测试案例,输入的第一行为一个整数n(0<=n<=1000,n代表将要输入的二叉树节点的个数(节点从1开始编号)。接下来一行有n个数字,代表第i个二叉树节点的元素的值。接下来有n行,每行有一个字母Ci。

Ci=’d’表示第i个节点有两子孩子,紧接着是左孩子编号和右孩子编号。

Ci=’l’表示第i个节点有一个左孩子,紧接着是左孩子的编号。

Ci=’r’表示第i个节点有一个右孩子,紧接着是右孩子的编号。

Ci=’z’表示第i个节点没有子孩子。

输出:

对应每个测试案例,

按照前序输出其孩子节点的元素值。

若为空输出NULL。

样例输入:

7

8 6 10 5 7 9 11

d 2 3

d 4 5

d 6 7

z

z

z

z

样例输出:

8 10 11 9 6 7 5

思路分析:

求二叉树镜像的过程:

先前序遍历二叉树的每个节点,如果结点有子节点,则把左右孩子结点进行对换,然后向下递归,直到第一个叶子节点结束。

二叉树每个点都会访问到一次,所以时间复杂度为O(n)。

空间复杂度O(1)。

这题算法理解了,代码好写,难而且折磨人的地方却是在测试用例和输入输出格式上。对于面试准备来说,过多拘泥于这些AC上,貌似浪费时间啊。

注意:

由于输入有数字和字符,所以要考虑输入缓冲队列的问题。如果某行含有字符则在最后会留下换行符,然后读取下一行的输入字符时,就会读取错误字符。因此在下一行数据开始输入前,要刷新缓冲区, 通过while((ch = getchar()) != ‘\n’) ; while–getchar()来吃掉前面scanf输入的’\n’。

输出格式上,输出的各节点要有一个空格,且输出最后一个元素后没有空格,而是输出一个换行符。

测试用例中,根节点是哪一个,题目并没指定,所以要根据入度来判断哪个才是根,根节点入度为0。(这里坑死我了,一直WA。潜意识里认为第一个元素就是根节点。。。。。。。)

如何根据入度来判断根节点以及构造二叉树呢:

将各个结点都看成是只有根结点而没有左右孩子的二叉树

根据各个结点之间的链接关系构造每个结点的左右孩子结点,将每个结点并入到所要构造的二叉树中;

确定根结点, 如果某个结点不是任何结点的孩子结点,则该结点就是根结点。

更详细的处理方法看代码注释!!

代码:

/********************************* 
【剑指Offer面试题】 九度OJ1521:二叉树的镜像
Author:牧之丶  Date:2015年
Email:bzhou84@163.com 
**********************************/
#include<stdio.h>
#include<stdlib.h>  
#include<string>
#include <math.h>
#include<stack>
#include <vector>
#include <iostream>
using namespace std;

#define MAX 1005

// 定义二叉树的结点
typedef struct Node
{
   int data;              
   Node * lchild;        
   Node * rchild;   
   bool isRootNode;       // 标记该结点是否为根结点
}BTNode;
BTNode biTNode[MAX];      // 二叉树所有结点数组

//将二叉树非叶子结点的左右孩子进行对换得到二叉树的镜像
void MirrorTree(BTNode * pNode)
{
  if(NULL == pNode||(pNode->lchild==NULL&&pNode->rchild==NULL))
  return;
  BTNode * temp;
  temp = pNode -> lchild;
  pNode -> lchild = pNode -> rchild;
  pNode -> rchild = temp;
  MirrorTree(pNode -> lchild);
  MirrorTree(pNode -> rchild);
}

//构造有n个结点的二叉树
BTNode * createBTree(int n)
{
    BTNode * rootNode = NULL;     //根节点
    if(n==0)                        // 边界检查
        return rootNode;
    char Ci;                          // 字符,Ci代表含有多少孩子结点的标志字符
    // 二叉树结点的数据域,二叉树结点的左孩子在biTNode[]的序号和右孩子在biTNode[]的序号
    int i,data,lChildNumber,rChildNumber;                        
    // 先构造,将各个结点都看成是只有根结点而没有左右孩子的二叉树
    for(i = 1;i <= n;i++)
    {
        scanf("%d",&data);
        biTNode[i].data = data;
        biTNode[i].lchild = NULL;
        biTNode[i].rchild = NULL;
        biTNode[i].isRootNode = true;
    }
    // 根据各个结点之间的链接关系构造每个结点的左右孩子结点,将每个结点并入到所要构造的二叉树中
    for(i = 1;i <= n;i++)
    {
        char c;
        while((c = getchar()) != '\n')
            ;  //吃掉前面scanf输入那一行的'\n'
        scanf("%c",&Ci);
        switch(Ci)
        {
        case 'd':
            scanf("%d%d",&lChildNumber,&rChildNumber);
            biTNode[i].lchild = &biTNode[lChildNumber];     //定位左右孩子
            biTNode[i].rchild = &biTNode[rChildNumber];
            biTNode[lChildNumber].isRootNode = false;       // biTNode[lChildNumber]不是二叉树的根结点
            biTNode[rChildNumber].isRootNode = false;      
            break;
        case 'l':
            scanf("%d",&lChildNumber);
            biTNode[i].lchild = &biTNode[lChildNumber];
            biTNode[i].rchild = NULL;
            biTNode[lChildNumber].isRootNode = false;    
            break;
        case 'r':
            scanf("%d",&rChildNumber);
            biTNode[i].lchild = NULL;
            biTNode[i].rchild = &biTNode[rChildNumber];
            biTNode[rChildNumber].isRootNode = false;      
            break;
        case 'z':
            biTNode[i].lchild = NULL;
            biTNode[i].rchild = NULL;
            break;
        default:
            break;
        }
    }
    // 如果某个结点不是任何结点的孩子结点,则该结点就是根结点
    for(i = 1;i <= n;i++)
    {
        if(biTNode[i].isRootNode==true)
        {
            rootNode = &biTNode[i];                          // 确定根结点
            break;
        }
    }
    return rootNode;
}

//前序遍历输出二叉树
void PreOrder(BTNode * pNode)
{
   if(pNode==NULL)
   return;
   printf(" %d",pNode -> data);          //输出格式空格
   PreOrder(pNode -> lchild);
   PreOrder(pNode -> rchild);
}

int main()
{
    int n;
    BTNode * root;
    while(scanf("%d",&n)!=EOF)
    {
        root = createBTree(n);
        if(root == NULL)
        {
           printf("NULL\n");
        }
        else
        {
           MirrorTree(root);
           printf("%d",root -> data);    //输出格式
           PreOrder(root -> lchild);
           PreOrder(root -> rchild);
           printf("\n");                //输出格式最后
        }
    }
    return 0;
}
/**************************************************************
    Problem: 1521
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1552 kb
****************************************************************/


总结

将二叉树中非叶子结点的左右孩子结点对换得到二叉树镜像。

输入有数字和字符,考虑输入缓冲队列的问题。

根据入度来判断根节点的方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: