7-31 笛卡尔树(25分)(题目分析+简单算法+详解+思路)

一:题目

7-31 笛卡尔树 (25 分)
笛卡尔树是一种特殊的二叉树,其结点包含两个关键字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

二:题目分析+思路

分析题意和示例:
每一行代表这个结点的序号(即第几行为第几个结点)
拿示例一来说:(其实也就是 该结点 该结点的左孩子,该结点的右孩子)
6
(0) 8 27 5 1
(1) 9 40 -1 -1
(2) 10 20 0 3
(3) 12 21 -1 4
(4) 15 22 -1 -1
(5) 5 35 -1 -1

思路: 

 用 两个map<int,int> 进行 存前两行的数据 其中 第一个int为行号,第二个int
 为每行的数据,然后单独处理后两行进行建树,建完树后中序输出,然后通过map找到对应的
 键值是否为升序,这是判读K1的条件是否成立;
 笛卡尔树的第二个条件是  该树的除叶节点外,其余结点的值都比左右孩子的值大 ,这个既然树已经建好了
 那就用递归做。

补充:其中建树的算法还很炫!代码中也有解释。

三:如果map容器的用法和vector容器的算法不熟悉 下方链接学习下哈

map容器的用法
vector容器的用法

四:上码

/**
	分析题意和示例:
	 每一行代表这个结点的序号(即第几行为第几个结点)
	 拿示例一来说:(其实也就是 该结点  该结点的左孩子,该结点的右孩子) 
	 		6
	(0)	8 27 5 1
	(1)	9 40 -1 -1
	(2)	10 20 0 3
	(3)	12 21 -1 4
	(4)	15 22 -1 -1
	(5)	5 35 -1 -1 
	 
	思路: 
	
	 先建树,用 两个map<int,int> 进行 存前两行的数据 其中 第一个int为 行号第二个int
	 为每行的数据,然后单独处理后两行进行建树,建完树后中序输出,然后通过map找到对应的
	 键值是否为升序,
	 是笛卡尔树的第二个条件是  该树的除叶节点外,其余结点的值都比左右孩子的值大 
*/ 

#include<bits/stdc++.h>
using namespace std;

typedef struct TNode* ptrTree;
typedef struct TNode{
	int data;
	ptrTree left;
	ptrTree right;
}tnode;

int cnt;//记录递归次数 
vector<int>v; //存中序遍历的序号 
map<int,int>m1,m2;//存前两行的数据 
int flag2 = 0;//用于判断K2 
 
ptrTree createTree(int number[1000][2],int x){
	
	if(x == -1)
	return NULL;
	cnt++;
	
	ptrTree BT = (ptrTree)malloc(sizeof(struct TNode));
	BT->left = NULL;
	BT->right = NULL;
	BT->data = x;
//	cout << BT->data << endl;
	
	BT->left = createTree(number,number[x][0]);
	BT->right = createTree(number,number[x][1]);
	 
	return BT; 
}

//中序遍历
void inorder(ptrTree BT){
	if( BT ){
		inorder(BT->left);
		int temp = BT->data;
		v.push_back(temp);
		inorder(BT->right); 
	}
	
} 

//是笛卡尔树的第二个判断条件
void judgement(ptrTree BT){
	if( BT->left != NULL ){
		
		if(m2[BT->data] > m2[BT->left->data]){
			  flag2 = 1;
			  return ;
		}
		
		judgement(BT->left);
	}
	
	if( BT->right != NULL ){
		
		if(m2[BT->data] > m2[BT->right->data]){
			flag2 = 1;
			return ;	
		}
		
		judgement(BT->right);
	}
	
	
	
} 

int main(){
	
	int N,flag1 = 0;
	int array[1000][2];//定义二维数组存储后两行的数据
	int m;//记录根节点用的 
	
	cin >> N;
	
	for( int i = 0; i < N; i++ )
	{
		int a,b,c,d;
		cin >> a >> b >> c >> d;
		
		m1[i] = a; m2[i] = b;//存储前两行数据
		array[i][0] = c;  array[i][1] = d;//存储后两行数据 
		 			
	} 
	 
	for( int i = 0; i < N;  i++)
	{
		//建树
		cnt = 0;
		ptrTree BT; 
		BT= createTree(array,i); //这种建树方法 其实指定根节点最好 但如果没有的话
		 						//那就挨个进行建树 如果其递归次数达到结点数目,那么就建树正确 
		if(cnt == N){
		 inorder(BT);//将中序遍历的顺序存入 vector中 
       	 judgement(BT);//条件K2 
		 break;
		}
	}
	
	if( flag2 == 1)
	cout << "NO"; 
	else{
		for(int i = 0; i < v.size()-1; i++)
		{
			if( m1[v[i]] > m1[v[i+1]])
			{
				cout << "NO";
				flag1 = 1;
				break;
			}			
		}
	}
	if(flag1 == 0 && flag2 == 0 )
	cout << "YES";
	
} 

 //测试测试点三  即K2的判断
//6
//8 27 5 1
//9 25 -1 -1
//10 20 0 3
//12 21 -1 4
//15 22 -1 -1
//5 35 -1 -1

在这里插入图片描述

四:总结

我在分析题意时 以为 K2的判断条件为 只要根节点的关键值最小就OK,其实不然应该是所有非叶结点的值都大于其左右孩子,这样导致测试点三一直过不去,然后我就重新分析题意,发现自己的逻辑错误,然后就找样例就行验证自己猜想,结果验证正确。我想说的是啥呢,就是在做题当中即便有一个点不过,也不要放弃,继续死磕,回归题目是根本,重新梳理逻辑。加油BOY!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天向上的菜鸡杰!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值