05-树7 堆中的路径 (25 point(s))

将一系列给定数字插入一个初始为空的小顶堆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,测试结果为:
在这里插入图片描述
进入死循环,将会超时。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值