1.实现了一个大根堆类。为方便调用定义成了static静态类成员函数。没有数据成员变量。一个建堆函数,一个调整函数。
#include "stdafx.h"
//定义两个有参宏来寻找数组中的数之间的关系
#define left(x) 2 * x + 1;//获得左节点在数组中的下标
#define right(x) 2 * (x + 1);//获得右节点在数组中的下标
using namespace std;
//大根堆类的实现:包括两个排序建堆的static函数
class dui{
public:
//对一个数组建大根堆
static void BuildMaxHeap(int* a, int length)
{
for (int i = length / 2 - 1; i >= 0; i--)//从底向上建堆length / 2 - 1~0
{
MaxHeapify(a, i, 0, length - 1);//调用一个最小堆调整函数
}
}
//假定对某一个节点i其左,右子树都是都是最大堆,但是对于节点i和它的左右子节点则可能破坏最大堆的性质,我们来写一个函数对这情况下的堆来进行维护使整体的堆满足最大堆性质
//维护节点i及左右孩子这三个节点的堆性质,并对交换的子节点进行再次维护
static void MaxHeapify(int* a, int i, int low, int high){
int l = 2 * i + 1;
int r = 2 * i + 2;
int largest, temp;//存最大数下标;临时存储变量
if (l<=high && a[l]>a[i]){//左孩子>i时
largest = l;
}
else{//左孩子<i时
largest = i;
}
if (r <= high && a[r]>a[largest]){//右孩子>i&&>左孩子时
largest = r;
}
if (largest != i){
temp = a[i];
a[i] = a[largest];
a[largest] = temp;
MaxHeapify(a, largest, low, high);
}
}
//堆排序函数:每次(删除根节点)交换根与最后一个节点,维护剩下的节点为新堆,直到i=1时只需交换,不再维护
static void HeapSort(int a[], int length)
{
int temp;
BuildMaxHeap(a, length);
for (int i = length - 1; i >= 1; i--)
{
//交换根节点和数组的最后一个节点,把最后一个节点排除在新堆之外
temp = a[i];
a[i] = a[0];
a[0] = temp;
MaxHeapify(a, 0, 0, i - 1);//维护下标为i-1到0的子数组的堆性质,排除了a[i]元素
}
}
//int *a;
};
2.HeapSort函数才是堆排序函数。按照删除根节点的办法,每次把最大数(根)放入到容器(数组)最后,这样就从后往前依次输出有序序列。此函数是堆排序函数,即对一个具备堆性质的容器或数组进行排序,输出一个递增或递减的序列。
3.在本节后面的习题当中有提到这么一个问题:为什么是从length/2-1递减到0,而不是从0开始递增到length/2-1呢?从length/2-1递减到0就意味着,从最后的一个非叶节点开始“从小到大”地进行维护,保证每一个点的子树都是最大堆,可以确保最大堆的性质,而如果从0递增到length/2-1则无法保证堆的性质,可以看如下反例:
对数组{14,10,8,16,7}从0递增到length/2-1的堆创建过程如下图所示:
可见无法保证最大堆性质。