05-树7 堆中的路径

66 阅读3分钟

题目描述

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

题解

题意理解:给定插入最小堆的序列,根据该序列生成最小堆。读入若干结点下标,输出对应结点到根结点路径上的结点值。

创建空堆与输出结果的函数不用多说,重点在于向堆中插入元素的复现,如下为阉割版。

Insert 函数:

  • 传入参数为 堆 与 被插入元素值
  • 如果堆满就退出
  • 如果堆未满就插入
    • 首先 i = ++H->Size ,标记插入到堆尾的下标
    • 如果父结点的元素值比待插入元素值大,父结点下滤,当前结点的值替换为父结点的值,当前指针移到父结点
    • 直到父结点的值比待插入元素小时退出,当前结点位置就是插入位置
    • 退出循环给当前结点赋值
  • 插入完成

完整代码(AC):

#include <stdio.h>
#include <stdlib.h>

typedef struct HeapStruct *MinHeap;
struct HeapStruct {
    int *Data;
    int Size;
    int Capacity;
};

void Insert(MinHeap H, int item)
{
    int i;
    if (H->Size == H->Capacity) return;
    else {
        for (i = ++H->Size; H->Data[i / 2] > item; i /= 2) {
            H->Data[i] = H->Data[i / 2];
        }
        H->Data[i] = item;
    }
}

MinHeap CreateHeap(int n)
{
    int i, parent, child, tmp, item;

    MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));
    H->Data = (int*)malloc(sizeof(int) * (n + 1));
    H->Size = 0;
    H->Capacity = n;
    H->Data[0] = -10001;

    for (i = 1; i <= n; i++) {
        scanf("%d", &item);
        Insert(H, item);
    }

    return H;
}

void PrintTrack(MinHeap H, int m)
{
    int i, j, index, flag;
    for (i = 0; i < m; i++) {
        scanf("%d", &index);
        flag = 0;
        for (j = index; j > 0; j /= 2) {
            if (flag) {
                printf(" %d", H->Data[j]);
            } else {
                flag = 1;
                printf("%d", H->Data[j]);
            }
        }
        printf("\n");
    }
}

void Free(MinHeap H)
{
    free(H->Data);
    free(H);
}

int main()
{
    int n, m;
    MinHeap H;
    scanf("%d %d", &n, &m);
    H = CreateHeap(n);
    PrintTrack(H, m);
    Free(H);
    return 0;
}

第一次尝试时使用读入一组数再调整堆的有序性来建堆。应该先建一个空堆,再逐个插入。

错误解答(WA):

该解答中主要练习了调整完全二叉树有序性的建堆函数。

#include <stdio.h>
#include <stdlib.h>

typedef struct HeapStruct *MinHeap;
struct HeapStruct {
    int *Data;
    int Size;
};

void BuildHeap(MinHeap H)
{
    int i, parent, child, tmp;
    for (i = H->Size / 2; i > 0; i--) {
        tmp = H->Data[i];
        for (parent = i; parent * 2 <= H->Size; parent = child) {
            child = parent * 2;
            if ((child != H->Size) && (H->Data[child + 1] < H->Data[child]))
                child++;
            if (tmp <= H->Data[child]) break;
            else H->Data[parent] = H->Data[child];
        }
        H->Data[parent] = tmp;
    }
}

MinHeap CreateHeap(int n)
{
    MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));
    H->Data = (int*)malloc(sizeof(int) * (n + 1));
    H->Size = n;
    H->Data[0] = -10001;

    for (int i = 1; i <= n; i++) {
        scanf("%d", &H->Data[i]);
    }

    BuildHeap(H);

    return H;
}

void PrintTrack(MinHeap H, int m)
{
    int i, j, index, flag;
    for (i = 0; i < m; i++) {
        scanf("%d", &index);
        flag = 0;
        for (j = index; j > 0; j /= 2) {
            if (flag) {
                printf(" %d", H->Data[j]);
            } else {
                flag = 1;
                printf("%d", H->Data[j]);
            }
        }
        printf("\n");
    }
}

void Free(MinHeap H)
{
    free(H->Data);
    free(H);
}

int main()
{
    int n, m;
    MinHeap H;
    scanf("%d %d", &n, &m);
    H = CreateHeap(n);
    PrintTrack(H, m);
    Free(H);
    return 0;
}