树2. List Leaves(树的遍历,队列的简单应用)

首先参考ice_camel的博客,其实现方式非常简洁便于理解

题目要求

Given a tree, you are supposed to list all the leaves in the order of top down, and left to right.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (<=10) which is the total number of nodes in the tree – and hence the nodes are numbered from 0 to N-1. Then N lines follow, each corresponds to a node, and gives the indices of the left and right children of the node. If the child does not exist, a “-” will be put at the position. Any pair of children are separated by a space.

Output Specification:

For each test case, print in one line all the leaves’ indices in the order of top down, and left to right. There must be exactly one space between any adjacent numbers, and no extra space at the end of the line.

Sample Input: 

1 - 
- - 
0 - 
2 7 
- - 
- - 
5 - 
4 6

Sample Output:

4 1 5

题目分析

题目输入序列第一列给出树的节点个数N(N<=10);节点依次编号0~N-1;第一列之后个各个序列依次表示从0到N-1节点的左右子树,存在即为子孩子的序号,不存在就用’-‘表示。 
首先,根据输入的信息建树,然后寻找根节点。寻找根节点的方法:用一个数组来标记每一个节点是否是其他节点的孩子节点,在输入中出现过得肯定不是根节点,因为输入的为节点左右孩子编号。 
然后,从根开始层次遍历,将叶子节点保存,再按格式输出即可。

C语言实现

#include <stdio.h>
#include <ctype.h>

struct Node
{
    int root;    //记录节点是否为根节点
    int left;    //左子树
    int right;   //右子树
};

int main(){
    int n;     //存储节点个数 N <= 10
    struct Node nodes[10];
    scanf("%d",&n);
    //printf("%d",n);
    for(int i = 0; i < n; i++){//初始化树节点
        nodes[i].root = 1;     //没有连接的节点都是根节点
        nodes[i].left = -1;    //没有左子树
        nodes[i].right = -1;   //没有右子树
    }
    for(int i = 0; i < n; i++){//构造树
        char ch1,ch2;
        scanf("\n%c %c",&ch1,&ch2);
        if(isdigit(ch1)){               //左子树存在,将左子树连接至该点
            nodes[i].left = ch1 - '0';  //指针指向左子树
            nodes[ch1 - '0'].root = 0;  //左子树取消根节点标记
        }
        if(isdigit(ch2)){
            nodes[i].right = ch2 - '0';
            nodes[ch2 - '0'].root = 0;
        }
    }

    int root;   //根节点序号
    for(int i = 0; i < n; i++)
        if(nodes[i].root == 1){
            root = i;
            break;
        }

    //构造完树后,层序遍历树,依次输出叶子节点;层序遍历:从根节点开始依次将左右儿子入队,直至队列为空
    int leaves = 0;   //记录输出叶节点的个数
    int queue[10];    //节点队列,只保存节点下标
    int head = 0, rear = 0;
    queue[rear++] = root;  //根节点入队
    while(rear - head){
        int node = queue[head++];  //队首节点出队

        if(nodes[node].left == -1 && nodes[node].right == -1){
            if(leaves)   //输出第一个时,不输出空格
                printf(" ");
            printf("%d",node);
            ++leaves;
        }
        if(nodes[node].left != -1)  //如果存在,左子树入队
            queue[rear++] = nodes[node].left;
        if(nodes[node].right != -1) //如果存在,右子树入队
            queue[rear++] = nodes[node].right;
    }
    return 0;
}

然后自己在此基础上整理了一下,代码如下
#include "stdafx.h"
#include "iostream"
using namespace std;
typedef int ElementType;
#define MAX 10
typedef struct Node *Tree;
struct Node{
	ElementType Root;
	int left;
	int right;
}nodes[MAX];
int BuildAndFind(Tree tree)
{
	int N,i,flag[MAX];
	char left,right;
	cin>>N;
	for(i=0;i<N;i++)
	{
		nodes[i].Root=1;
		nodes[i].left=-1;
		nodes[i].right=-1;
	}
	for(i=0;i<N;i++)
	{
		cin>>left>>right;
		if(left!='-')
		{
			nodes[i].left=left-'0';
			nodes[left-'0'].Root=0;
		}
		if(right!='-')
		{
			nodes[i].right=right-'0';
			nodes[right-'0'].Root=0;
		}
	}
	for(i=0;i<N;i++)
	{
		if(nodes[i].Root)
			return i;
	}

}
void FindLeaves(int root)
{
	int leave=0;
	int queue[MAX];
	int front=0,rear=0;
	queue[front++]=root;
	while(front-rear)
	{
		int node=queue[rear++];
		if(nodes[node].left==-1&&nodes[node].right==-1)
		{
			cout<<node<<"    ";
				leave++;
		}
		if(nodes[node].left!=-1)
		{
			queue[front++]=nodes[node].left;
		}
		if(nodes[node].right!=-1)
		{
			queue[front++]=nodes[node].right;
		}
	}
}
int main()
{
	int root;
	root=BuildAndFind(nodes);
	FindLeaves(root);
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值