树的一些基础东西
来自Wikipedia上对树的理解:
在图论中,树(英语:Tree)是一种无向图(undirected graph),其中任意两个顶点间存在唯一一条路径。或者说,只要没有回路的连通图就是树。森林是指互相不交并树的集合。树图广泛应用于计算机科学的数据结构中,比如二叉查找树,堆,Trie树以及数据压缩中的霍夫曼树等等。
树的基础知识:
1、时间戳:
按照dfs的过程,将每个节点第一次被访问的顺序(v[x]被标记为1时),依次给这n个节点标记1~n的数字即该节点的时间戳。
代码:
1 void dfs(int x){ 2 v[x]=1;dfn[x]=++cnt; //dfn时间戳,cnt初始为0 3 for(int i=head[x];i;i=next[i]){ 4 int y=ver[i]; 5 if(v[y])continue; 6 dfs(y); 7 } 8 }
2、树的dfs序
第一次访问到某个节点时,记录其一次编号,回溯时再记录一次它的编号,最后产生2n的节点序列就是树的dfs序。
性质:某节点x从第一次被标记在节点序列中到第二次被标记之间的节点序列就是以x为根节点的子树的dfs序
代码:
1 void dfs(int x){ 2 a[++m]=x; //a数组存储dfs序 3 v[x]=1; //记录点是否被访问过 4 for(int i=head[x];i;i=next[i]){ 5 int y=ver[i]; 6 if(v[y])continue; 7 dfs(y); 8 } 9 a[++m]=x; 10 }
3、树的深度
树中各个节点的深度是自上而下的统计信息,其中根节点深度为0,其它节点深度即到根节点的层数。dfs遍历往下的子节点深度依次+1,即若当前所在节点x的深度为dep[x],则它的子节点y的深度为dep[y]=dep[x]+1;
dfs实现代码:
1 void dfs(int x){ 2 v[x]=1; 3 for(int i=head[x];i;i=next[i]){ 4 int y=ver[i]; 5 if(v[y])continue; 6 d[y]=d[x]+1; //父节点向子节点更新深度 7 dfs(y); 8 } 9 }
bfs实现代码:
下面的bfs实现代码若在树中则d[x]是x在树中深度,若对于一张图的话,则d[x]为x的层次数(从1到x大的最少经过点数)
1 void bfs(){ 2 memset(d,0,sizeof(d)); 3 queue<int>q; 4 q.push(1);d[1]=1; 5 while(!q.empty()){ 6 int x=q.front();q.pop(); 7 for(int i=head[x];i;i=next[i]){ 8 int y=ver[i]; 9 if(d[y])continue; 10 d[y]=d[x]+1; 11 q.push(y); 12 } 13 } 14 }
4、树的子树大小和重心
树的子树大小是自下而上统计的信息,子树大小即以某个节点x为根节点的子树的节点个数,一般用size[x]表示。容易想到,若x的子节点为:y1、y2……yn,则size[x]=size[y1]+size[y2]+…+size[yn];
树的重心。指的是对于一个节点x,从树中删去它,产生的若干个不想连的部分中节点数最多的一颗树的节点数size记为maxn,令maxn取最小值的节点x即一颗树的重心。
代码:
void dfs(int x){ v[x]=1;size[x]=1; //size存储子树大小 int max_part=0; //删除x节点后最大子树的大小 for(int i=head[x];i;i=next[i]){ int y=ver[i]; if(v[y])continue; dfs(y); size[x]+=size[y]; max_part=max(max_part,size[y]); } max_part=max(max_part,n-size[x]); //n为整棵子树节点总数 if(max_part<ans){ans=max_part;pos=x;} //ans记录重心对应的max_part,pos记录重心 }
5、图的连通块的个数和划分
dfs可以求出森林(即多棵不连通的树)中树的个数,并将节点划分到每棵树中。思路就是不停对没有划分的节点x进行dfs遍历,就会访问所有与x连通的点并对它们划分,直到所有点均被划分为止。
代码:
1 void dfs(int x){ 2 v[x]=cnt; 3 for(int i=head[x];i;i=next[i]){ 4 int y=ver[i]; 5 if(v[y])continue; 6 dfs(y); 7 } 8 } 9 int main() 10 { 11 for(int i=1;i<=n;i++) 12 if(!v[i]){cnt++,dfs(i);} //cnt即连通块个数 13 }