一、将任意数组调整为堆
如何将任意数组调整为最大堆?
1.1
思路:遍历原数组,依次调用add(内部进行siftUp操作)向堆中插入元素,整个数组就变为最大堆。
时间复杂度:O(nlogn)
1.2heapify操作
从最后一个非叶子节点开始,进行元素下沉操作,直到向上走到根节点即可。
时间复杂度:O(n)+O(nlogn)
空间复杂度:O(n)
二、堆排序
原地堆排序:从最后一个非叶子结点开始
时间复杂度:O(nlogn)
空间复杂度:O(1)
步骤:
1.将任意数组heapify,调整为最大堆
2.将堆顶元素和尾部元素进行交换
/**
* 将任意数组进行原地堆排序
* @param arr
*/
public static void heapSort(int[] arr) {
// 1.将任意数组调整为最大堆
// 从最后一个非叶子节点开始
for (int i = (arr.length - 1 - 1) / 2; i >= 0; i--) {
siftDown(arr,i,arr.length);
}
// 依次将堆顶元素和最后位置元素交换
// 最开始待排序数组[0...arr.length - 1] 已排序的数组[]
// 交换一个之后 [0...arr.length - 2] [arr.length- 1]
// 交换第二个值之后 [0..arr.length - 3] [arr.length - 2,arr.length - 1]
// 此处终止条件不用写i = 0 ,当整个待排序数组就剩一个元素时,其实整个数组已经有序
for (int i = arr.length - 1; i > 0; i--) {
swap(arr,0,i);
siftDown(arr,0,i);
}
}
/**
* 元素下沉操作
* @param arr
* @param i
* @param n 当前arr中有效的元素个数
*/
private static void siftDown(int[] arr, int i, int n) {
// 仍然存在子树
while ((2 * i) + 1 < n) {
int j = 2 * i + 1;
// 右孩子存在且大于左子树值
if (j + 1 < n && arr[j + 1] > arr[j]) {
j = j + 1;
}
// j对应的下标就是左右子树的最大值
if(arr[i] >= arr[j]) {
break;
}else {
swap(arr,i,j);
i = j;
}
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}