参考:https://www.cnblogs.com/onepixel/articles/7674659.html
其他排序算法传送门:https://blog.csdn.net/jkdcoach/article/details/87442482
源码:https://github.com/sunrui849/sort
堆排序
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
1.1 算法描述
- 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
- 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
- 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
1.2 动图演示
1.3特性
时间复杂度固定为 n*(log n) ,并且无需额外的空间,采用堆的数据结构进行排序,堆是一颗完全二叉树。常用于取n个数中前K大(小)的数。
1.4代码实现
//记录已排序的最小索引,在构建最大堆时初始化
private static int num = 0;
/**
* 堆排序
* 从小到大
* @param arr
* @return
*/
public static int[] sort(int[] arr) {
if (arr == null || arr.length == 0){
return arr;
}
buildHeap(arr);//将无序数组构建成最大堆
//只需要遍历完剩余两个节点时即可结束
for (int i = num - 1; i > 0; i--){
swap(arr,0,i);
num--;//此时数组后面 下标是num开始的到最后 的均为已排好序的
heapify(arr,0);//此时堆中只有根节点是错误的,调整即可
}
return arr;
}
/**
* 构建最大堆
* @return
*/
private static int[] buildHeap(int[] arr) {
num = arr.length;
//最后一个元素的父节点为 num/2 向下取整,构建最大堆也就是从倒数第二层开始调整
for (int i = num/2 ; i >= 0; i--){
heapify(arr,i);
}
return arr;
}
/**
* 调整堆
* @param arr
* @param index
* @return
*/
private static int[] heapify(int[] arr, int index){
int leftChildIndex = index * 2 + 1;
int rightChildIndex = index * 2 + 2;
int parentIndex = index;
//比较父节点和左子节点的值,大的改为父节点
if (leftChildIndex < num && arr[leftChildIndex] > arr[parentIndex]){
parentIndex = leftChildIndex;
}
//比较父节点和右子节点的值(此时父节点为原来的左节点和父节点中的最大值),大的改为父节点
if (rightChildIndex < num && arr[rightChildIndex] > arr[parentIndex]){
parentIndex = rightChildIndex;
}
//如果父节点改变了,那么开始交换位置,并向下继续调整(这个递归的逻辑是为了改变根节点时的调整,构建最大堆时这个递归代码是冗余的)
if (parentIndex != index){
swap(arr,parentIndex,index);
heapify(arr,parentIndex);
}
return arr;
}
/**
* 交换位置
* @param arr
* @param i
* @param j
* @return
*/
private static int[] swap(int[] arr,int i,int j){
int flag = arr[i];
arr[i] = arr[j];
arr[j] = flag;
return arr;
}