堆排序
升序->大顶堆
降序->小顶堆
步骤
(1)构造堆
(2)取下堆顶值,继续构造堆
(3)循环(2)直到堆中剩下最后一个元素,排序完成
构造堆
举例 构造大顶堆
找到最后一个非叶子节点的下标,arr.length/2-1
从右往左,从下往上,构造大顶堆
第一轮
第二轮
第三轮
(1)拿到索引节点的值,存到temp中,比较索引节点的左右孩子,寻找较大的孩子
(2)如果发现左(右)孩子比temp节点值大,就把左(右)孩子的值赋给索引节点
(3)把左(右)孩子当作新的索引节点(双亲节点),比较索引节点的左右孩子,寻找较大的孩子
(4)如果发现左孩子比(temp节点值)大,就把左孩子的值赋给索引节点
(5)。。。重复上面。。。
(n-1)直到孩子索引超过数组长度结束循环
(n)将temp节点值赋值给最后一个孩子索引(结束循环的索引)的双亲节点
取下堆顶值,继续构造堆
交换了对顶元素,大顶堆被破坏,需要从堆顶从上往下修复
代码
package com.tree;
import java.util.Arrays;
/**
* @program: DataStructures
* @description: 堆排序
* @author: XuDeming
* @date: 2020-01-03 09:03:04
*
* 升序->大顶堆
* 降序->小顶堆
**/
public class HeapSort {
public static void main(String[] args) {
int[] arr = {16, 7, 6, 18, 17, 8};
heapSort(arr);
}
public static void heapSort(int arr[]) {
// (1)构造一个大顶堆
// arr.length/2-1 找到最后一个非叶子节点的下标
// 从右往左,从下往上,构造大顶堆
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, arr.length);
}
// (2)将堆顶元素与末尾元素交换,将最大元素"下沉"到末尾
// (3)重新调整堆结构,构造大顶堆,交换...
for (int i = arr.length - 1; i > 0; i--) {
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
// 交换了对顶元素,大顶堆被破坏,需要从堆顶从上往下修复
adjustHeap(arr, 0, i);
}
System.out.println(Arrays.toString(arr));
}
/**
*
* @param arr 待调整数组
* @param parentIndex 双亲节点下标
* @param length 待调整数组长度
*/
public static void adjustHeap(int[] arr, int parentIndex, int length) {
// 获取双亲节点 方便后续比较
int temp = arr[parentIndex];
// 索引指向左孩子下标
int index = parentIndex * 2 + 1;
while (index < length) {
// 获取右孩子下标
int rChildIndex = index + 1;
// 如果有右孩子 且 右孩子比左孩子大
if (rChildIndex < length && arr[rChildIndex] > arr[index]) {
// 索引指向右孩子下标
index = rChildIndex;
}
// 如果孩子节点比双亲节点大
if (arr[index] > temp) {
// 将孩子节点值 赋值 给双亲节点
arr[parentIndex] = arr[index];
// 将孩子节点的下标作为待调整的双亲 继续调整
parentIndex = index;
// 索引指向左孩子下标
index = parentIndex * 2 + 1;
} else { // 双亲节点已经最大
break;
}
}
// 将一开始双亲节点的值赋值给索引节点
arr[parentIndex] = temp;
}
}