经典排序之堆排序
堆排序思路
堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:
大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;
二叉树的性质
已知父节点的下标,可以获取其子节点的下标
父节点下标为 i
左子树下标为 i x 2 + 1
右子树下标为 i x 2 + 2
例: i = 1 左为3 右为4
同理知道左右子树可以知道父节点下标。
思路
根据大顶堆可以知道,root节点大于所有节点为最大,那么我们可以将其移动数组最后一位,然后将 [0, n-1] 进行堆的构建 循环调用
代码展示
public int[] sortArray(int[] arr) {
int len = arr.length;
// 初始化构建
buildMaxHeap(arr, len);
// 构建之后 0下标为数组最大值,for循环从最后一位开始,交换 然后重新构建
for (int i = len - 1; i > 0; i--) {
swap(arr, 0, i);
len--;
heapify(arr, 0, len);
}
return arr;
}
// 对半构建
private void buildMaxHeap(int[] arr, int len) {
for (int i = len >> 1; i >= 0; i--) {
heapify(arr, i, len);
}
}
private void heapify(int[] arr, int i, int len) {
// len 为本次构建堆的数组长度
// 获得父节点 左子树,右子树 下标位置
int left = 2 * i + 1;
int right = 2 * i + 2;
int largest = i;
// 左子树下标小于 数组长度 并且 左子树的值大于父节点 则改变largest 标识位
if (left < len && arr[left] > arr[largest]) {
largest = left;
}
// 右子树与左子树相同
// 这里如果左子树时已经改变 则比较左右子树大小
if (right < len && arr[right] > arr[largest]) {
largest = right;
}
// 如果父节点标识为发生改变,则将标识为指向的位置与父节点进行交换,并重新构建
if (largest != i) {
swap(arr, i, largest);
// 现在发生改变,则查看改变之后的位置的变化
heapify(arr, largest, len);
}
}
private void swap(int[] arr, int i, int j) {
int next = arr[i];
arr[i] = arr[j];
arr[j] = next;
}

浙公网安备 33010602011771号