堆排序主要需要先理解清楚堆(heap)。堆的定义:
对于序列
,若满足
或者
,其中
,则称该序列为堆。
堆可以看做是一棵二叉树。我们讨论升序排序,所以我们需要的是最大堆,也就是父节点的值总是大于等于任何一个子节点的值。
堆排序的步骤:
1) 输入乱序数组
2)调整为最大堆。先调整每个非叶节点,使得该节点为根节点的子树为最大堆。
3)将根节点与最后一个节点的值互换,并将互换后的最后一个节点移出堆。
4)如果堆中的元素个数大于1,则回到2),否则,输出当前数组,则为输出排序好的数组
复习的时候,发现以前实现的堆排序虽然能work,但是效率有点问题。重新实现了一个版本:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void fixdown(vector<int> &nums, int k, int n){
while(2*k+1 < n){
int swap_ind = (2 * k + 2 >= n) ? 2 * k + 1:
(nums[2*k+2] < nums[2*k+1]) ? 2*k+1: 2*k+2;
if(nums[k] < nums[swap_ind])
swap(nums[k], nums[swap_ind]);
else
break;
k = swap_ind;
}
}
void heapsort(vector<int> &nums){
int n = nums.size();
for(int i=n/2-1; i>=0; i--){
fixdown(nums, i, n);
}
for(int i=0; i<n; i++){
swap(nums[0], nums[n-i-1]);
fixdown(nums, 0, n-i-1);
}
}
int main(int argc, char *argv[]){
int n;
cin >> n;
if(n < 2){
cout << "Size of array must bigger than 1" << endl;
return 0;
}
vector<int> array;
for(size_t i=0; i<n; i++){
int tmp;
cin >> tmp;
array.push_back(tmp);
}
heapsort(array);
for(int a: array){
cout << a << " ";
}
cout << endl;
return 0;
}
以前实现的算法如下:
void heapsort(int *arr, int n){
/*
arr: array
n: size of array
*/
if(n == 1)
return;
int k, swap_ind;
/*adjust heap*/
for(int i=n/2-1; i>=0; i--){
k = i;
while(2*k+1 < n){
swap_ind =
(2*k+2 >= n) ? 2*k+1 :
(arr[2*k+1] > arr[2*k+2]) ? 2*k+1 : 2*k+2;
if(arr[swap_ind] > arr[k]){
swap(arr, k, swap_ind);
k = swap_ind;
} else {
break;
}
}
}
//remove the top node out of heap
swap(arr, 0, n-1);
heapsort(arr, n-1);
}
void swap(int *arr, int i, int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}