[Wikioi 1501 & 3143]二叉树问题两则

1.Wikioi 1501 二叉树的最大高度和宽度

    给出一个二叉树,输出它的最大宽度和高度。

第一行一个整数n。

下面n行每行有两个数,对于第i行的两个数,代表编号为i的节点所连接的两个左右儿子的编号。如果没有某个儿子为空,则为0。

输出共一行,输出二叉树的最大宽度和高度,用一个空格隔开。

5

2 3

4 5

0 0

0 0

0 0

2 3

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 二叉树的序遍历

求一棵二叉树的前序遍历,中序遍历和后序遍历

第一行一个整数n,表示这棵树的节点个数。

接下来n行每行2个整数L和R。第i行的两个整数Li和Ri代表编号为i的节点的左儿子编号和右儿子编号。

输出一共三行,分别为前序遍历,中序遍历和后序遍历。编号之间用空格隔开。

5

2 3

4 5

0 0

0 0

0 0

1 2 4 5 3

4 2 5 1 3

4 5 2 3 1

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


二叉树的内容很多,应用灵活,是各类计算机竞赛中的重要考点,需要引起我们的重视

你可能感兴趣的:(数据结构,二叉树)