14.堆排序
阿新 • • 發佈:2020-12-04
堆排序
從 13 裡面拿出來的,害,後面的陣列就自己編把,別和我重了
程式碼
#include <iostream> using std::cin; using std::cout; using std::endl; using std::ostream; using std::string; using std::swap; struct Element { int key; string data; // 過載比較運算子, 方便後面直接元素對比 bool operator<(const Element &rhs) const { return key < rhs.key; } bool operator<=(const Element &rhs) const { return key <= rhs.key; } bool operator>(const Element &rhs) const { return key > rhs.key; } bool operator>=(const Element &rhs) const { return key >= rhs.key; } }; // 過載 << 用於輸出陣列型別 template <size_t N> ostream &operator<<(ostream &os, const Element (&array)[N]) { for (const Element &e : array) cout << e.data << "(" << e.key << ") "; return os; } // 把以 root 為根的子樹調整為大根堆(根>=左、右孩子) // 陣列從 1 號位置開始放, root 的左孩子是 2*root, 右孩子是 2*root + 1 // 這裡的陣列從 0 號位置開始放, root 的左孩子是 2*root+1, 右孩子是 2*root + 2 void adjust_heap(Element array[], int root, int length) { Element old_root = array[root]; // 暫存 root 節點的值 for (int i = 2 * root + 1; i < length; i = 2 * i + 1) // i 指向 root 節點的左孩子 { if (i + 1 < length && array[i] < array[i + 1]) // 如果右孩子存在, 且比左孩子大 i++; // 讓 i 指向右孩子 if (old_root >= array[i]) break; // 如果原 root 結點的值 >= 左右孩子中的最大者, 不用調整了 array[root] = array[i]; // 否則, 把它換到 root 結點的位置 root = i; // 換過之後, 以 i 為根的子樹可能不再是大根堆, 需要繼續調整 } array[root] = old_root; // 調整到最後, root 指到了正確位置, 它的父節點比它大, 子節點比它小, 原來的根節點就放到這裡 } // 建立一個大根堆 void build_max_heap(Element array[], int length) { int last_branch_node = length / 2; // 最後一個分支結點應該是 結點數 / 2, 往後就是葉子結點了 for (int i = last_branch_node; i >= 0; i--) // 從後往前, 調整所有分支結點 adjust_heap(array, i, length); } // 堆排序 void heap_sort(Element array[], int length) { build_max_heap(array, length); // 把陣列轉成大根堆 for (int i = length - 1; i > 0; i--) // 從陣列最後一個元素開始往前掃 { swap(array[0], array[i]); // 把大根堆的根節點(最大值)換到後面 adjust_heap(array, 0, i); } } int main(int argc, char const *argv[]) { Element array[] = {{23, "小紅"}, {88, "小米"}, {6, "小黑"}, {54, "小白"}, {76, "小綠"}}; int length = 5; cout << "原始陣列: " << array << endl; heap_sort(array, length); cout << "排序結果: " << array << endl; return 0; }