void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
//堆调整算法实现
void max_HeapAdjust(int* A, int index, int n) {
if (2 * index < n){
int cur = index;
if (2 * index + 1 < n && A[2 * index + 1] > A[cur])
cur = 2 * index + 1;
if (2 * index + 2 < n && A[2 * index + 2] > A[cur])
cur = 2 * index + 2;
//(3)
if (cur != index){
swap(A[cur], A[index]);
max_HeapAdjust(A, cur, n);
}
}
}
int* heapSort(int* A, int n) {
//(1)
for (int i = n / 2 - 1; i >= 0; i--)//该循环建堆(自下而上)
max_HeapAdjust(A, i, n);
//(2)
for (int j = n - 1; j > 0; j--) {
swap(A[j], A[0]);
max_HeapAdjust(A, 0, j);//堆调整(自上而下)
}
return A;
}
算法思想:堆是一个完全二叉树,分有最大堆和最小堆。以最大堆(根的值大于左右子树的值,子树也是最大堆)为例。
就是堆顶和堆尾对换,并输出最后一个,剩下的进行堆调整再一次次循环下去
以数组A[6] = {1,5,3,2,2,4}为例,进行堆排序
算法解析:如图A所示,
在第(1)中,循环执行max_HeapAdjust函数,函数
index值分别为 2 1 0
执行一次函数对比 A[5] A[2] A[3] A[1] A[1] A[0]
A[6] A[2] A[4] A[1] A[2] A[0]
以当index=0为例,比较A[1]与A[0] 比较A[2]与A[0]
因为A[0]<A[1],cur=1 故执行(3)
在(3)中,A[0]与A[1]互换值,使得A[0]=5,A[1]=1,由于换了A[1],故需要比较A[1]与其两个子节点。cur=1传入max_HeapAdjust
index= 1
执行对比 A[3] A[1]
A[4] A[1]
因为A[1]<A[3],cur=3 故执行(3) 重复以上步骤,直到建堆完成
走完以上步骤,算是构建最大堆完成,即根节点A[0]最大,得到图C;向下继续走
在(2)中,执行一次循环,互换根节点A[0] 与最后一个叶节点A[j],此时A[j]即A[5]为最大值,执行max_HeapAdjust
此后每次循环index都是0,即每次都从堆根部与子节点对比,向下走构建最大堆(不包括刚才替换的A[5]),然后替换A[0]
与刚刚A[j]即A[4]替换,此时A[4]为最大值,依次类推,最后得到数组A即按索引从小到大排序完成
总结:
首先构建最大堆,自下而上构建(从叶节点到根节点)
其次,在最大堆上将根节点与最后一个叶节点互换值,然后排除此叶节点的其他节点,自上而下构建最大堆(从根节点到叶节点),
在最大堆上将根节点与最后一个叶节点互换值,然后排除此叶节点的其他节点,自上而下构建最大堆(从根节点到叶节点),
依次类推,所有的节点都被排除构建堆时,完成,由此得到的数组即根据索引由小变大排序