一、题目
将一系列给定数字顺序插入一个初始为空的小顶堆H[]。随后判断一系列相关命题是否为真。命题分下列几种:
- x is the root:x是根结点;
- x and y are siblings:x和y是兄弟结点;
- x is the parent of y:x是y的父结点;
- x is a child of y:x是y的一个子结点。
输入格式:
每组测试第1行包含2个正整数N(≤ 1000)和M(≤ 20),分别是插入元素的个数、以及需要判断的命题数。下一行给出区间[−10000,10000]内的N个要被插入一个初始为空的小顶堆的整数。之后M行,每行给出一个命题。题目保证命题中的结点键值都是存在的。
输出格式:
对输入的每个命题,如果其为真,则在一行中输出T,否则输出F。
输入样例:
5 4
46 23 26 24 10
24 is the root
26 and 23 are siblings
46 is the parent of 23
23 is a child of 10
输出样例:
F
T
F
T
二、方法1
1、思路
本题考察的是对堆的认识。
(1)知识点
① 完全二叉树
若设二叉树的深度为 h ,除第 h 层外,其它各层 (1 ~ h - 1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
例如:
一棵二叉树至多只有最下面的一层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
② 小顶堆和大顶堆
堆是一棵完全二叉树,其任何一非叶节点满足性质:
任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。
- 小顶堆:堆顶的关键字是所有关键字中最小的
- 大顶堆:堆顶的关键字是所有关键字中最大的
③ 堆的简单性质
堆的最大特点就是可以用数组来表示,不需要用指针来建立二叉树。
用数组来表示堆,只需要弄清楚三个问题:
- 给定一个父亲的下标 x,能知道其左右孩子的下标;
- 给定一个左孩子的下标 x,能知道其父亲和右兄弟的下标;
- 给定一个右孩子的下标 x,能知道其左兄弟和父亲的下标。
通过数学证明,得出一个优美的论断:
- 已知孩子的下标 x,其父亲的下标为 ( x - 1)// 2;
- 已知父亲的下标 x,其左右孩子的下标分别为
( x + 1)* 2 - 1 ,( x + 1)* 2;
④ 创建堆
void creat(int x)
{
heap[++cnt] = x;
int t = cnt;
while (t > 1 && heap[t] < heap[t / 2])
{
heap[t] = heap[t / 2];
heap[t / 2] = x;
t = t / 2;
}
heap[t] = x;
}
(2)题目的判断
① 判断命题输入
命题一: x is the root:x是根结点;
命题二: x and y are siblings:x和y是兄弟结点;
命题三: x is the parent of y:x是y的父结点;
命题四: x is a child of y:x是y的一个子结点。
主要是利用 scanf() 函数不能接收空格的特点来区分各个命题:
- 先用 scanf() 接收 x;
- 然后用 scanf() 接收一次 str,判断 str 的首字母 是否为 a,若为 a,则为命题二;
- 若不为 a,则再用 scanf() 接收一次 str,判断 str 的首字母 是否为 a,若为 a,则为命题四;
- 若不为 a,则再用 scanf() 接收一次 str,判断 str 的首字母,若为 r,则为命题一;若为 p,则为命题三。
② 判断命题真假
- x是根结点:a[x] == 1
- x和y是兄弟结点:a[x] / 2 == a[y]
- x是y的父结点:a[x] / 2 == a[y]
- x是y的一个子结点:a[y] / 2 == a[x]
(3)易错点提示
由于题目上要求数的范围为 [−10000,10000],直接处理数据会导致数组溢出,测试点3发生段错误,这是因为有负数导致的结果,只需要将所有数据+10000 即可。
2、代码
#include<stdio.h>
#define max 20010
int heap[max];
int a[max];
int n, m;
int i, j, k;
int key, cnt = 0;
int x, y;
char str[50];
void creat(int x);
int main()
{
scanf("%d %d", &n, &m);
for (i = 1; i <= n; i++)
{
scanf("%d", &key);
creat(key);
}
for (i = 1; i < max; i++)
{
a[heap[i] + 10000] = i;
}
while (m--)
{
scanf("%d ", &x);
x += 10000;
scanf("%s", str);
if (str[0] == 'a')
{
scanf("%d", &y);
y += 10000;
if (a[x] / 2 == a[y] / 2)
printf("T\n");
else
printf("F\n");
scanf("%s %s", str, str);
}
else
{
scanf("%s", str);
if (str[0] == 'a')
{
scanf("%s %s %d", str, str, &y);
y += 10000;
if (a[x] / 2 == a[y])
printf("T\n");
else
printf("F\n");
}
else
{
scanf("%s", str);
if (str[0] == 'r')
{
if (a[x] == 1)
printf("T\n");
else
printf("F\n");
}
else
{
scanf("%s %d", str, &y);
y += 10000;
if (a[y] / 2 == a[x])
printf("T\n");
else
printf("F\n");
}
}
}
}
return 0;
}
void creat(int x)
{
heap[++cnt] = x;
int t = cnt;
while (t > 1 && heap[t] < heap[t / 2])
{
heap[t] = heap[t / 2];
heap[t / 2] = x;
t = t / 2;
}
heap[t] = x;
}