思路
这个代码还不错
https://blog.csdn.net/weixin_51609435/article/details/122982075
就是从下往上进行调整
1. 如何将数组映射成树
对于下面这颗树,原来的数组是:
好,如果调整的话,我们第一个应该调整的是最下边,最右边的树,即
5 2 1 根是 5 看看左右孩子有没有比他大的,我们在上边数组中如何确定第一个子树先找5 2 1 呢,
首先可以看一下下面的文章,介绍数组和树映射的
https://blog.csdn.net/qq_44993268/article/details/131452785
我们可以确定的是
这个小树的root 的index = 4 left = 9 right = 10
即 left = 2 * root +1
right = 2 * root +2;
我们现在知道的是数组的长度len,知道最后一个元素last = len-1(数组从0开始)
所以 如果我们设 第一个应该排序的子树即最下最右的子树的根为x
如果len是偶数,则最后一个在左边,即
len-1 = 2* x +1;
x=(len-2)/2
如果len是奇数,则最后一个在右边,即
len-1 = 2* x +2;
x=(len-3)/2
但是我们发现,就是不管奇数还是偶数,都可以用x=(len-2)/2这个来计算
这样我们就找到第一个需要调整的子树,下一个的话就是x-1(自己对着上边的树模拟)
bug
len-- 是下一行才起作用!
还有一个易错点,是 怎么判断三个数的大小,怎么找到三个数中最大的
代码
import java.util.Arrays;
public class HeapSortTest {
public static void main(String[] args) {
int[] arrary = {9,5 ,6,3,5,3,1,0,96,66};
heapSort(arrary);
System.out.println(Arrays.toString(arrary));
}
public static void heapSort(int[] nums){
int len = nums.length;
for (int i = (len-2)/2; i >=0 ; i--) {
heapAdjust(i, nums, len);
}
while (len >1){
int temp = nums[0];
nums[0] = nums[len-1];
nums[len-1] = temp; //最后一个
heapAdjust(0, nums,--len);
System.out.println(Arrays.toString(nums));
}
}
// start 需要调整的子树的根
// len 是目前需要调整的数组的长度
private static void heapAdjust(int start, int[] nums, int len) {
for (int i = start; i < len;) {
//左孩子右孩子都有
if (i*2+1 < len && i*2+2 < len){
if (nums[i] >= nums[i*2+1] && nums[i] >= nums[i*2+2]){
return;
} else if (nums[i] >= nums[i*2+1] && nums[i] < nums[i*2+2]) {
//右孩子大
int temp = nums[i*2+2];
nums[i*2+2] = nums[i];
nums[i] = temp;
i = i*2+2;
} else if (nums[i*2+2] < nums[i*2+1]){
int temp = nums[i*2+1];
nums[i*2+1] = nums[i];
nums[i] = temp;
i = i*2+1;
}else {
int temp = nums[i*2+2];
nums[i*2+2] = nums[i];
nums[i] = temp;
i = i*2+2;
}
} else if (i*2+1 < len) { //只有左孩子
if (nums[i] >= nums[i*2+1]){
return;
}else {
int temp = nums[i*2+1];
nums[i*2+1] = nums[i];
nums[i] = temp;
i = i*2+1;
}
}else { //左右孩子都没有
return;
}
}
}
}