树的表示 | Tree | C/C++实现

问题描述

请编写一个程序,输出给定有根树T中各节点u的信息,信息内容如下:

u的结点编号
u的结点种类(根、内部节点、叶)
u的父节点编号
u的子结点列表
u的深度

这里我们设给定树拥有n个结点,编号分别为0至n - 1。

输入: 第1行输入结点的个数n。接下来n行按照下述格式输入各结点的信息,每个结点占一行。
id k c1 c2 … ck
id为结点的编号,k为度。c1 c2 … ck为第1个子结点到第k个子结点的编号。
输出: 请按下述格式输出结点的信息。结点信息按编号升序排列。
node id: parent = p, depth = d, type, [c1, …, ck]
p代表父节点的编号。不存在父节点时输出-1。d表示结点的深度。type表示结点的类型,从roor(根)、internal node(内部结点)、leaf(叶)三个字符串中选择其一。
c1…ck是子结点列表。这里我们将给定树视为有序树,请按照输入的顺序输出。相邻信息用逗号和空格隔开。

限制:
1 ≤ n ≤ 100000
结点的深度不超过20。

输入示例

13
0 3 1 4 10
1 2 2 3
2 0
3 0
4 3 5 6 7
5 0
6 0
7 2 8 9
8 0
9 0
10 2 11 12
11 0
12 0

输出示例

node 0: parent = -1, depth = 0, root, [1, 4, 10]
node 1: parent = 0, depth = 1, internal node, [2, 3]
node 2: parent = 1, depth = 2, leaf, []
node 3: parent = 1, depth = 2, leaf, []
node 4: parent = 0, depth = 1, internal node, [5, 6, 7]
node 5: parent = 4, depth = 2, leaf, []
node 6: parent = 4, depth = 2, leaf, []
node 7: parent = 4, depth = 2, internal node, [8, 9]
node 8: parent = 7, depth = 3, leaf, []
node 9: parent = 7, depth = 3, leaf, []
node 10: parent = 0, depth = 1, internal node, [11, 12]
node 11: parent = 10, depth = 2, leaf, []
node 12: parent = 10, depth = 2, leaf, []

讲解

首先我们要考虑如何存储输入的有根树。本题中,树在输入完成后结点数不再变化,所以可以利用左子右兄弟表示法(left-child right-sibling representation)来表示树。左子右兄弟表示法中的各节点具有以下信息。

结点u的父结点
结点u的最左侧子结点
结点u右侧紧邻的兄弟结点

左子右兄弟表示法的实现

struct Node{ int parent, left, right; };
struct Node T[MAX];

//或者

int parent[MAX], left[MAX], right[MAX];

引用u.parent即可知道各结点u的父结点。不存在父结点的就是根。另外,不存在u.left的结点为叶(leaf),不存在u.right的结点为最右侧子结点。为表示不存在父结点、左子结点、右兄弟结点的情况,我们将值NIL用作一个特殊的结点编号。此时要保证NIL不作为一般结点编号使用。

各结点的深度可通过下述算法求得。

getDepth(u)
	d = 0
	while T[u].right != NIL
		u = T[u]].parent
		d++
	return d

求结点u的深度时,需要从u出发逐一寻找父结点,统计u到根之间总共经过的边数。这里我们将根的父结点设为NIL(-1),从而与其他节点区分开。

另外,使用下述递归性质的算法可以更快求出树中所有结点的深度。

setDepth(u, p)
	D[u] = p
	if T[u].right != NIL
		setDepth(T[u].right, p)
	if T[u].left != NIL
		setDepth(T[u].left, p + 1)

上述算法会递归地计算右侧兄弟结点以及最左侧子结点的深度。这里的T通过左子右兄弟表示法实现,如果当前结点存在右侧兄弟结点,则不改变深度p直接进行递归调用,如果存在最左侧子结点,则先将深度加1再进行递归调用。

结点u的子结点列表从u的左侧子结点开始按顺序输出,直到当前子结点不存在右侧兄弟结点为止。

printChildren(u)
	c = T[u].left
	while c != NIL
	 	print c
	 	c = T[c].right

AC代码如下

#include<iostream>
using namespace std;
#define MAX 100005
#define NIL -1

struct Node { int p, l, r; };

Node T[MAX];
int n, D[MAX];

void print(int u){
	int i, c;
	cout<<"node "<<u<<": ";
	cout<<"parent = "<<T[u].p<<", ";
	cout<<"depth = "<<D[u]<<", ";
	
	if(T[u].p == NIL) cout<<"root, ";
	else if(T[u].l == NIL) cout<<"leaf, ";
	else cout<<"internal node, ";
	
	cout<<"[";
	
	for(i = 0, c = T[u].l; c != NIL; i++, c = T[c].r){
		if(i) cout<<", ";
		cout<<c;
	} 
	cout<<"]"<<endl;
}

//递归地求深度
int rec(int u, int p){
	D[u] = p;
	if (T[u].r != NIL) rec(T[u].r, p); //右侧兄弟设置为相同深度
	if (T[u].l != NIL) rec(T[u].l, p + 1); //最左侧子结点的深度设置为 
} 

int main(){
	int i, j, d, v, c, l, r;
	cin>>n;
	for(i = 0; i < n; i++) T[i].p = T[i].l = T[i].r = NIL;
	
	for(i = 0; i < n; i++){
		cin>>v>>d;
		for(j = 0; j < d; j++){
			cin>>c;
			if(j == 0) T[v].l = c;
			else T[l].r = c;
			l = c;
			T[c].p = v;
		}
	}
	for(i = 0; i < n; i++){
		if(T[i].p == NIL) r = i;
	}
	
	rec(r, 0);
	
	for(i = 0; i < n; i++) print(i);
	
	return 0;
} 
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值