1. 简介
堆排序利用的是堆序性,最小堆进行从大到小的排序。
先建初堆,保证堆序性。将堆顶元素与最后一个元素交换,
就将当前堆中的最大(小)的元素放到了最后后。堆大小递减,再重新调整堆选出第二大,重复上述过程。
2. 实现
2.1 建初堆
由于堆具有递归性,即以根节点的所有子树都是一个堆。
我们需要从下往上调整堆。即从完全二叉树的最大非叶子节点开始调整堆,直到根节点。
这样才能保证堆序性。
对于数组3,4,1,2,5
,建初堆的过程。
- 代码
template<typename T>
void adj_heap(std::vector<T> &arr,std::size_t rt, std::size_t bd) {
T v = arr[rt];
std::size_t child;
std::size_t i;
for (i = rt; i < bd; i = child) {
child = i * 2 + 1;
if ( child + 1 < bd && arr[child + 1] < arr[child])
++child;
if (child >= bd || v <= arr[child] ) {
break;
}
else{
arr[i] = arr[child];
}
}
arr[i] = v;
}
template<typename T>
void make_orig_heap(std::vector<T> &arr, std::size_t sz) {
for (std::size_t i = sz/2 - 1; i != -1; --i){
adj_heap(arr, i, sz);
}
}
2.2 堆排序
建立初始堆后,我们就确定了最小(大)的元素。
将该元素与最后位置交换,并将堆大小 - 1。
我们就又得到了一个未调整的堆。我们重复调整堆和交换元素的过程,直到最后堆大小为1。
所以,最小堆进行排序形成的序列是从大到小。
过程如图
- 代码
template<typename T>
void heap_sort(std::vector<T> &arr, std::size_t sz) {
if ( 0 == sz)
return ;
make_orig_heap(arr, sz);
for (std::size_t i = sz - 1; i > 0; --i) {
T last = arr[i];
arr[i] = arr[0];
arr[0] = last;
adj_heap(arr, 0, i);
}
}