简介
- 堆是完全二叉树(对应满二叉树,每个节点的序号一一对应)
- 每个结点都大于或者等于左右子结点的值称为大顶堆
- 每个结点都小于或者等于左右子节点的值称为小顶堆
堆排序是不稳定排序
稳定性问题以后讨论
排序思想(大顶堆),小顶堆类似
- 首先通过要排序数组构造大顶堆(这一步可以将数组的最大值放在数组的首位)
- 交换数组的
首尾
元素 - 数组的
长度减一
继续构造大顶堆,重复2 - 得到由
小到大
排序的数组(大顶堆)
代码分析
构造大顶堆:
start = (arr.length - 2) / 2; 找到第一个非叶子节点(start 在这里表示的都是非叶子节点)
public static void Sort(int[] arr) {
int length = arr.length;
int start = (arr.length - 2) / 2; //从第一个非叶子节点,由下至上
for (; start >= 0; start--) { // 遍历非叶子节点
Adjust(arr, length, start); //构造大顶堆
}
for(int i = arr.length-1 ;i>0 ;i--){ //数组的长度减小,继续构造大顶堆
Swap(arr,0,i); //交换首尾元素()
Adjust(arr,i,0); //继续构造大顶堆
}
}
Sort调用了Adjust()函数
k = k*2+1 的作用是在取的最大值之后(也即是第一次构造完大顶堆)步骤3的过程,从0节点继续往下构造大顶堆
public static void Adjust(int[] arr, int length, int start) {
int temp = arr[start];
int i = start;
for (int k = start * 2 + 1; k < length; k = k * 2 + 1) { // 此时这个的作用应该是首尾交换后从上往下构造大顶堆
if (k < length - 1 && arr[k] < arr[k + 1]) {
//此时如果节点的值大于左节点的值,k++(为右节点的index值) : 找出左右节点的value值最大的节点,将其index保存在key中
k++;
}
if (arr[k] > temp) { //如果arr[start]小于子节点的值,将其更改,i保存子节点的index
arr[i] = arr[k];
i = k; //同时也对向下调整做准备,更新 i (start)的位置
} else {
break;
}
arr[i] = temp; //更改子节点的值
}
}
测试用例
public static void main(String[] args) {
int[] arr = {45, 21, 46, 56, 32, 23, 98};
Sort(arr);
for (int a : arr) {
System.out.print(a + " ");
}
}
排序结果