有n个顶点的树具有以下3个特点:连通,不含圈,恰好包含n-1条边,有意思的是,具备上述3个特点中的任意两个,就可以推出第三个
11.1.1无根树转有根树
分析:
邻接矩阵占用的空间很大,用vector数组即可。由于n个结点的树,只有n-1条边,vector数组实际占用的空间与n成正比
vector<int>G[maxn];
void read_tree(){
int u,v;
scanf("%d",&n);
for(int i=0;i<n-1;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
}
转化过程如下:
void dfs(int u,int fa){ //递归转化以u为根的子树,u的父节点fa
int d=G[u].size(); //结点u的相邻点个数
for(int i=0;i<d;i++){
int v=G[u][i]; //结点u的第i个相邻点V
if(v!=fa)
dfs(v,p[v]=u); //把v的父结点设为u,然后递归
}
}
主程序设置p[root]=-1(表示根结点的父结点不存在),然后调用dfs(root,-1)即可。初学者最容易犯的错误之一就是忘记判断v是否和父结点相等
11.1.2表达式树
二叉树是表达式处理的常用工具
const int maxn=1000;
int lch[maxn],rch[maxn];
char op[maxn];
int nc=0;
int build_tree(char* s,int x,int y){
int i,c1=-1,c2=-1,p=0;
int u;
if(y-x==1){ //仅一个字符,建立单独结点
u=++nc;
lch[u]=rch[u]=0;
op[u]=s[x];
return u;
}
for(i=x;i<y;i++){
switch(s[i]){
case '(': p++; break;
case ')': p--; break;
case '+': case '-': if(!p) c1=i; break;
case '*': case '/': if(!p) c2=i; break;
}
}
if(c1<0) c1=c2; //找不到括号外的加减法,就要乘除号
if(c1<0) return build_tree(s,x+1,y-1); //整个表达式被一对括号括起来
u=++nc;
lch[u]=build_tree(s,x,c1);
rch[u]=build_tree(s,c1+1,y);
op[u]=s[c1];
return u;
}