堆排序
介绍
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种**选择排序,**它的最坏,最好,平均时间复杂度均为 O ( n l o g n ) O(nlogn) O(nlogn),它也是不稳定排序。
- 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
- 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;
图片来源于:https://www.cnblogs.com/chengxiao/p/6129630.html
步骤
- 构建大(小)顶堆;
- 把堆尾(未排序的最后一个节点)与根节点(最大/小值)交换,从根节点向下调整堆;
- 调整堆尾位置,重复2,直到根节点与堆尾重合;
演示
推荐排序算法动态调试、演示网站: https://www.cs.usfca.edu/~galles/visualization/HeapSort.html
图片来源于:https://www.runoob.com/w3cnote/heap-sort.html
代码与思想
/**
* TODO 堆排序
*
* @author nanfeng
* @date 2022/03/29/ 19:34
*/
public class HeapSort {
public static void main(String[] args) {
int[] nums = new int[]{711,42,333,6,7555,85,93,24,30,177};
heapSort(nums);
System.out.println(Arrays.toString(nums));
}
static void heapSort(int[] nums) {
// 从n/2-1处开始自下向上构造大顶堆,因为从此处开始正好是深度最大的叶子节点的父节点
for (int i = nums.length / 2 - 1; i >=0 ; i--) {
heapAdjust(nums, i, nums.length);
}
// 目前数组符合大顶堆,但仍然无序。
// 通过将根节点与最后一个未排序交换,再调整将数组排序(最终为升序)
// 一次堆调整确定一个最大值
for (int i = nums.length - 1; i > 0; i--) {
swap(nums, 0, i);
heapAdjust(nums, 0, i);
}
}
// 调整为大顶堆
static void heapAdjust(int[] nums, int index, int length) {
// 保存 调整节点 的值
int temp = nums[index];
// 从 index 的左子节点开始调整,也就是2*index+1处开始
for (int i = 2 * index + 1; i < length; i = 2 * i + 1) {
// 如果左子节点小于右子节点,i指向右子节点
if (i < length - 1 && nums[i] < nums[i + 1]) i++;
// 父节点小于子节点,将父节点赋值为子节点
if (nums[index] < nums[i]){
nums[index] = nums[i];
// 父指针更新后的位置
index = i;
}
// 符合大顶堆定义,退出循环
else break;
}
// 将 调整节点 放到最终位置
nums[index] = temp;
}
// 交换
static void swap(int[] nums, int o1, int o2) {
int temp = nums[o1];
nums[o1] = nums[o2];
nums[o2] = temp;
}
}
参考: