1. 堆排序基本介绍
- 堆排序是利用堆这种数据结构而设计的算法,堆排序是一种选择排序。
- 堆是一个完全二叉树。
- 每个结点的值都大于等于其左右子孩子结点的值,被称为大顶堆。
- 每个结点的值都小于等于其左右子孩子结点的值,被称为小顶堆。
- 一般升序采用大顶堆,降序采用小顶堆。
- 堆的基本作用是:快速找到集合中的最值
2. 存储方式
上图以小顶堆为例,使用数组保存二叉树结构,用层序遍历将二叉树的节点值放到数组中(顺序存储二叉树)。
讲解的时候是在二叉树上观察各个结点的关系,实际上堆排序将数据放到数组中,进行的排序
3. 下标关系
- 已知双亲(parent)的下标,则:
- 左孩子(left)下标 = 2 * parent + 1
- 有孩子(right)下标 = 2 * parent + 2
- 已知孩子(不区分左右)(child)下标,则:
- 双亲(parent)下标 = (child - 1) / 2;
其中下标值指的是在数组中的下标值
4. 代码
package tree;
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int[] arr = {4,6,8,5,9};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
// 堆排
public static void heapSort(int[] arr){
createHeap(arr); // 因为传进来的二叉树不一定是正确的大顶堆,必须先将堆调整为大顶堆 —— 因为我们要做的是升序,所以是大顶堆
for(int i = 0; i < arr.length - 1; i++){
swap(arr,0,arr.length - 1 - i);
shiftDown(arr, 0, arr.length - i - 1);
}
}
private static void createHeap(int[] arr) {
for(int i = (arr.length - 1) / 2; i >= 0; i--){
shiftDown(arr, i, arr.length);
}
}
/**
*
* @param arr 存储堆的数组 —— 要进行调整的二叉树 / 数组
* @param index 要调整位置的下标
* @param length 数组的长度
*/
private static void shiftDown(int[] arr, int index, int length) {
int left = index * 2 + 1; // 当前结点的左子结点下标
// 要比较左子节点是否存在
// 因为堆这个数据结构是完全二叉树 —— 如果左子节点不存在,那么就一定没有右子节点
while(left < length){
int right = index * 2 + 2; // 当前结点的右子节点下标
int max = left; // 比较左子节点的值 和 右子节点的值,比较得出两者中较小的那一个值
if(right < length) {
if (arr[left] < arr[right]) {
max = right;
}
}
// 比较当前结点的值 和 它的左右子节点中较小的那一个
// 如果 当前结点 比较小,那么需要将较小的那个结点,提到前边来
if(arr[index] >= arr[max]){
break;
}
swap(arr, index, max);
index = max;
left = 2 * index + 1;
}
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}