挑战程序设计竞赛 算法和数据结构 第8章 树
8.2 ALDS1_7_A:Rooted Trees
原书AC代码:
#include <iostream>
using namespace std;
#define MAX 100005
#define NIL -1
struct Node{int p,l,r;};
Node T[MAX];
int n,D[MAX];
void print(int u){
int i,c;
cout<<"node "<<u<<": ";
cout<<"parent = "<<T[u].p<<", ";
cout<<"depth = "<<D[u]<<", ";
if(T[u].p==NIL)cout<<"root, ";
else if(T[u].l==NIL)cout<<"leaf, ";
else cout<<"internal node, ";
cout<<"[";
for(i=0,c=T[u].l;c!=NIL;i++,c=T[c].r){
if(i)cout<<", ";
cout<<c;
}
cout<<"]"<<endl;
}
//递归地求深度
int rec(int u,int p){
D[u]=p;
if(T[u].r!=NIL)rec(T[u].r,p);//右侧兄弟设置为相同深度
if(T[u].l!=NIL)rec(T[u].l,p+1);//最左侧子节点的深度设置为自己的深度+1
}
int main(){
int i,j,d,v,c,l,r;
cin>>n;
for(i=0;i<=n;i++)T[i].p=T[i].l=T[i].r=NIL;
for(i=0;i<n;i++){
cin>>v>>d;
for(j=0;j<d;j++){
cin>>c;
if(j==0)T[v].l=c;
else T[l].r=c;
l=c;
T[c].p=v;
}
}
for(i=0;i<n;i++){
if(T[i].p==NIL)r=i;
}
rec(r,0);
for(i=0;i<n;i++)print(i);
return 0;
}
原书代码中,对初学者,比较难理解的地方是:左子右兄表示法。笔者解释如下,左子关系表示父子,右子关系表示兄弟。
原书样例,画图如下:
上图,左子右兄表示法 图如下:
左子右兄表示法 优点,个人体会是,能轻易的将一棵树 转化为 二叉树
仿照上述代码,本人编写的C语言AC代码如下:
#include <stdio.h>
#include <string.h>
struct node{
int p,l,r;
}T[100100];
int n,D[100100];//深度
void dfs(int u,int d){
D[u]=d;
if(T[u].l!=-1)dfs(T[u].l,d+1);
if(T[u].r!=-1)dfs(T[u].r,d);
}
void print(){
int i,j,c;
for(i=0;i<n;i++){
printf("node %d: parent = %d, depth = %d,",i,T[i].p,D[i]);
if(T[i].p==-1)printf(" root, ");
else if(T[i].l==-1)printf(" leaf, ");
else printf(" internal node, ");
printf("[");
for(j=0,c=T[i].l;c!=-1;j++,c=T[c].r){
if(j)printf(", ");
printf("%d",c);
}
printf("]\n");
}
}
int main(){
int r,c,u,k,i,j,p;
memset(T,-1,sizeof(T));
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d%d",&u,&k);
for(j=0;j<k;j++){
scanf("%d",&c);
if(j==0)T[u].l=c;
else T[r].r=c;
r=c;
T[c].p=u;
}
}
for(i=0;i<n;i++)
if(T[i].p==-1){
p=i;
break;
}
dfs(p,0);
print();
return 0;
}
2017-9-20 22:16
8.3 ALDS1_7_B Binary Trees
原书AC代码:
//ALDS1_7_B:Binary Trees
#include <cstdio>
#define MAX 10000
#define NIL -1
struct Node{int parent,left,right;};
Node T[MAX];
int n,D[MAX],H[MAX];
void setDepth(int u,int d){
if(u==NIL)return;
D[u]=d;
setDepth(T[u].left,d+1);
setDepth(T[u].right,d+1);
}
int setHeight(int u){
int h1=0,h2=0;
if(T[u].left!=NIL)
h1=setHeight(T[u].left)+1;
if(T[u].right!=NIL)
h2=setHeight(T[u].right)+1;
return H[u]=(h1>h2?h1:h2);
}
//返回结点u的兄弟结点
int getSibling(int u){
if(T[u].parent==NIL)return NIL;
if(T[T[u].parent].left!=u&&T[T[u].parent].left!=NIL)
return T[T[u].parent].left;
if(T[T[u].parent].right!=u&&T[T[u].parent].right!=NIL)
return T[T[u].parent].right;
return NIL;
}
void print(int u){
printf("node %d: ",u);
printf("parent = %d, ",T[u].parent);
printf("sibling = %d, ",getSibling(u));
int deg=0;
if(T[u].left!=NIL)deg++;
if(T[u].right!=NIL)deg++;
printf("degree = %d, ",deg);
printf("depth = %d, ",D[u]);
printf("height = %d, ",H[u]);
if(T[u].parent==NIL){
printf("root\n");
}else if(T[u].left==NIL&&T[u].right==NIL){
printf("leaf\n");
}else{
printf("internal node\n");
}
}
int main(){
int v,l,r,root=0;
scanf("%d",&n);
for(int i=0;i<n;i++)T[i].parent=NIL;
for(int i=0;i<n;i++){
scanf("%d %d %d",&v,&l,&r);
T[v].left=l;
T[v].right=r;
if(l!=NIL)T[l].parent=v;
if(r!=NIL)T[r].parent=v;
}
for(int i=0;i<n;i++)if(T[i].parent==NIL)root=i;
setDepth(root,0);
setHeight(root);
for(int i=0;i<n;i++)print(i);
return 0;
}
仿照上述代码,本人编写的C语言AC代码如下:
//ALDS1_7_B Binary Trees
#include <stdio.h>
#include <string.h>
struct node{
int parent,left,right;
}T[30];
int H[30],D[30];//H[]高度 D[]深度
int setHeight(int u){
int h1=0,h2=0;//2此处写成 int h1,h2;
if(T[u].left!=-1)
h1=setHeight(T[u].left)+1;
if(T[u].right!=-1)
h2=setHeight(T[u].right)+1;//1此处写成 h2=setHeight(T[u].right+1);
return H[u]=h1>h2?h1:h2;
}
void setDepth(int u,int d){
D[u]=d;
if(T[u].left!=-1)setDepth(T[u].left,d+1);
if(T[u].right!=-1)setDepth(T[u].right,d+1);
}
void print(int u){
int deg=0;
printf("node %d: parent = %d, ",u,T[u].parent);
printf("sibling = ");
if(T[u].parent==-1)printf("-1, ");//4 添上改行 就因为少了该句,调试程序1个小时
else if(T[T[u].parent].left!=-1&&T[T[u].parent].left!=u)
printf("%d, ",T[T[u].parent].left);
else if(T[T[u].parent].right!=-1&&T[T[u].parent].right!=u)
printf("%d, ",T[T[u].parent].right);
else
printf("-1, ");
if(T[u].left!=-1)deg++;
if(T[u].right!=-1)deg++;
printf("degree = %d, ",deg);
printf("depth = %d, ",D[u]);
printf("height = %d, ",H[u]);
if(T[u].parent==-1)printf("root\n");
else if(T[u].left==-1&&T[u].right==-1)printf("leaf\n");
else printf("internal node\n");
}
int main(){
int n,i,root=0,v,l,r;
memset(T,-1,sizeof(T));
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d%d%d",&v,&l,&r);
if(l!=-1){T[v].left=l,T[l].parent=v;}
if(r!=-1){T[v].right=r,T[r].parent=v;}
}
for(i=0;i<n;i++)
if(T[i].parent==-1){
root=i;
break;
}
setHeight(root);
setDepth(root,0);
for(i=0;i<n;i++)
print(i);
return 0;
}
原书程序问题,数组开得太大,题目中约束0<=n<=25。
2017-9-26 23:08 AC该问题
8.4 ALDS1_7_C:Tree Walk
原书AC代码:
//ALDS1_7_C:Tree Walk
#include <stdio.h>
#define MAX 10000
#define NIL -1
struct Node{int p,l,r;};
struct Node T[MAX];
int n;
/*前序遍历*/
void preParse(int u){
if(u==NIL)return;
printf(" %d",u);
preParse(T[u].l);
preParse(T[u].r);
}
/*中序遍历*/
void inParse(int u){
if(u==NIL)return;
inParse(T[u].l);
printf(" %d",u);
inParse(T[u].r);
}
/*后序遍历*/
void postParse(int u){
if(u==NIL)return;
postParse(T[u].l);
postParse(T[u].r);
printf(" %d",u);
}
int main(){
int i,v,l,r,root;
scanf("%d",&n);
for(i=0;i<n;i++){
T[i].p=NIL;
}
for(i=0;i<n;i++){
scanf("%d %d %d",&v,&l,&r);
T[v].l=l;
T[v].r=r;
if(l!=NIL)T[l].p=v;
if(r!=NIL)T[r].p=v;
}
for(i=0;i<n;i++)if(T[i].p==NIL)root=i;
printf("Preorder\n");
preParse(root);
printf("\n");
printf("Inorder\n");
inParse(root);
printf("\n");
printf("Postorder\n");
postParse(root);
printf("\n");
return 0;
}
仿照上述代码,本人编写的C语言AC代码如下:
//ALDS1_7_C:Tree Walk
#include <stdio.h>
#include <string.h>
struct node{
int parent,left,right;
}T[30];
void Preorder(int u){//先序遍历
if(u==-1)return;//u==-1叶子节点的下一个节点
printf(" %d",u);//根
Preorder(T[u].left);//左
Preorder(T[u].right);//右
}
void Inorder(int u){//中序遍历
if(u==-1)return;
Inorder(T[u].left);//左
printf(" %d",u);//根
Inorder(T[u].right);//右
}
void Postorder(int u){//后序遍历
if(u==-1)return;
Postorder(T[u].left);//左
Postorder(T[u].right);//右
printf(" %d",u); //根
}
int main(){
int n,i,root=0,v,l,r;
memset(T,-1,sizeof(T));
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d%d%d",&v,&l,&r);
if(l!=-1){
T[v].left=l,T[l].parent=v;
}
if(r!=-1){
T[v].right=r,T[r].parent=r;
}
}
for(i=0;i<n;i++)
if(T[i].parent==-1){
root=i;
break;
}
printf("Preorder\n");
Preorder(root);
printf("\n");
printf("Inorder\n");
Inorder(root);
printf("\n");
printf("Postorder\n");
Postorder(root);
printf("\n");
return 0;
}
收获,学习了一种二叉树的输入输出方式。
2017-9-27
8.5 ALDS1_7_D:Reconstruction of the Tree
上在线测评网站,发现该题名字应为:ALDS1_7_D:Reconstruction of a Tree
提交,程序一直处于:Judging状态,估计AOJ此题处于修改,或删除状态。
原书样例通过的代码:
//ALDS1_7_D:Reconstruction of the Tree
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
int n,pos;
vector<int> pre,in,post;
void rec(int l,int r){
if(l>=r)return;
int root=pre[pos++];
int m = distance(in.begin(),find(in.begin(),in.end(),root));
rec(l,m);
rec(m+1,r);
post.push_back(root);
}
void solve(){
pos = 0;
rec(0,pre.size());
for(int i=0;i<n;i++){
if(i)cout<<" ";
cout<<post[i];
}
cout<<endl;
}
int main(){
int k;
cin>>n;
for(int i=0;i<n;i++){
cin>>k;
pre.push_back(k);
}
for(int i=0;i<n;i++){
cin>>k;
in.push_back(k);
}
solve();
return 0;
}
仿照上述代码,本人编写的C语言样例通过代码如下:
//ALDS1_7_D:Reconstruction of the Tree
#include <stdio.h>
int pre[110],in[110],post[110],pos=1,k=1,n;
void rec(int left,int right){//用中序,先序构建后序
int c,i;//根
if(left>right)return;
c=pre[pos++];
for(i=1;i<=n;i++)
if(in[i]==c){
break;
}
rec(left,i-1);
rec(i+1,right);
post[k++]=c;
}
int main(){
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&pre[i]);
for(i=1;i<=n;i++)
scanf("%d",&in[i]);
rec(1,n);
for(i=1;i<=n;i++)
printf("%d ",post[i]);
return 0;
}
通过该题,深刻认识到,先,中,后 序的核心在于 根,根是三种转换的桥梁。
2017-9-27 19:08样例通过。
2017-9-27 19:09完成该章内容学习,二叉树知识得到巩固,递归技能得到加强,明白了根是二叉树的核心,掌握了树的左子右兄表示法。