开始树啦!
一、定义
一棵树是由n(n>0)个元素组成的有限集合,其中:
(1)每个元素称为结点(node);
(2)有一个特定的结点,称为根结点或树根(root);
(3)除根结点外,其余结点能分成m(m>=0)个互不相交的有限集合T0,T1,T2,……Tm-1。其中的每个子集又都是一棵树,这些集合称为这棵树的子树。
eg(图)
二、性质
A.树是递归定义的;
B.一棵树中至少有1个结点。
这个结点就是根结点,它没有前驱,其余每个结点都有唯一的一个前驱结点。
每个结点可以有0或多个后继结点。
因此树虽然是非线性结构,但也是有序结构。
至于前驱后继结点是哪个,还要看树的遍历方法,我们将在后面讨论;
C.一个结点的子树个数,称为这个结点的度(degree,结点1的度为3,结点3的度为0);
度为0的结点称为叶结点(树叶leaf,如结点3、5、6、8、9);
度不为0的结点称为分支结点(如结点1、2、4、7);
根以外的分支结点又称为内部结点(结点2、4、7);
树中各结点的度的最大值称为这棵树的度(这棵树的度为3)。
D.在用图形表示的树型结构中,
对两个用线段(称为树枝)连接的相关联的结点,称上端结点为下端结点的父结点,称下端结点为上端结点的子结点,称同一个父结点的多个子结点为兄弟结点。
如结点1是结点2、3、4的父结点,结点 2、3、4是结点1的子结点,它们又是兄弟结点,同时结点2又是结点5、6的父结点。
称从根结点到某个子结点所经过的所有结点为这个子结点的祖先。
如结点1、4、7是结点8的祖先。
称以某个结点为根的子树中的任一结点都是该结点的子孙。
如结点7、8、9都是结点4的子孙。
E.定义一棵树的根结点的层次(level)为0,其它结点的层次等于它的父结点层次加1。
如结点2、3、4的层次为1,结点5、6、7的层次为2,结点8、9的层次为3。
一棵树中所有的结点的层次的最大值称为树的深度(depth)。
如这棵树的深度为3。
F.对于树中任意两个不同的结点,
如果从一个结点出发,自上而下沿着树中连着结点的线段能到达另一结点,称它们之间存在着一条路径。
可用路径所经过的结点序列表示路径,路径的长度等于路径上的结点个数减1。
如上图中,结点1和结点8之间存在着一条路径,并可用(1、4、7、8)表示这条路径,该条路径的长度为3。
注意:
①不同子树上的结点之间不存在路径。
②从根结点出发,到树中的其余结点一定存在着一条路径。
G.森林(forest)是m(m>=0)棵互不相交的树的集合。
三、树的遍历
在应用树结构解决问题时,往往要求按照某种次序获得树中全部结点的信息,这种操作叫作树的遍历。
遍历的方法有多种,常用的有:
A、先序(根)遍历
先访问根结点,再从左到右按照先序思想遍历各棵子树。
原则:根——>左——>右
如上图先序遍历的结果为:125634789;
B、后序(根)遍历
先从左到右遍历各棵子树,再访问根结点。
原则:左——>右——>根
如上图后序遍历的结果为:562389741;
C、中序遍历
先遍历左孩子,然后再遍历根节点,最后遍历右孩子
原则:左——>根——>右
如上图中序遍历的结果为:526138794
D、层次遍历
按层次从小到大逐个访问,同一层次按照从左到右的次序。
原则:从上到下,从左到右
如上图层次遍历的结果为:123456789;
E、叶结点遍历
有时把所有的数据信息都存放在叶结点中,而其余结点都是用来表示数据之间的某种分支或层次关系,这种情况就 用这种方法。
原则:只询问每个叶子节点
如上图按照这个思想访问的结果为:56389;
四、题目——找树根和孩子
【问题描述】
给定一棵树,输出树的根root,孩子最多的结点max以及他的孩子
【输入格式】
第一行:n(结点数<=100),m(边数<=200)。
以下m行;每行两个结点x和y,
表示y是x的孩子(x,y<=1000)。
【输出格式】
第一行:树根:root。
第二行:孩子最多的结点max。
第三行:max的孩子。
【输入样例】
8 7
4 1
4 2
1 3
1 5
2 6
2 7
2 8
【输出样例】
4
2
6 7 8
上代码:
#include<cstdio>
using namespace std;
int tree[222],maxx=0,root,maxroot,n,m,x,y,g=0;
/*
tree[] :记录孩子所对的父亲编号
root :树的树根编号
maxx :孩子最多的结点个数
maxroot :拥有最多孩子结点的根的编号
n :结点个数(n<=100)
m :边数(m<=200)
x :父亲(<=1000)
y :孩子(<=1000)
*/
int main() {
scanf("%d %d\n",&n,&m);
for(int i=1; i<=m; i++) { //分别有m种情况(谁是谁的孩子)
scanf("%d %d\n",&x,&y);
tree[y]=x;//用tree数组存储孩子y的父亲为……
}
for(int i=1; i<=n; i++) {
if(tree[i]==0) { //如果它没有父亲,则此数为树的根
root=i;//用root记录下来
break;
}
g=0;//循环n次,寻找最大孩子数,g记录
for(int j=1; j<=n; j++) {
if(tree[j]==i) g++;
if(g>maxx) { //如果这一次的个数比maxx大,就用maxx记录下来
maxx=g;
maxroot=i;
}
}
}
printf("%d\n%d\n",root,maxroot);
for(int i=1; i<=n; i++)
if(tree[i]==maxroot)
printf("%d ",i);
return 0;
}