前言
堆包括
- 大根堆:父节点的值都大于其左右孩子的值
- 小根堆: 父节点的值都小于其左右孩子的值
提示:以下是本篇文章正文内容,下面案例可供参考
一、基本思想
按照堆的定义构建起一个堆,那么每次就可以确定一个最大值或最小值(根上),那么将这个值放入数组最后一位,即可排好了一位元素。后续以此缩减范围递归处理。
二、性能分析
- 空间复杂度O(1)
- 时间复杂度O(nlog2n)
- 不稳定排序算法
三、实现代码
调用排序方法:
public void HeapSort(){
System.out.println(Arrays.toString(arr));
// 初始化堆化
MaxHeap(arr,arr.length);
for (int i = arr.length-1; i >=0 ; i--) {
// 将第一个元素(最大的这一个)交换到数组末尾
SwapArraysDoucment.swap(arr,0,i);
// 将交换后的元素继续堆化
MaxHeapFixDown(arr,0,i);
}
System.out.println(Arrays.toString(arr));
}
初始化堆:
public void MaxHeap(int arr [],int len){
// 从len/2+1开始调整 是最后一个非叶子节点 叶子节点可视为已经堆化
for (int i = len/2+1; i >=0; i--) {
// 对该子树进行堆化
MaxHeapFixDown(arr,i,len);
}
}
小顶堆化代码:
private void MinHeapFixDown(int[] arr, int cur_root, int len) {
int left = cur_root*2+1;
int right = cur_root*2+2;
// 找到左右孩子 左右孩子可能会有不同的情况
// 如果该结点是叶子 那么无需处理 也就是递归出口
if(left>=len){
return;
}
// 初始化最小孩子下标为 左孩子
int min =left;
// 有做孩子,没有右孩子的情况 最小孩子下表也初始化为左孩子
if(right>=len){
min = left;
}else {//左右孩子都有的情况
// 对比左右孩子 找到最小的一个
if(arr[right]<arr[left]){
// 确定了最小的一个孩子
min = right;
}
}
// 如果最小孩子的值比父节点还要小 那么交换
if(arr[cur_root]>arr[min]){
// 交换根节点的元素和最小的一个的孩子的位置
SwapArraysDoucment.swap(arr,cur_root,min);
// 并且递归处理最小一个孩子的位置
MinHeapFixDown(arr,min,len);//min的下标是不断变化的 为递归增量
}
}
大顶堆化代码同理:
private void MaxHeapFixDown(int[] arr, int cur_root, int len) {
// 找到左右孩子 左右孩子可能会有不同的情况
int left = cur_root*2+1;
int right = cur_root*2+2;
// 没有孩子
if(left>=len){
return;
}
int max =left;
if(right>=len){
// 没有右孩子
max = left;
}else {
// 对比左右孩子 找到最大的一个
if(arr[right]>arr[left]){
// 确定了最大的一个孩子
max = right;
}
}
// 交换根节点的元素和最小的一个的孩子的位置
if(arr[cur_root]<arr[max]){
SwapArraysDoucment.swap(arr,cur_root,max);
// 并且递归处理最小一个孩子的位置
MaxHeapFixDown(arr,max,len);
}
}
总结
本文记录了复习堆排序的一些过程。