堆排序
堆排序是把一组无序数组,构建成一个二叉树形式的堆,有大顶堆和小顶堆两种。每一个根节点都比其子节点大的堆叫大顶堆,这样堆顶的元素就是最大值(对左右子节点的大小顺序无要求),反之则称为小顶堆。
堆排序分为两步,第一步是根据要求构建一个大顶堆,或者小顶堆。第二步,(以大顶堆为例)将堆顶最大 值与堆中最后一位元素位置互换,之后将其取出。这样就得到了该数组的最大值,因为在这个过程中造成了对大顶堆的破坏,就需要对堆重新构建,成为一个大顶堆。之后再重复上述步骤,依次取出第二大、第三大、第四大、第五大、第六大........个元素,之后就得到了一个有序的数组。
int[] arr = new int[] { 89,9,32,5,1,53,63,22,62,26,46,73,74,25 };// 测试数组
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void heapSort(int[] arr) {
for (int i = arr.length - 1; i >= 0; i--) {//根据数组的长度,自下往上,从右到左构建一个大顶堆。
heapBuild(arr, i, arr.length);//调用构建大顶堆的函数
}
for (int i = arr.length - 1; i >= 0; i--) {//
int temp = arr[0];//将堆顶与堆尾的元素调换位置
arr[0] = arr[i];
arr[i] = temp;
heapBuild(arr, 0, i);//调换一次位置后,大顶堆已经不是大顶堆,需要重新构建,但因为交换了堆顶与堆尾
} //的值,这里的根节点可以从堆顶节点开始进行比较,重新构建大顶堆。
}
public static void heapBuild(int[] arr, int parent, int lenght) {
int temp = arr[parent];//将父节点的数值存在temp中
int Child = 2 * parent + 1;//大顶堆的规律,左节点与右节点的物理地址分别为:2 * parent + 1和2 * parent + 1+1;
while (Child < lenght) {//循环条件是子树节点的物理位置小于数组长度。
if (Child + 1 < lenght && arr[Child] < arr[Child + 1]) {//判断该父节点是否有右子树节点,并且左右节点的大小比较
Child++;
}
if (temp >= arr[Child]) {//注意!!!!!!!!!这里的child已经是右节点的物理地址、
break;
}
arr[parent] = arr[Child];//根节点小于子节点,将子节点数换到根节点位
parent = Child;//将子节点位置换到根节点位
Child = parent * 2 + 1;
}
arr[parent] = temp;//如果while循环发生实现,那么这里的arr[parent]=temp存储的性质已经改变为一个子节点。
}
[1, 5, 9, 22, 25, 26, 32, 46, 53, 62, 63, 73, 74, 89]
Process finished with exit code 0