vlambda博客
学习文章列表

树和二叉树的定义、遍历

一、树的定义

 

顾名思义,树是一种把数据组织成“倒置的树”状的结构。从上往下看,有一个总的起源,称为树的(如上图的A);

每个数据元素可能有多个后继,如上图A有三个后继,B有两个后继,K0个后继。每个后继称为对应节点的儿子节点。如A有三个儿子BCD;注意,不特别声明,儿子节点都是没有顺序之分的。下面两棵树本质是一样的树。

 

儿子节点没有顺序之分的称为无序树,有顺序之分的称为有序树

对应的,A称为BCD父亲,每条边连接的是一对父子关系AB是一对父子节点。

没有后继的节点称为叶子节点;

根和叶子节点之外的称为分支节点

具有相同父亲的节点互称为兄弟节点

树的定义是递归的,某个子节点往下的所有节点称为他的子树,例如以A为根的树(A往下的所有节点)有三棵子树,分别是以B为根的子树、以C为根的子树,以D为根的子树。

子树上的所有节点都称为他的子孙节点。例如EFKL都称为B得到子孙节点。

某节点往上直到根为止都称为他的祖先节点。例如ADH都是H的祖先节点。

两个节点的共有的祖先称为公共祖先。例如BAKF的公共祖先,其中B点距离KF最近,把B点称为他们的最近公共祖先

两个节点的路径:一个节点向上走到最近公共祖先,再走到另外一个节点,沿途经过的点和边称为二者的路径。树中任意两点之间都有唯一的一条路径。

树的:每个节点的儿子的个数称为节点的度,最大的节点的度称为树的度。

树的深度:树中节点是分层的,根位于第一层,节点所处的层数称为该节点的深度,节点的最大深度称为树的深度。

树中节点每个节点不是平等的。树中有根,有叶子,有父亲,有儿子。如果打破这种层次关系,认为每个节点平等的,把他称为树图

 

树图不是树,所有节点都是平等,没有根,也没有叶子节点。树图中一条边连接的两个点互称为邻接点。每个节点的邻接点个数称为该点的度,所以树中节点的度一般比树图中点的度小1(根节点除外)。

树图的性质:

1)n个点被n-1条边联通起来。

2)任意两点之间都有唯一的一条路径。

3)把任意一个点当做根开始划分层次都得到一棵树,所以树图和树在处理问题时有时候被认为是等同的。

二、树的表示

1、父亲表示法(并查集)

2、树形表示法(向量实现、邻接表实现)

   树的向量实现:

vector <int> tree[101];

3、长子兄弟法(二叉树概念)、树转二叉树

树转二叉树核心代码:

for(int i=1;i<n;i++)

{

 int a,b;

 cin>>a>>b;//ab的父亲

 if(z[a]==0)

{

 z[a]=b; tree[a].l=b;

}

else

{

 tree[z[a]].r=b; z[a]=b;

}

}

三、树的遍历(题号:020000

1、先根遍历

void dfs1(int num)

{

  cout << num << endl;

for(int i = 0; i < tree[num].size(); i ++) //如果num是叶子节点,本循环不执行

dfs1(tree[num][i]);

}

2、后根遍历

3、长子兄弟法(二叉树)的遍历(题号0200002

1)、二叉树的表示:

struct node{ int l,r; };

node tree[100005];

2)、前序遍历(遍历结果与先根遍历相同)

void xian(int x)

{

cout << x << endl;

if(tree[x].l) xian(tree[x].l); //如果存在左儿子,递归处理左边

if(tree[x].r) xian(tree[x].r);

}

3)、中序遍历(遍历结果与树的后根遍历相同)

4)、后序遍历

5)、中序与前序推后序(题号:020016

代码:

string fr, md; //fr是前序字符串,md是中序字符串

void go(int ll, int lr, int ml, int mr)

{

 int pos = md.find(fr[ll]); //在中序中找根的下标位置

if (pos > ml) go(ll + 1, ll + pos - ml, ml, pos - 1);

 if (pos < mr) go(ll + pos - ml + 1, lr, pos + 1, mr);

cout << fr[ll];

 }