7-31 笛卡尔树 (25 分)c语言

笛卡尔树是一种特殊的二叉树,其结点包含两个关键字K1和K2。首先笛卡尔树是关于K1的二叉搜索树,即结点左子树的所有K1值都比该结点的K1值小,右子树则大。其次所有结点的K2关键字满足优先队列(不妨设为最小堆)的顺序要求,即该结点的K2值比其子树中所有结点的K2值小。给定一棵二叉树,请判断该树是否笛卡尔树。

输入格式:

输入首先给出正整数N(≤1000),为树中结点的个数。随后N行,每行给出一个结点的信息,包括:结点的K1值、K2值、左孩子结点编号、右孩子结点编号。设结点从0~(N-1)顺序编号。若某结点不存在孩子结点,则该位置给出−1。

输出格式:

输出YES如果该树是一棵笛卡尔树;否则输出NO

输入样例1:

6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 21 -1 4
15 22 -1 -1
5 35 -1 -1

输出样例1:

YES

输入样例2:

6
8 27 5 1
9 40 -1 -1
10 20 0 3
12 11 -1 4
15 22 -1 -1
50 35 -1 -1

输出样例2:

NO

思路:

先把这颗树建立起来:使用二维数组dist[][]存储各个结点k1,k2的信息;使用二维数组child[][]记录左右儿子;使用一维数组dad[]记录儿子;初始化为-1

通过根节点递归进行访问各个节点,判断是否YES的条件,我用了比较笨的办法,把所有情况罗列出来;看左边所有k1数据是否比右边所有k1数据小,左边k1数据是否比父节点k1小,右边k1数据是否比父节点k1大;根节点数据k2是否比所有子结点k2小。

#include<stdio.h>
#define MAXSIZE 1010
int dist[MAXSIZE][2];//0是k1值 1是k2值 
int dad[MAXSIZE];
int child[MAXSIZE][2]; //0是左孩子 1是右孩子
int vis[MAXSIZE];
int FLAG=1;
void find(int parent,int lchild,int rchild)
{
	if(parent==-1)return;//递归出口
	if(vis[parent]==0)//vis记录下走过的足迹,走过就不用在再了
	{
		vis[parent]=1;
		if(lchild!=-1)
		{
        //左儿k1是否比父k1大?左儿k2是否比父k2小?
		if(dist[parent][0]<dist[lchild][0]||dist[parent][1]>dist[lchild][1])
		{
			FLAG=0;
			return;
		}	
		}
		if(rchild!=-1)
		{
		if(dist[parent][0]>dist[rchild][0]||dist[parent][1]>dist[rchild][1])
	    {
	    	FLAG=0;
	    	return;
		}
		}		
	}
	int lparent=lchild;
	int rparent=rchild;
	int llchild=child[lparent][0];
	int lrchild=child[lparent][1];
	int rlchild=child[rparent][0];
	int rrchild=child[rparent][1];
	if(llchild!=-1&&rlchild!=-1)//左边是否比右边都要小,总共2*2四种情况
	if(dist[llchild][0]>dist[rlchild][0])
	{
		FLAG=0;return;
	}
	if(llchild!=-1&&rrchild!=-1)
	if(dist[llchild][0]>dist[rrchild][0])
	{
		FLAG=0;return;
	}
	if(lrchild!=-1&&rlchild!=-1)
	if(dist[lrchild][0]>dist[rlchild][0])
	{
		FLAG=0;return;
	}
	if(lrchild!=-1&&rrchild!=-1)
	if(dist[lrchild][0]>dist[rrchild][0])
	{
		FLAG=0;return;
	}		
	
	find(lparent,llchild,lrchild);//递归访问
	find(rparent,rlchild,rrchild);
	return;
}
int main()
{
	int n,i,j,root=0;
	scanf("%d",&n);
	for(i=0;i<n;i++)//初始化所有数据为-1
	{
		child[i][0]=child[i][1]=-1;
		dad[i]=-1;
		dist[i][0]=-1;
	}//建立父子关系
	for(i=0;i<n;i++)
	{
		scanf("%d%d%d%d",&dist[i][0],&dist[i][1],&child[i][0],&child[i][1]);
		if(child[i][0]!=-1)dad[child[i][0]]=i;
		if(child[i][1]!=-1)dad[child[i][1]]=i;		
	}
	for(i=0;i<n;i++)if(dad[i]==-1)root=i;
	int lchild=child[root][0],rchild=child[root][1];	
	find(root,lchild,rchild);
	if(FLAG==1)
	printf("YES\n");
	else if(FLAG==0)
	printf("NO\n"); 
	return 0;
 } 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值