一切解说尽在注释中,超级详细,超级容易理解
package protect;
import static Sort.tools.swap;
public class Heap01 {
/**
* 排序的思想:作为大根堆,首元素必然是最大的元素(没有比它大的),末尾元素必然是最小的元素(没有比他小的)
* 所以可以直接将首末元素进行交换,这样最为一个升序数组的最后一个元素就排好了,可以不用管它了,所以--heapSize,访问不到该数据
* 此时的堆是首节点是最小的,所以应该进行调整,使其重新成为大根堆
* 重复以上过程,最终堆就会成为一个升序的数组
* @param arr
*/
public static void heapSort(int[] arr) {
//如果说数组的长度不符合条件就直接return,没有必要进行排序
if(arr.length < 2 || arr == null) {
return;
}
//先将数组弄成大根堆
for(int i = 0;i < arr.length;i++) {
heapify(arr,i,arr.length);
}
//将堆的长度设置成数组的长度
int heapSize = arr.length;
//首先交换堆的首末位置的元素
swap(arr,0,--heapSize);
//只要堆的长度大于0就执行循环
while(heapSize > 0) {
heapify(arr,0,heapSize);
swap(arr,0,--heapSize);
}
}
public static void heapInsert(int[] arr,int index) {
//只要index位置的数值大于其父节点,就执行循环
while(arr[index] > arr[(index - 1) / 2]) {
swap(arr,index,(index - 1) / 2);//交换两个结点的值
index = (index - 1) / 2;//调整index向上
}
}
/**
* 判断index位置的数是否需要向下移动
*
* @param arr 待排序的数组
* @param index 从index下标的位置开始做调整
* @param heapSize 堆的长度
*/
public static void heapify (int[] arr,int index,int heapSize) {
int left = 2 * index + 1;//表示index位置的左子节点的下标
while (left < heapSize) {//只要index处的数值所在的位置有左子节点就继续循环
//第一次bigger记录的是index位置的数值左右子节点的较大值的下标
int bigger = left + 1 > heapSize && arr[left] > arr[left + 1] ? left : left + 1;
//第二次bigger记录的是index位置和其左右子节点的较大值的下标
bigger = arr[bigger] > arr[index] ? bigger : index;
//如果是index位置的值比较大就不用调整,直接退出循环
if(bigger == index) {
break;
}
//否则就是需要将index位置的数值向下调整
swap(arr,bigger,index);
//以此类推,继续向下比较
index = bigger;
left = 2 * index + 1;
}
}
}