void abc(int a[], int e, int f) { // sink 下沉
int i = e, j = 2*i, t = a[i];
while (j+1 <= f) {
if (a[j+1] > a[j]) j++;
if (a[j] > a[i]) a[i] = a[j];
i = j; j = 2*i;
}
a[i] = t;
}
主程式建堆與排序迴圈均有邊界錯誤,導致輸出結果錯誤。
a[i] = a[j],未將暫存值 t 下沉至最終位置,導致資料遺失。for (p=n/2; p>=1; p--) 若陣列從 1 起算正確,但主程式 a[15] 實際用 1..14,n=14 正確。for (p=14; p>=1; p--) 應為 p>1,否則 p=1 時 abc(a,1,1) 無意義。n+1 大小並忽略 a[0]。void sink(int a[], int k, int n) {
int temp = a[k];
for (int i = 2*k; i <= n; i *= 2) {
if (i < n && a[i] < a[i+1]) i++; // 取較大子節點
if (temp >= a[i]) break; // 父節點已足夠大
a[k] = a[i]; // 子節點上移
k = i; // 繼續下沉
}
a[k] = temp; // 放入最終位置
}
void heapSort(int a[], int n) {
// 建堆
for (int i = n/2 - 1; i >= 0; i--) sink(a, i, n-1);
// 排序
for (int i = n-1; i > 0; i--) {
swap(a[0], a[i]);
sink(a, 0, i-1);
}
}
掌握 不變式:以 k 為根的子樹已為大頂堆,是寫正確 sink 的關鍵。