一、思路:
(1)将数组arr[0~n-1]调整形成最大堆;
(2)取堆顶点(即取最大值)放到数组arr[n-1]的位置,即将arr[0]与arr[n-1]交换位置;
(3)调整arr[0]到arr[n-2]重新形成最大堆;
(4)同理,取堆顶arr[0](即取最大值)放到数组arr[n-2]位置,即交换arr[0]与arr[n-2]位置;
(5)重复以上步骤,这样从数组arr[n-1]->arr[0]是第一大,第二大,…,就是从小到大排序;(同理:从大到小,就用最小堆实现)
二、实现程序:
#include <iostream>
using namespace std;
const int maxSize = 100;
template <class T>
void HeapSort(T arr[], int n); // 堆排序
template <class T>
void ShiftDown(T arr[], int start, int end); // 下滑
int main(int argc, const char * argv[]) {
int i, n, arr[maxSize];
cout << "请输入要排序的数的个数:";
cin >> n;
cout << "请输入要排序的数:";
for(i = 0; i < n; i++)
cin >> arr[i];
cout << "排序前:" << endl;
for(i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
HeapSort(arr, n);
cout << "排序后:" << endl;
for(i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
// 堆排序
template <class T>
void HeapSort(T arr[], int n) {
int CurrentPos, i, temp; // CurrentPos当前下滑结点
// 第一步:第1次形成最大堆,(n / 2 - 1)为倒数第一个非叶结点
for(CurrentPos = (n / 2 - 1); CurrentPos >= 0; CurrentPos--)
ShiftDown(arr, CurrentPos, n-1);
// 第二步:取堆顶点(即最大值)放到n-1位置:交换arr[0]与arr[n-1]
temp = arr[0];
arr[0] = arr[n-1];
arr[n-1] = temp;
for(i = n-2; i > 0; i--) { // 第2次形成最大堆
// 第三步:将剩下的数arr[0 ~ n-2]重新调整最大堆
ShiftDown(arr, 0, i); // 每次只是调整刚交换的arr[0]就可以了
temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
}
}
// 下滑
template <class T>
void ShiftDown(T arr[], int start, int end) {
int i, j, temp;
i = start;
j = 2 * i + 1; // j是i的子女
temp = arr[i];
while(j <= end) {
if(j < end && arr[j] < arr[j+1]) // 选两个子女中较大者
j++;
if(temp < arr[j]) { // 如果双亲比子女小,则上移子女结点
arr[i] = arr[j];
i = j; // 父
j = 2 * i + 1; // 子女
} else // 否则,则结束循环
break;
}
arr[i] = temp; // 把arr[0]暂存的值填到当前位置
}
测试数据:
7
20 12 50 70 2 8 40