本专栏持续输出数据结构题目集,欢迎订阅。
题目
笛卡尔树是一种特殊的二叉树,其结点包含两个关键字 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
代码
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
// 节点结构
typedef struct Node {
int k1; // 用于二叉查找树的关键字
int k2; // 用于最小堆的关键字
int left; // 左孩子索引
int right; // 右孩子索引
} Node;
Node nodes[1000]; // 存储所有节点
int n; // 节点总数
// 检查以index为根的子树是否满足最小堆性质(k2)
int isMinHeap(int index) {
if (index == -1) return 1; // 空节点视为满足条件
// 当前节点的k2值
int currentK2 = nodes[index].k2;
// 检查左子树
int left = nodes[index].left;
if (left != -1) {
if (nodes[left].k2 <= currentK2) return 0; // 子节点k2不大于当前节点,不满足最小堆
if (!isMinHeap(left)) return 0; // 递归检查左子树
}
// 检查右子树
int right = nodes[index].right;
if (right != -1) {
if (nodes[right].k2 <= currentK2) return 0; // 子节点k2不大于当前节点,不满足最小堆
if (!isMinHeap(right)) return 0; // 递归检查右子树
}
return 1;
}
// 检查以index为根的子树是否满足二叉查找树性质(k1)
// 需要传入当前子树的k1值范围 [minK1, maxK1]
int isBST(int index, int minK1, int maxK1) {
if (index == -1) return 1; // 空节点视为满足条件
int currentK1 = nodes[index].k1;
// 检查当前节点的k1是否在有效范围内
if (currentK1 <= minK1 || currentK1 >= maxK1) {
return 0;
}
// 检查左子树:左子树所有节点的k1必须小于当前节点的k1
int left = nodes[index].left;
if (left != -1 && !isBST(left, minK1, currentK1)) {
return 0;
}
// 检查右子树:右子树所有节点的k1必须大于当前节点的k1
int right = nodes[index].right;
if (right != -1 && !isBST(right, currentK1, maxK1)) {
return 0;
}
return 1;
}
int main() {
scanf("%d", &n);
// 读取所有节点信息
for (int i = 0; i < n; i++) {
scanf("%d %d %d %d",
&nodes[i].k1,
&nodes[i].k2,
&nodes[i].left,
&nodes[i].right);
}
// 特殊情况:空树
if (n == 0) {
printf("YES\n");
return 0;
}
// 寻找根节点(没有父节点的节点)
int root = -1;
int hasParent[1000] = {0}; // 标记节点是否有父节点
for (int i = 0; i < n; i++) {
if (nodes[i].left != -1) {
hasParent[nodes[i].left] = 1;
}
if (nodes[i].right != -1) {
hasParent[nodes[i].right] = 1;
}
}
// 找到根节点(没有父节点的节点)
for (int i = 0; i < n; i++) {
if (!hasParent[i]) {
root = i;
break;
}
}
// 检查是否同时满足二叉查找树和最小堆性质
int bstValid = isBST(root, INT_MIN, INT_MAX);
int heapValid = isMinHeap(root);
if (bstValid && heapValid) {
printf("YES\n");
} else {
printf("NO\n");
}
return 0;
}
2578

被折叠的 条评论
为什么被折叠?



