堆排序主要分为堆的建立,堆的排序两大部分。
堆的建立主要由堆的调整遍历形成。
堆的调整
给定一个堆,根节点下标为t总长度为len,从根到叶子节点逐层调整
以大根堆为例:
void Adjust_heap(vector<int>& a, int t, int len) {
a[0] = a[t];//用空着的a[0]存放根节点
//i的初始值为t节点的左子节点
for (int i = t * 2; i <= len; i = i * 2) {
if (i < len && a[i] < a[i + 1]) {
//i<len是要保证右兄弟存在 i指向最大的子节点
i++;
}
if (a[0] >= a[i]) {
//如果根节点比最大的子节点还要大 则无需调整
break;
}
else {
//如果最大子节点比根节点要大
a[t] = a[i];//根节点与最大子节点互换
t = i;//t为被交换的最大子节点(下一层循环的父节点)
//若进入下一层循环,a[t]=a[i]仍然表示根节点与最大子节点互换
}
}
a[t] = a[0];//将根节点换到最后交换的位置
}
堆的建立
n维无序数组可以转化为n维的无序满二叉树,其中非终端节点为n/2向下取整个(二叉树的性质)。所以对每个非终端节点进行调整即可得到大根堆(小根堆)。
void Heap_build(vector<int>& t, int len) {
for (int i = len / 2; i > 0; i--) {//从n/2一直到根节点调整
Adjust_heap(t, i, len);
}
}
堆排序
将根节点与最后一个节点互换,然后对除了最后的节点(原先的跟节点)之外进行调整,即可得到一个大根堆(小根堆)+根节点。重复操作直到堆中的元素数目为1,所得到的序列即为堆排序。
需要注意的是大根堆得到的排序为降序,而小根堆得到的是升序。
void Heap_sort(vector<int>& t, int len) {
for (int i = len - 1; i > 0; i--) {
swap(t[1], t[i + 1]);//将根节点与最后一个堆中的节点互换
Adjust_heap(t, 1, i);//调整剩下的堆
}
}
用例测试:
结果:
ps:t[0]为垃圾元素 真正排序的为t[1…7]