【剑指Offer面试题】 九度OJ1523:从上往下打印二叉树

题目链接地址:
http://ac.jobdu.com/problem.php?pid=1523

题目1523:从上往下打印二叉树

时间限制:1 秒内存限制:128 兆特殊判题:否提交:1148解决:484
题目描述:
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
输入:
输入可能包含多个测试样例,输入以EOF结束。
对于每个测试案例,输入的第一行一个整数n(1<=n<=1000, :n代表将要输入的二叉树元素的个数(节点从1开始编号)。接下来一行有n个数字,代表第i个二叉树节点的元素的值。接下来有n行,每行有一个字母Ci。
Ci=’d’表示第i个节点有两子孩子,紧接着是左孩子编号和右孩子编号。
Ci=’l’表示第i个节点有一个左孩子,紧接着是左孩子的编号。
Ci=’r’表示第i个节点有一个右孩子,紧接着是右孩子的编号。
Ci=’z’表示第i个节点没有子孩子。
输出:
对应每个测试案例,
按照从上之下,从左至右打印出二叉树节点的值。
样例输入:
7
8 6 5 7 10 9 11
d 2 5
d 3 4
z
z
d 6 7
z
z
样例输出:
8 6 10 5 7 9 11


思路分析:

从上至下,从左至右遍历二叉树,很明显这是二叉树的层序遍历。用队列是最好的办法了。算法思路:
- 初始化时,申请一个队列用于保存二叉树的结点,将二叉树的根结点push入队;
- 只要队列不为空,就弹出队列的队首元素进行输出,如果该元素还有左右孩子,则将其左右孩子也依次push进队;
- 循环步骤2,直到队列为空时,执行结束。
时间复杂度O(n)
空间复杂度O(n)
注意:

  • 由于输入有数字和字符,所以要考虑输入缓冲队列的问题。如果某行含有字符则在最后会留下换行符,然后读取下一行的输入字符时,就会读取错误字符。因此在下一行数据开始输入前,要刷新缓冲区, 通过while((ch = getchar()) != ‘\n’) ; while–getchar()来吃掉前面scanf输入的’\n’。
  • 输出格式上,输出的各节点要有一个空格,且输出最后一个元素后没有空格,而是输出一个换行符。
  • 测试用例中,根节点是哪一个,题目并没指定,所以要根据入度来判断哪个才是根,根节点入度为0。(这里坑死我了,一直WA。潜意识里认为第一个元素就是根节点。。。。。。。)
    如何根据入度来判断根节点以及构造二叉树呢:

    1. 将各个结点都看成是只有根结点而没有左右孩子的二叉树
    2. 根据各个结点之间的链接关系构造每个结点的左右孩子结点,将每个结点并入到所要构造的二叉树中;
    3. 确定根结点, 如果某个结点不是任何结点的孩子结点,则该结点就是根结点。

代码:

/********************************* 
【剑指Offer面试题】 九度OJ1523:从上往下打印二叉树
Author:牧之丶  Date:2015年
Email:bzhou84@163.com 
**********************************/
#include <stdio.h>
#include <stdlib.h>  
#include <string>
#include <math.h>
#include <stack>
#include <vector>
#include<queue>  
using namespace std;  
#define MAX 1005

// 定义二叉树的结点
typedef struct Node
{
    int data;              
    Node * lchild;        
    Node * rchild;   
    bool isRootNode;       // 标记该结点是否为根结点
}BTNode;
BTNode biTNode[MAX];      // 二叉树所有结点数组
//构造有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 LevelTraverse(BTNode * root)  
{  
    if(!root)
        return;
    BTNode * cur;              // 当前正在被遍历的二叉树结点  
    queue <BTNode *> queueTreeNode;  
    queueTreeNode.push(root);                  // 将二叉树的根结点插入到队列末尾  
    while(queueTreeNode.size())  
    {  
        cur = queueTreeNode.front();  
        queueTreeNode.pop();  
        if(cur == root)  
        {  
            printf("%d",cur -> data);    // 格式  
        }  
        else 
        {  
            printf(" %d",cur -> data);    // 格式  
        }  

        if(cur -> lchild)     // 将当前结点的左孩子插入到队列末尾  
        {  
            queueTreeNode.push(cur -> lchild);  
        }  
        if(cur -> rchild)     // 将当前结点的右孩子插入到队列末尾  
        {  
            queueTreeNode.push(cur -> rchild);  
        }  
    }  
    printf("\n");  
}  

int main()  
{  
    BTNode * root;  
    int n;  
    while(EOF != scanf("%d",&n))  
    {  
        root = createBTree(n);  
        LevelTraverse(root);             // 层序遍历二叉树  
    }  
    return 0;  
}  
/**************************************************************
    Problem: 1523
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1084 kb
****************************************************************/
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值