堆排序的思路:将要排序的数组先构成一个大顶堆(此时除了顶点,其他还是乱序的),将第一个元素与最后一个元素交换,再对n-1个元素堆排序,依次类推就能构成一个从小到大的数组
package cn.stu.test;
import java.util.Arrays;
public class HeadSort {
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/**
* 对第k个元素进行堆排序
* @param arr
* @param k
* @param length需要排序的数组的长度,随着不断地将第一个元素移到数组后面,这个长度会逐渐变小
*/
public static void headSortNumber(int[] arr, int k, int length) {
int i = (length + 1) / 2 - 1;
while (k <= i) {
int t = k * 2 + 1;
if (t + 1 <= length && arr[t] < arr[t + 1]) {//如果左子结点小于右子结点,k指向右子结点
t += 1;
}
if (arr[k] > arr[t])//如果子节点小于父节点,直接跳过
break;
swap(arr, k, t);
k = t;
}
}
public static void headSort(int[] arr) {
//构建一个堆
for (int j = arr.length / 2 - 1; j >= 0; j--) {
headSortNumber(arr, j, arr.length - 1);
}
//进行堆排序
for (int j = arr.length - 1; j > 0; j--) {
swap(arr, j, 0);
headSortNumber(arr, 0, j - 1);
}
}
public static void main(String[] args) {
int[] arr = new int[] { 43, 22, 21, 23, 67, 54, 78, 92, 34, 11, 36 };
System.out.println(Arrays.toString(arr));
System.out.println("************************************");
headSort(arr);
System.out.println(Arrays.toString(arr));
}
}
优化:headSortNumber每次执行的时候,频繁的交换操作会降低执行效率,我们可以采用替代交换为赋值。
public static void headSortNumber(int[] arr, int k, int length) {
int i = (length + 1) / 2 - 1;
int temp = arr[k];
while (k <= i) {
int t = k * 2 + 1;
if (t + 1 <= length && arr[t] < arr[t + 1]) {
t += 1;
}
if (temp > arr[t])
break;
arr[k] = arr[t];
k = t;
}
if(temp != arr[k]){
arr[k] = temp;
}
}
总结:堆排序是一种不稳定的排序方式,执行效率是O(nlogn),借用堆的结构,巧妙地进行排序。重点要理解堆排序时,子节点和父节点的关系。
注意:
- 可以借用笔纸演算来帮助理解堆排序的过程
- 涉及数组的时候要注意防止数组越界