MOOC資料結構PTA05-樹7 堆中的路徑
阿新 • • 發佈:2021-08-20
題目
將一系列給定數字插入一個初始為空的小頂堆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 <stdbool.h> #include <stdio.h> #include <stdlib.h> #define Maximum 1000 typedef struct hnode { /*堆陣列*/ int* data; /*當前個數*/ int size; /*最大容量*/ int capacity; } Hnode, *Heap; /*函式宣告*/ Heap initHeap(int max); bool isFull(Heap H); bool isEmpty(Heap H); bool insert(Heap H, int x); int delete (Heap H); void PercDown(Heap H, int p); void buildMinHeap(Heap H); void printPath(Heap H, int M); /*主函式*/ int main() { int N, M; scanf("%d%d", &N, &M); int tempData; Heap H = initHeap(Maximum); for (int i = 1; i <= N; i++) { /*scanf("%d", &H->data[i]); H->size++;*/ scanf("%d", &tempData); insert(H, tempData); } /*此種方式會導致葉節點順序與輸入順序不同步*/ //buildMinHeap(H); printPath(H, M); return 0; } /*函式定義*/ Heap initHeap(int max) { Heap H = (Heap)malloc(sizeof(Hnode)); H->data = (int*)malloc((Maximum + 1) * sizeof(int)); /*最小堆的哨兵*/ H->data[0] = -10001; H->size = 0; H->capacity = Maximum; return H; } bool isFull(Heap H) { return (H->size == H->capacity); } bool isEmpty(Heap H) { return (H->size == 0); } bool insert(Heap H, int x) { if (isFull(H)) return false; Heap temp; int seat = ++H->size; /*如果待插入位置的父親大於待插入元素,將父親下放*/ while (x < H->data[seat / 2]) { H->data[seat] = H->data[seat / 2]; seat = seat / 2; } H->data[seat] = x; return true; } int delete (Heap H) { if (isEmpty(H)) return false; int seat, parent, child; int MaxItem = H->data[1]; /* 用最大堆中最後一個元素從根結點開始向下過濾下層結點 */ int x = H->data[H->size--]; /* 注意當前堆的規模要減小 */ for (parent = 1; parent * 2 <= H->size; parent = child) { child = parent * 2; if (child != H->size) /* Child指向左右子結點的較小者 */ child = (H->data[child] < H->data[child + 1]) ? child : child + 1; if (x <= H->data[child]) break; /* 找到了合適位置 */ else /* 向下濾X,把上層的根用child填充,即把小的child往上放 */ H->data[parent] = H->data[child]; } H->data[parent] = x; return MaxItem; } void PercDown(Heap H, int p) { /* 下濾:將H中以H->Data[p]為根的子堆調整為最xiao堆 */ int Parent, Child; int X; X = H->data[p]; /* 取出根結點存放的值 */ for (Parent = p; Parent * 2 <= H->size; Parent = Child) { Child = Parent * 2; if ((Child != H->size) && (H->data[Child] > H->data[Child + 1])) Child++; /* Child指向左右子結點的較xiao者 */ if (X <= H->data[Child]) break; /* 找到了合適位置 */ else /* 下濾X */ H->data[Parent] = H->data[Child]; } H->data[Parent] = X; } void buildMinHeap(Heap H) { /* 調整H->Data[]中的元素,使滿足最大堆的有序性 */ /* 這裡假設所有H->Size個元素已經存在H->Data[]中 */ int i; /* 從最後一個結點的父節點開始,到根結點1 */ for (i = H->size / 2; i > 0; i--) PercDown(H, i); } void printPath(Heap H, int M) { int* index = (int*)malloc(M * sizeof(int)); int temp; for (int i = 0; i < M; i++) scanf("%d", index + i); /*輸出序列*/ for (int i = 0; i < M; i++) { temp = index[i]; while (temp > 1) { printf("%d ", H->data[temp]); temp /= 2; } if (i != M - 1) printf("%d\n", H->data[1]); else printf("%d", H->data[1]); } }