05-树7 堆中的路径

将一系列给定数字插入一个初始为空的小顶堆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

 

最小堆的基本操作,可以用数组就直接实现,在这里为为了复习直接用了完整的方式。

但是在这过程中发现一个现象,题目是让一个一个把输入插入到最小堆中。

而我是直接先把所有数据按输入顺序放入数组里,然后再重新调整各节点满足最小堆。结果发现这两种方式形成的最小堆有结构的细微差异,叶子节点的位置会有所不同,这样再输出路径就会出现与题目不符合的情况。因此还是要按照题目的意思来。

//注意:这个方法与原题答案顺序不同

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAXDATA -10001 //岗哨
typedef struct Hnode * Heap;
struct Hnode{
    int *data;
    int size;
    int capacity;
};
typedef Heap MINheap;

MINheap creatMinheap(){ //最小堆节点的创建
    MINheap h = (MINheap)malloc(sizeof(struct Hnode));
    h->data = (int*)malloc(sizeof(int)*1001);
    h->size = 0;
    h->capacity = 1000;
    h->data[0] = MAXDATA;
    return h;
}

void percDown(MINheap h, int p){//调整节点
    int head = h->data[p];
    int parent,child;
    for (parent = p;parent*2 <= h->size;parent = child){
        child = parent*2;
        if ((child!=h->size)&&(h->data[child]>h->data[child+1])){
            child++;
        }
        if (h->data[child]>=head) break;
        else h->data[parent] = h->data[child];
    }
    h->data[parent] = head;
}
MINheap buildMinHeap(MINheap h){
    int i;
    for (i=h->size/2; i>0; i--){
        percDown(h,i);
    }
    return h;
}

MINheap readMinHeap(MINheap h ,int N){//按顺序读取数
    int x;
    for (int i = 1; i <= N; ++i){
        scanf("%d",&x);
        getchar();
        h->data[i] = x;
        h->size++;
    }
    //读取完所有数
    //最小堆调整
    buildMinHeap(h);//读完后进行调整以满足最小堆条件
    return h;
}

void printLoad(MINheap h, int i){//输出路径
    for (;i>0;i=i/2){
        printf("%d", h->data[i]);
        if (i!=1) printf(" ");
    }
    printf("\n");

}

int main(){
    int N,M;
    scanf("%d %d",&N,&M);
    printf("%d %d\n",N,M);
    MINheap h = creatMinheap();
    h = readMinHeap(h,N);//读取
    h = buildMinHeap(h);//调整
    int p;
    while(M--){
        scanf("%d",&p);
        getchar();
        printLoad(h,p);//输出
    }
    return 0;
}

正确的答案:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h> 
#define MINDATA -10001;//岗哨

int a[1001],size;//size是当前数组里的个数

void insert(int x){//最小堆的插入
    int i;
    if (size == 1000) return;
    //这里注意向上比较的时候一定要和插入值x比较而不是a[i]比较
    for ( i = ++size; a[i/2]>x; i=i/2){ 
    // i=++size  size的值增加 同时把增加后的值给了变量i
        a[i] = a[i/2];
    }
    a[i] = x;
}

int main(){
    int N,M;
    a[0] = MINDATA;//岗哨赋值
    scanf("%d %d",&N,&M);
    int x;
    for (int i = 1; i <= N; ++i){//插入
        scanf("%d",&x);
        insert(x);
    }
    int p;
    for (int i = 0; i < M; ++i){
        scanf("%d",&p);
        printf("%d", a[p]);//为了格式 先输出一个数
        for (int i = p/2; i > 0; i=i/2){
            printf(" %d",a[i]);
        }
        printf("\n");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值