
向下调整的前提是左右子树必须已经是一个堆才能调整.我们以小堆为例, 如下所示.
其中: array 代表存储堆的数组; size 代表数组中被视为堆数据的个数; index 代表要调整位置的下标; left 代表 index 左孩子下标; right 代表 index 右孩子下标; min 代表 index 的最小值孩子的下标.

关于堆的建立基本思想就是从倒数第一个非叶子节点的子树开始调整, 一直调整到根节点的树, 即为堆.这里我们以大根堆为例.

堆排序的基本思想也是选择排序, 只是不再使用遍历的方式查找无序区间的最大值, 而是通过堆来选择无序区间的最大的数; 还需要注意: 升序排序要建大堆; 降序排序要建小堆.
详细过程如下:

代码如下:
public class SelectSort {
public static void createHeap(int[] arr) {
//从小到大排序 --> 大根堆
for(int i = (arr.length - 1 - 1)/2;i>=0;i--) {
siftDown(arr,i, arr.length);
}
}
public static void siftDown(int[] arr,int root,int len) {
int parent = root;
int child = 2*parent+1;
while (child < len) {
if(child+1 < len && arr[child] < arr[child+1]) {
child++;
}
//child的下标就是左右孩子的最大值下标
if(arr[child] > arr[parent]) {
int tmp = arr[child];
arr[child] = arr[parent];
arr[parent] = tmp;
parent = child;
child = 2*parent+1;
} else {
break;
}
}
}
public static void heapSort(int[] arr) {
createHeap(arr); //O(n)
int end = arr.length - 1;
while (end > 0) { //O(N*LogN)
int tmp = arr[end];
arr[end] = arr[0];
arr[0] = tmp;
siftDown(arr,0,end);
end--;
}
}
public static void main(String[] args) {
int[] arr = {3,2,1,5,8,7,6,4,9};
System.out.println(Arrays.toString(arr));
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
}
运行结果:

性能分析:

直接选择排序比较简单, 每一次排序只能确定一个数值, 因此这里不再进行描述其详细过程.
代码如下:
public class SelectSort {
public static void selectSort(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i+1; j < array.length; j++) {
if (array[j] < array[i]) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
}
}
public static void main(String[] args) {
int[] arr = {3,2,5,7,1,6,8,9,4};
System.out.println(Arrays.toString(arr));
selectSort(arr);
System.out.println(Arrays.toString(arr));
}
}
运行结果:

性能分析:
