有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;
}