堆排序是一种基于二叉堆(Binary Heap)数据结构的比较排序算法。它利用了堆这种数据结构的特性来进行排序,是一种选择排序的改进版本。
堆排序的基本思想
将待排序序列构建成一个堆(大顶堆或小顶堆)
将堆顶元素(最大值或最小值)与末尾元素交换
缩小堆的范围,重新调整堆结构
重复上述过程直到整个序列有序
堆排序的特点
不稳定排序:相同值的元素可能会改变相对顺序
原地排序:不需要额外的存储空间(除了递归或迭代使用的栈空间)
时间复杂度:始终为O(n log n),没有最坏情况
空间复杂度:O(1)
代码实现
package Sort;
public class HeapSort {
public static void main(String[] args) {
int[] res = getHeapSort(new int[]{5,8,9,1,3,6,4,2,7});
for (int i = 0; i < res.length; i++) {
System.out.print(res[i]+" ");
}
}
//堆排序
//步骤:
//1.构建二叉堆(可最大堆--升序,最小堆--降序)
//2.循环将首位元素与未排序的末尾元素交换
//3.重新调整二叉堆
public static int[] getHeapSort(int[] array){
int len = array.length;
if (len < 1) return array;
//1.构建最大堆
buildMaxHeap(array,len);
//2.循环将首位(最大值)元素与未排序的末尾元素交换
while(len > 0){
swap(array,0,len-1);
len--;
//3.重新调整最大堆
adjustHeap(array,0,len);
}
return array;
}
//1.构建二叉堆--最大堆
public static void buildMaxHeap(int[] array,int len){
//从最后一个非叶子结点开始向上构造最大堆,完全二叉树的非叶子结点公式:(N/2)-1
for (int i = (len/2 - 1); i >=0 ; i--) {
adjustHeap(array,i,len);
}
}
//2.交换元素
public static void swap(int[] array,int i,int j){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
//3.调整二叉堆
public static void adjustHeap(int[] array, int i, int len){
int maxIndex = i;//定义最大指针
//完全二叉树求左节点的公式:2*i+1, 右节点:2*i+2
int left = 2*i + 1;
int right = 2*i + 2;
//如果有左子树,且左子树>父节点,则将最大指针指向左子树
if (left < len && array[left] > array[maxIndex]){
maxIndex = left;
}
//如果有右子树,且右子树>父节点,且>左子树,则将最大指针指向右子树
if (right < len && array[right] > array[maxIndex]){
maxIndex = right;
}
//如果父节点不是最大值,则将父节点与最大值交换,并且递归调整与父节点交换的位置
if (maxIndex != i){
swap(array,maxIndex,i);
adjustHeap(array,maxIndex,len);
}
}
}
时间复杂度分析
建堆过程:O(n)
每次调整堆:O(log n),共需要调整n-1次
总时间复杂度:O(n log n)
空间复杂度分析
堆排序是原地排序算法,只需要常数级别的额外空间,因此:
空间复杂度:O(1)