原理
利用二叉堆的性质来完成对于无序数组的排序
- 最大堆的堆顶是整个堆中的最大元素
- 最小堆的堆顶是整个堆中的最小元素
所以,以最大堆为例,如果删除一个最大堆的堆顶(逻辑删除,只是跟末尾的节点进行互换),那么经过自我调整,第二大的元素就会被交换上来,成为最大堆的堆顶。经过n-1次互换后,原本的二叉堆就变成由小到大的有序集合了。如图:

代码
/*** “下沉”调整* @param array 待调整的堆* @param parentIndex 要“下沉”的父节点* @param length 堆的有效大小* 将大的元素下沉的步骤:* 1.定义要下沉的父节点,子节点=父节点*2+1,如果子节点存在就继续循环* 2.比较左子节点跟右子节点大小,哪个大就将子节点定位到哪个节点* 3.判断父节点跟子节点的大小,看是否需要下沉* 4.把子节点的值赋值给父节点,令此时的子节点成为父节点继续下沉*/public static void downAdjust(int[] array, int parentIndex,int length) {int temp = array[parentIndex];// 左子节点 = 父节点 * 2 + 1int childrenIndex = 2 * parentIndex + 1;while (childrenIndex < length) {// 如果右子节点存在,且右子节点的值大于于左子节点,则定位到右子节点if (childrenIndex + 1 <= length && array[childrenIndex] > array[childrenIndex + 1]) {childrenIndex++;}// 如果父节点的值小于等于任何一个子节点,则结束循环if (temp >= array[childrenIndex]) {break;}array[parentIndex] = array[childrenIndex];parentIndex = childrenIndex;childrenIndex = 2 * childrenIndex + 1;}array[parenIndex] = temp;}public static void headSort(int[] array) {// 1.把无序数组构成最大堆;从倒数第一个非叶子节点开始下沉,循环for (int i = (array.length-2)/2; i>=0; i--) {downAdjust(array,i,array.length);}// 2.循环删除堆顶元素,移到集合尾部,调整堆产生新的堆顶for (int i = array.length-1; i>0; i--) {int temp = array[i];array[i] = array[0];array[0] = temp;// 下沉调整最大堆downAdjust(array,0,i);}}
复杂度分析
空间复杂度为O(1),因为没有开辟额外的空间。下沉方法的时间复杂度是O(logn),把无序数组构建成二叉堆的时间复杂度是O(n),需要进行n-1次循环,因为构建二叉堆跟循环是并列关系,所以总的时间复杂度是O(nlogn)
