PAT1004多叉树 叶子节点的个数

1004 Counting Leaves (30分)

A family hierarchy is usually presented by a pedigree tree. Your job is to count those family members who have no child.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 0<N<100, the number of nodes in a tree, and M (<N), the number of non-leaf nodes. Then M lines follow, each in the format:

ID K ID[1] ID[2] ... ID[K]    

where ID is a two-digit number representing a given non-leaf node, K is the number of its children, followed by a sequence of two-digit ID's of its children. For the sake of simplicity, let us fix the root ID to be 01.

The input ends with N being 0. That case must NOT be processed.

Output Specification:

For each test case, you are supposed to count those family members who have no child for every seniority level starting from the root. The numbers must be printed in a line, separated by a space, and there must be no extra space at the end of each line.

The sample case represents a tree with only 2 nodes, where 01 is the root and 02 is its only child. Hence on the root 01 level, there is 0 leaf node; and on the next level, there is 1 leaf node. Then we should output 0 1 in a line.

Sample Input:

2 1
01 1 02 

Sample Output:

0 1

题目大意:

给定一棵多叉树,求解每一层有多少叶子节点。然后按照层的顺序把每一层的叶子节点数进行输出。即使是0 个也输出0 。

思路分析:

树的节点编号从 0 – N-1.依然是对于多叉树的存储,我们一般是用邻接表存储。 比如之前的 1079、1090、1094、1106 这四道题,都是用对象数组进行存储。对象中包含了一个 存储孩子节点ID的 list 列表。 同样的思想,我们也可以用一个map 进行存储, key 存储父节点的ID , value 为一个list 列表,存储这个父节点的孩子节点们。 本质和邻接表是一样的。

下面的问题就转化为,在这样的一个存储模式下,如何求解每一层的叶子节点数。 其实深度优先遍历和广度优先遍历都是可以的。 这里我使用广度优先遍历,也就是层序遍历进行求解。

第一个问题是:我们如何判断一个节点是叶子节点? 它的孩纸个数为0 ,也就是map中,这个节点的key 对应的list 的size 为0 , 即孩子列表为空。

第二个问题是:如何统计每一层的叶子节点个数? 要统计每一层的叶子节点的个数,我们就必须把一层节点,放在一起处理。那么就需要我们在一个循环中把这层节点放在一起。首先我们需要知道这层节点有多少个,由于我们是在一个队列中进行计算,因此,初始时,root 节点入队,此时第1层只有一个节点。当我们在循环中处理完这一个节点,并把它的所有孩子节点入队时,下次队列中的所有节点都是第二层节点。 以此类推。

第三个问题是:我们说处理节点的时候,到底在处理什么? 其实就是判断当前从队列中取出的这个节点它是不是一个叶子节点,翻译成代码语言就是,这个节点的孩子列表是不是为空。

这次Java 可以跑过时间限制。

完整代码:

// date:3/06  score 30/30

import java.util.*;

public class P1004 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int SumNodes = input.nextInt();    // 节点个数
        int Noleftnode = input.nextInt(); // 非叶子节点的个数
        Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
        for (int i = 1; i <= SumNodes; i++) {
            List<Integer> chList = new ArrayList<>();
            map.put(i, chList);
        }

        for (int j = 0; j < Noleftnode; j++) {
            int ID = input.nextInt();  // 非叶子节点的编号
            int chnum = input.nextInt(); // 它有多少孩子
            for (int k = 0; k < chnum; k++) {
                int chilID = input.nextInt();
                map.get(ID).add(chilID); // 把孩子加入map中    这个和邻接表的存储思想是一致的
            }
        }


        //目标是求解每一层有多少叶子节点
        List<Integer> res = new ArrayList<>();
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(01);
        while (queue.size() != 0) {
            int nodeNum = queue.size();  // 当前层有这么多父节点
            int count = 0;

            // 处理一层
            for (int i = 0; i < nodeNum; i++) {  // 处理每一个父节点
                int parId = queue.poll();     //我拿到一个父节点
                List<Integer> chilist = map.get(parId); //然后我拿到该父节点的孩子列表
                // 判断这个孩子列表是否为空 即这个父节点是不是叶子结点
                if (chilist.size() == 0) {  // 如果孩子类表是空 则 这个父节点是一个叶子结点
                    count++;
                } else { // 如果不是空, 把它所有的孩子 都加入队列
                    for (int p = 0; p < chilist.size(); p++)
                        queue.offer(chilist.get(p));
                }
            }
            res.add(count);  // 不管是否为0 都要进行添加 因为每一层都要输出有多少叶子节点
        }
		
        // 输出最后的答案
        for (int i = 0; i < res.size(); i++) {
            System.out.print(res.get(i));
            if (i != res.size() - 1)
                System.out.print(" ");
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值