基本概念
堆积的定义(两种形式):
称满足条件(1)的堆积为大顶堆积,称满足条件(2)的堆积为小顶堆积,本文使用大顶堆积。2、堆积是一棵完全二叉树,二叉树中任何一个分支结点的值都大于或者等于它的孩子结点的值,并且每一棵子树也满足堆积的特性,如下图:
堆积有如下特点:序列的第一个元素或者二叉树的根结点的值最大。
核心思想和步骤
堆积排序的核心思想如下:
第 i 趟排序将序列的前 n-i+1 个元素组成的子序列 为一个堆积,然后将堆积的第一
个元素与堆积的最后那个元素交换位置。
堆积排序的步骤如下:
1、将原始序列转换为第一个堆积。(建初始堆积);
2、将堆积的第一个元素与堆积的最后那个元素交换位置(即去掉最大值元素);
3、将“去掉”最大值元素后剩下的元素组成的子序列重新转换一个新的堆积;
4、重复上述过程的第2至第3步n-1次;
堆积排序的完整过程如下图所示:
堆积排序的过程中有一个非常重要的步骤就是将一个序列转换成堆,这个该如何完成呢?
我们知道,堆(二叉堆)可以视为一棵完全二叉树,完全二叉树的一个“优秀”的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示,每一个结点对应数组中的一个元素,同时对于i个元素,它的左右子节点在下标以0开始的数组中的位置分别为:2*i+1、2*i+2;
建堆的核心内容是调整堆,使二叉树满足堆的定义(每个节点的值都不大于其父节点的值)。调堆的过程应该从最后一个非叶子节点开始,假设有数组A = {1, 3, 4, 5, 7, 2, 6, 8, 0}。那么调堆的过程如下图,数组下标从0开始,A[3] = 5开始,分别对5,4,3,1进行调整。分别与左孩子和右孩子比较大小,如果A[3]最大,则不用调整,否则和孩子中的值最大的一个交换位置,在图1中是A[7] > A[3] > A[8],所以A[3]与A[7]对换,从图1.1转到图1.2。
堆排序的动态图如下:
算法实现
调整堆子算法的C语言实现如下:
该子算法的功能是将以编号为 i 的结点作为根的子树调整为一个堆积;
其中,
K :序列;
i :被调整的二叉树的根的序号;
n :被调整的二叉树的结点数目。
堆积排序的完整算法的C语言实现如下:
算法分析
堆积排序的时间复杂度为O(nlog2n);
本文部分参考自:堆排序算法详解