目录
本文就不讲述堆排序的概念了,只讲2个重点,理清楚了这两个重点,才算真正理解了堆排序。
1、完整堆排序代码
public static void main(String[] args) {
int[] nums = {7,8,2,9,3,1,90,88,33};
heapSort(nums);
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
}
public static void heapSort(int[] nums){
int length = nums.length;
//从这里开始构造大顶堆
int start = length/2-1;
//构造大顶堆
for (int i = start;i>=0;i--) {
heapAdjust(nums,i,length);
}
//重新构造大顶堆
for (int i = length; i >=3; i--) {
swap(nums,0,i-1);
heapAdjust(nums,0,i-1);
}
//最后剩第0个和第1个元素
if (nums[0] > nums[1]){
swap(nums,0,1);
}
}
public static void heapAdjust(int[] nums,int start,int length){
if (length == 2){
return;
}
int k = 2 * start + 1;
if (nums[k + 1] > nums[k]){
k++;
}
if (nums[k] > nums[start]){
//交换
swap(nums,start,k);
//交换之后需要重新构建
for (int i = 2 * start + 1; i < length/2-1; i++) {
heapAdjust(nums,i,length);
}
}
}
public static void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
2、为什么要从 length/2-1处开始构建
因为对于一个完全二叉树来说,length/2-1 所对应的节点是 倒数第二层,从右往左 第一个非叶子节点。
看图1
看图2
大家自己可以试下更多的场景,一定是满足 倒数第二层,从右往左 第一个非叶子节点 这个规则的。这个对于大家理解堆排序是至关重要的。
构造堆的循环就是从 倒数第二层,从右往左,从第一个非叶子节点开始,从右往左再往上一层循环 构建的这么一个步骤。
3、堆调整过程中为什么还需要循环
先来看待排序的数组
int[] nums = {7,8,2,9,3,1,90,88,33};
转化成完全二叉树如下图所示
该数组中
经过第一次构建之后, 88 和 9 交换位置 变成
继续排序 8、88、3这三个节点,88和8需要交换
8和88交换之后,8、33、33 不满足规则 nums[i] > nums[2*i+1],所以需要继续交换。这也是
需要这个循环的原因