堆排序(C++)

丸子叮咚響發表於2020-10-30

實現

  1. 初始時把要排序的n個數的序列看作是一棵順序儲存的二叉樹(一維陣列儲存二叉樹),調整它們的儲存序,使之成為一個堆,
    將堆頂元素輸出,得到n 個元素中最小(或最大)的元素,這時堆的根節點的數最小(或者最大)。
    然後對前面(n-1)個元素重新調整使之成為堆,輸出堆頂元素,得到n 個元素中次小(或次大)的元素。
    依此類推,直到只有兩個節點的堆,並對它們作交換,最後得到有n個節點的有序序列。稱這個過程為堆排序。
  2. 程式碼
// s節點不滿足堆時的調整處理
void adjust_heap(int a[], int n, int s){
  int temp = a[s];
  int child = 2*s + 1; // s節點左子
  while(child < n){
    // s節點右子存在,且右子更大
    if ((child + 1 < n -1) && (a[child] < a[child + 1])){
      child +=1;
    }

    // 更大子節點移到s節點
    if (a[s] < a[child]) {
      a[s] = a[child];
      s = child;
      child = 2 * s + 1;
    }else {
      break;
    }
    a[s] = temp;
  }
}

// 建大堆
void build_heap(int a[], int n) {
  if (n < 2){
    return;
  }

  int last_f = 0; // 最後一個有子節點的父節點
  if (n % 2 == 0){
    last_f = (n - 1) /2; // n為偶數,最後一個節點為左子節點
  } else {
    last_f = (n - 3) /2; // n為奇數,最後一個節點為右子節點
  }

  for (int i = last_f; i >=0; --i){
    adjust_heap(a, n, last_f);
  }
}

void heap_sort(int a[], int n) {
  // 建最大堆
  build_heap(a, n);
  for (int i = n - 1; i >=0; --i) {
    // 堆頂節點(a[0])與i節點交換值
    int temp = a[i];
    a[i] = a[0];
    a[0] = temp;

    // 將前i個節點重新調整為最大堆
    adjust_heap(a, i, 0);

    print(a, n);
  }
}

測試

  1. 程式碼
#include <iostream>
using namespace std;

void print(int a[], int num) {
  for (int i = 0; i < num; ++i) {
    cout << a[i] << " ";
  }
  cout << endl;
}

int main() {
  int a[] = {7, 6, 5, 4, 3, 2, 1};
  int n = sizeof(a) / sizeof(a[0]);
  print(a, n);
  heap_sort(a, n);
  print(a, n);
  cin.get();
  return 0;
}
  1. 結果
7 6 5 4 3 2 1
6 4 5 1 3 2 7
5 4 2 1 3 6 7
4 3 2 1 5 6 7
3 1 2 4 5 6 7
2 1 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7

相關文章