本题完成最小堆的建立
将一系列给定数字插入一个初始为空的小顶堆H[]。随后对任意给定的下标i,打印从H[i]到根结点的路径。
输入格式:
每组测试第1行包含2个正整数N和M(≤1000),分别是插入元素的个数、以及需要打印的路径条数。下一行给出区间[-10000, 10000]内的N个要被插入一个初始为空的小顶堆的整数。最后一行给出M个下标。
输出格式:
对输入中给出的每个下标i,在一行中输出从H[i]到根结点的路径上的数据。数字间以1个空格分隔,行末不得有多余空格。
输入样例:
5 3
46 23 26 24 10
5 4 3
题目的最小对堆建立后变成上述的样子,因此查询5,返回的路径是24(下标为5),23,10
输出样例:
24 23 10
46 23 10
26 10
其中关键点在于:
- 最小堆使用数组完成比较好,从尾部插入,如果其父节点比插入的元素大,父节点元素下移动
- 一个下标 i 的 i/2 一定是其父节点的下标,这样从最下端插入元素时可以很快得跟父节点进行比较
- 堆的0下标元素需要设置一个岗哨元素,取堆元素可能取到的最小值,这样不会数组越界
代码如下:
#include<stdio.h>
#include<stdlib.h>
#define maxsize 1001
#define minelement -10001
int heap[maxsize], size;
void makeheap(int n);//建立最小堆
void print(int i);//打印i节点的位置的路径
void insert(int v);//向堆中插入元素
int main()
{
int n, m;
scanf("%d %d", &n, &m);
makeheap(n);
while (m)
{
int tep;
scanf("%d", &tep);
print(tep);
m--;
}
return 0;
}
void makeheap(int n)
{
size = 0;
heap[0] = minelement;//在零下标的位置处设置岗哨元素,保证最小的插在1的位置
int i;
for (i = 0; i < n; i++)
{
int tep;
scanf("%d", &tep);
insert(tep);
}
return;
}
void insert(int v)//向堆中插入元素
{
if (size == maxsize - 1)return;//如果size超过数组的最大值,不能插入
int i;
for (i = ++size; heap[i / 2] > v; i /= 2)//插入前堆的size加1,同时i从最后这个元素开始插入,如果其父节点比插入的节点小,退出循环
heap[i] = heap[i / 2];//没有退出循环表示父节点比要插入的大,因此其父节点下移动
heap[i] = v;
return;
}
void print(int i)//打印i节点的位置的路径
{
printf("%d", heap[i]);
i /= 2;
for (; i >= 1; i /= 2)
printf(" %d", heap[i]);
printf("\n");
return;
}