概念
堆排序是一种基于二叉堆数据结构的排序算法。它的基本思想是将待排序的序列构建成一个大顶堆或小顶堆,然后依次取出堆顶元素,即最大或最小元素,再将剩余的元素重新构建成一个堆,重复这个过程直到所有元素都取出并排序完成。
排序步骤
- 构建堆:将待排序的序列看作是一个完全二叉树,从最后一个非叶子节点开始,依次进行下沉操作,使得每个节点的值都大于(或小于)其子节点的值,最终得到一个大顶堆(或小顶堆)。
- 取出堆顶元素:将堆顶元素与最后一个元素交换位置,然后将堆的大小减一,即排除已经排序好的元素。
- 重建堆:对交换后的堆顶元素进行下沉操作,使得堆重新满足大顶堆(或小顶堆)的性质。
- 重复上述步骤,直到堆的大小为1,即所有元素都已经取出并排序完成。
算法分析
堆排序的时间复杂度为O(nlogn),其中n为待排序序列的长度。堆排序是一种原地排序算法,不需要额外的存储空间,但是由于堆排序的操作需要频繁地进行元素的交换,因此相对于其他排序算法,它的性能较低。
算法实现(示例)
- 交换方法为自定义
import java.util.Arrays;
/**
* 八大排序-堆排序
*/
public class Dui {
public static void main(String[] args) {
int[] arr= {5,7,4,2,0,3,1,6,9,7,5,13,23,24};
//构建大顶堆
for (int p = arr.length-1; p >=0; p--) {
adjust(arr,p,arr.length);
}
//重复首尾交换并维护
for (int i = arr.length-1; i>=0; i--) {
swap(arr, 0, i, 0);
adjust(arr,0,i);
}
System.out.println(Arrays.toString(arr));
}
/**
* 堆的维护
*/
public static void adjust(int[] arr,int parent,int length) {
//定义左孩子
int child=parent*2+1;
while(child<length) {
//定义右孩子
int rchild=child+1;
if(rchild<length&&arr[child]<arr[rchild]) {
child++;
}
if(arr[parent]<arr[child]) {
swap(arr, parent, child, 1);
parent=child;
child=child*2+1;
}else {
break;
}
}
}
/**
* 交换方法swap
* 交换数组arr
* 下标i,j
* 排序方式z
* z为0从小到大,z为1从大到小
*/
public static void swap(int[] arr,int i,int j,int z) {
//从小到大
if(z==0) {
if(arr[i]>arr[j]) {
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
//从大到小
}else if(z==1) {
if(arr[i]<arr[j]) {
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
}