将一系列给定数字插入一个初始为空的小顶堆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
输出样例:
24 23 10
46 23 10
26 10
思路如下:
陈越姥姥说这道题很简单,按理说是挺简单的,就是我对细节上面没有理解到位,导致费了些波折,最后还是新建了个VS空项目,调试了下才找出问题所在。原因是哨兵处的值设置为了10001,最小堆的情况下,哨兵处的值应当为最小值而不是最大值,照搬最大堆的插入就出问题了,应当设置为-10001,然后就AC了。
堆的存储,逻辑和物理存储都为数组的形式。首先创建一空的最小堆,输入一个元素插入一个元素,将新插入元素放在数组最末端,依次和父结点比较,若是父结点较大,则将父结点的值赋给子节点,依次进行,直到碰到哨兵,说明插入值为堆中的最小值,应当为根节点。
创建好最小堆之后,查找路径,要求的是打印从H[i]到根结点的路径,就是倒序路径,自然下标除以二就得到父结点的下标值,将值取出打印,重复操作直至下标i为1为止。
还有一种就是简单的数组存储,原理也相同,只是代码要简化许多,也更抽象一些。将两种实现的代码贴在下面:
代码如下:
实现1:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#define MAXDATA -10001; /*最小堆中会出现的最小值或小于最小值的值*/
using namespace std;
typedef int ElementType;
typedef struct HNode *Heap;
struct HNode {
ElementType *data;
int size;
int capacity;
};
typedef Heap MinHeap;
void findPath(MinHeap H, int idx);
bool isFull(MinHeap H);
MinHeap insertElement(MinHeap H, ElementType X);
MinHeap creatHeap(int maxSize);
int main() {
int N, M;
cin >> N >> M;
MinHeap mh;
mh = creatHeap(N);
for (int i = 0; i < N; i++) {
int tmp;
cin >> tmp;
mh = insertElement(mh, tmp);
}
for (int i = 0; i < M; i++) {
int idx;
cin >> idx;
findPath(mh, idx);
}
return 0;
}
MinHeap creatHeap(int maxSize) {
/*创建容量为MaxSize的空的最大堆*/
MinHeap H = (MinHeap)malloc(sizeof(struct HNode));
H->data = (ElementType*)malloc(sizeof(ElementType)*(maxSize + 1));
H->size = 0;
H->capacity = maxSize;
H->data[0] = MAXDATA; /*定义哨兵为大于堆中所有可能元素的值*/
return H;
}
bool isFull(MinHeap H) {
return (H->size == H->capacity);
}
MinHeap insertElement(MinHeap H, ElementType X) {
/*将元素X插入最小堆H中,其中H->Data[0]已经定义为哨兵*/
int i;
if (isFull(H)) {
printf("最大堆已满");
}
i = ++H->size; /*i指向插入后堆中的最后一个元素位置*/
for (; X < H->data[i / 2]; i /= 2) {
H->data[i] = H->data[i / 2]; /*上滤X*/
}
H->data[i] = X; /*将X插入*/
return H;
}
void findPath(MinHeap H, int idx) {
while (idx != 1) {
printf("%d ", H->data[idx]);
idx /= 2;
}
printf("%d\n", H->data[1]);
}
实现2,转载自_a_dai_ 05-树7 堆中的路径 (25 point(s))
#include<stdio.h>
#define N 1002
int h[N]={0};
void resort(int i);
void way2root(int i);
int main(){
int n, m;
scanf("%d%d",&n, &m);
for(int i = 1; i <= n; i++){//二叉树从1开始编码
scanf("%d",h+i);
resort(i);
}
while(m--){
int index;
scanf("%d",&index);
way2root(index);
}
return 0;
}
void resort(int i){
//把新插入的元素,放入到数组最后一个元素
//然后重新组织成最小堆
while(i/2&& h[i/2] > h[i]){
int tmp = h[i];
h[i] = h[i/2];
h[i/2] = tmp;
i /= 2;
}
}
void way2root(int i){
while(i != 1){
printf("%d ",h[i]);
i /= 2;
}
printf("%d\n",h[1]);
}
测试结果:
若MAXDATA=10001,测试结果为:
进入死循环,将会超时。