1.Wikioi 1501 二叉树的最大高度和宽度
题目描述 Description
给出一个二叉树,输出它的最大宽度和高度。
输入描述 Input Description
第一行一个整数n。
下面n行每行有两个数,对于第i行的两个数,代表编号为i的节点所连接的两个左右儿子的编号。如果没有某个儿子为空,则为0。
输出描述 Output Description
输出共一行,输出二叉树的最大宽度和高度,用一个空格隔开。
样例输入 Sample Input
5
2 3
4 5
0 0
0 0
0 0
样例输出 Sample Output
2 3
数据范围及提示 Data Size & Hint
n<16
默认第一个是根节点
以输入的次序为编号
2-N+1行指的是这个节点的左孩子和右孩子
注意:第二题有极端数据!
1
0 0
这题你们别想投机取巧了,给我老老实实搜索!
#include <stdio.h>
#define MAXN 20
int width[MAXN]; //width[i]=第i层的宽度
struct Node
{
int v;
Node *left;
Node *right;
};
void addTreeLeft(Node *root,int val) //addTreeLeft(树根指针,该节点的值) 创建新的左子树
{
Node *newnode;
newnode=new Node;
newnode->v=val;
newnode->left=NULL;
newnode->right=NULL;
root->left=newnode;
return;
}
void addTreeRight(Node *root,int val) //addTreeRight(树根指针,该节点的值) 创建新的右子树
{
Node *newnode;
newnode=new Node;
newnode->v=val;
newnode->left=NULL;
newnode->right=NULL;
root->right=newnode;
}
Node *search(Node *root,int val) //在父节点root下寻找值为val的结点
{
Node *result;
result=NULL;
if(root->v==val)
return root;
if(root->left!=NULL)
{
result=search(root->left,val);
if(result!=NULL) return result;
}
if(root->right!=NULL)
result=search(root->right,val);
return result;
}
void getWidth(Node *root,int deep) //getWidth(父节点指针,该父节点深度) 获得该父节点向下的最大宽度
{
width[deep]++;
if(root->left!=NULL) getWidth(root->left,deep+1);
if(root->right!=NULL) getWidth(root->right,deep+1);
}
int getHigh(Node *root) //获得父节点root下的最大高度
{
int lHigh=0,rHigh=0,maxHigh=0;
if(root->left!=NULL) maxHigh=getHigh(root->left);
if(root->right!=NULL) rHigh=getHigh(root->right);
if(rHigh>maxHigh) maxHigh=rHigh;
return maxHigh+1;
}
void delTree(Node *root) //delTree(父节点指针) 删除该父节点及其左右儿子节点
{
if(root->left!=NULL) delTree(root->left);
if(root->right!=NULL) delTree(root->right);
delete root;
}
int main()
{
int i,n,l,r,max=0;
Node *root,*node; //创建树的根结点、输入数据时需要用的父节点
node=new Node;
root=new Node;
root->v=1;
root->left=NULL;
root->right=NULL;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d",&l,&r);
node=search(root,i); //查找编号为i的结点
if(l>0) addTreeLeft(node,l); //左子树不为空,就给编号为i的结点接上编号为l的儿子左结点
if(r>0) addTreeRight(node,r); //右子树不为空,就给编号为i的结点接上编号为r的儿子右结点
}
getWidth(root,1); //获得各层最大宽度
int h=getHigh(root); //获得最大高度
for(i=1;i<=MAXN;i++)
if(width[i]>max)
max=width[i];
printf("%d %d\n",max,h);
delTree(root);
return 0;
}
2.Wikioi 3143 二叉树的序遍历
题目描述 Description
求一棵二叉树的前序遍历,中序遍历和后序遍历
输入描述 Input Description
第一行一个整数n,表示这棵树的节点个数。
接下来n行每行2个整数L和R。第i行的两个整数Li和Ri代表编号为i的节点的左儿子编号和右儿子编号。
输出描述 Output Description
输出一共三行,分别为前序遍历,中序遍历和后序遍历。编号之间用空格隔开。
样例输入 Sample Input
5
2 3
4 5
0 0
0 0
0 0
样例输出 Sample Output
1 2 4 5 3
4 2 5 1 3
4 5 2 3 1
数据范围及提示 Data Size & Hint
n <= 16
#include <stdio.h>
struct Node
{
int v;
Node *left;
Node *right;
};
void addTreeLeft(Node *root,int val) //创建父节点为root的值为val的左子树
{
Node *newnode;
newnode=new Node;
newnode->right=NULL;
newnode->left=NULL;
newnode->v=val;
root->left=newnode;
}
void addTreeRight(Node *root,int val) //创建父节点为root的值为val的左子树
{
Node *newnode;
newnode=new Node;
newnode->right=NULL;
newnode->left=NULL;
newnode->v=val;
root->right=newnode;
}
Node *search(Node *root,int val)
{
Node *result;
result=NULL;
if(root->v==val) return root;
if(root->left!=NULL) //先搜索左子树
{
result=search(root->left,val);
if(result!=NULL) return result;
}
if(root->right!=NULL) //再搜索右子树
result=search(root->right,val);
return result;
}
void delTree(Node *root) //删除根结点为root的子树,先删它的左右儿子子树,再删父节点
{
if(root->left!=NULL) delTree(root->left);
if(root->right!=NULL) delTree(root->right);
delete root;
}
void firstPrint(Node *root)//前序遍历打印
{
printf("%d ",root->v);
if(root->left!=NULL) firstPrint(root->left);
if(root->right!=NULL) firstPrint(root->right);
}
void midPrint(Node *root)//中序遍历打印
{
if(root->left!=NULL) midPrint(root->left);
printf("%d ",root->v);
if(root->right!=NULL) midPrint(root->right);
}
void lastPrint(Node *root)//后序遍历打印
{
if(root->left!=NULL) lastPrint(root->left);
if(root->right!=NULL) lastPrint(root->right);
printf("%d ",root->v);
}
int main()
{
int n,i,j,l,r;
Node *root,*node; //创建树的根结点、输入数据时用到的结点
root=new Node; //树根初始化
root->v=1;
root->left=NULL;
root->right=NULL;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d",&l,&r);
node=search(root,i); //找到根结点下编号为i的结点
if(l>0) addTreeLeft(node,l);
if(r>0) addTreeRight(node,r);
}
//先序、中序、后序遍历
firstPrint(root);
printf("\n");
midPrint(root);
printf("\n");
lastPrint(root);
printf("\n");
return 0;
}
下面是二叉树的几个重要模块接口:
1、二叉树的数据结构
struct Node
{
int v; //结点编号
Node *left; //左子树指针
Node *right; //右子树指针
};
2、二叉树结点的左子树创建
void addTreeLeft(Node *root,int val) //创建父节点为root的值为val的左子树
{
Node *newnode;
newnode=new Node;
newnode->right=NULL;
newnode->left=NULL;
newnode->v=val;
root->left=newnode;
}
3、二叉树结点的右子树创建
void addTreeRight(Node *root,int val) //创建父节点为root的值为val的左子树
{
Node *newnode;
newnode=new Node;
newnode->right=NULL;
newnode->left=NULL;
newnode->v=val;
root->right=newnode;
}
4、二叉树结点的查找
Node *search(Node *root,int val)
{
Node *result;
result=NULL;
if(root->v==val) return root;
if(root->left!=NULL) //先搜索左子树
{
result=search(root->left,val);
if(result!=NULL) return result;
}
if(root->right!=NULL) //再搜索右子树
result=search(root->right,val);
return result;
}
5、二叉树的删除
void delTree(Node *root) //删除根结点为root的子树,先删它的左右儿子子树,再删父节点
{
if(root->left!=NULL) delTree(root->left);
if(root->right!=NULL) delTree(root->right);
delete root;
}
6、二叉树的先序、中序、后序遍历
void firstPrint(Node *root)//前序遍历打印
{
printf("%d ",root->v);
if(root->left!=NULL) firstPrint(root->left);
if(root->right!=NULL) firstPrint(root->right);
}
void midPrint(Node *root)//中序遍历打印
{
if(root->left!=NULL) midPrint(root->left);
printf("%d ",root->v);
if(root->right!=NULL) midPrint(root->right);
}
void lastPrint(Node *root)//后序遍历打印
{
if(root->left!=NULL) lastPrint(root->left);
if(root->right!=NULL) lastPrint(root->right);
printf("%d ",root->v);
}
二叉树的内容很多,应用灵活,是各类计算机竞赛中的重要考点,需要引起我们的重视