十-4, 堆排序及其Java实现
前置知识:
堆:可以把堆看做一棵顺序存储的完全二叉树,这棵树满足,所有的子结点都不大于或不小于其父结点。
大顶堆:每个结点皆大于或等于其左右孩子结点; 一般升序采用大顶堆;
小顶堆:每个结点皆小于或等于其左右孩子结点; 一般降序采用小顶堆;
- 由于完全二叉树的性质(只有最下面两层结点度小于2,并且最下一层叶结点集中在靠左的位置上),使得堆很容易用数组来表示,每个节点对应数组的一个元素, 拿上图一大顶堆为例得到下图.
-
在数组地址从0开始时,所以我们可以从一个节点的下标i,得出这个节点的父节点下标为
i/2-1 向下取整
,这个节点的左孩子节点下标为2i+1
,右孩子节点下标为2i+2
, -
比如上图中, 40结点下标为2, 它的左孩子结点为 2i+1=5 即是35, 它的右孩子结点为 2i+2 =6 即是30.
-
若下标从1开始,则某个节点的父节点下标为
向下取整 i/2
,左孩子节点为2i
,右孩子节点为2i+1
稳定性:不稳定
在堆的调整过程中,比较和交换所走的是该结点到叶子结点的一条路径,对于相同关键字的结点,可能会出现排在后面的关键字被交换到前面的情况;
原理演示:
基本思想:
- 将待排序列构造成一个大顶堆;
- 此时, 整个序列的最大值就是堆顶的根节点;
- 将其与末尾元素进行交换, 此时末尾就是最大值;
- 然后将剩余的n-1个元素重新构造成一个堆, 这样会得到n个元素的次小值, 如此反复执行, 便能得到一个有序序列了;
- 可以看到在构建大顶堆的过程中, 元素的个数逐渐减少, 最后得到一个有序的序列了.
*注:优先队列一般使用最小堆。
Java实现的具体步骤
- 首先我们需要一个调整堆为大顶堆或小堆顶的方法(adjustHeap(int[] arr, int length)), 在这个方法中一定要有的参数是,
存放堆的数组 arr
, 以及数组的长度length
, 为什么一定需要传入数组的长度呢? 因为每调整好一次堆, 我们就使用2中的方法, 把堆顶的元素(根节点)跟堆的最后一个结点进行了交换, 这些元素算是已经有序了的, 所以在这个过程中堆中的待排元素是慢慢减少了的; - 我们还需要的一个方法是取出堆顶的元素(根节点)跟数组的尾部元素进行交换的反复 headpSort(int[] arr)
- 此外, 也切记要写一个数组中的两个元素进行交换的方法 arrSwap(int[] arr, int index1, int index2);
代码示例:
package DataStrcture.SortAlgorithmsDemo;
import java.util.Arrays;
public class HeapSort_copy {
/**
* 堆排序
* 1.先调整堆, 每次交换出一个元素后都要进行堆的调整, 或大顶堆, 或小顶堆
* 2. 当调整为大顶堆(升序)或者小顶堆(降序), 把堆顶元素与堆中的最后一个元素进行交换.
* 3. 每调整一次就交换一次, 最终整个序列都是有序的了
*/
//程序结构
// 1. 调整大顶堆/小顶堆的adjustHeap()
//2. 把堆顶(根节点)结点交换到数组末尾的方法
//3. 数组元素交换的工具方法
//1
/**
*
* @param arr 待排数组(动态变化的, 去掉了末尾已经排好序的元素)
* @param length 长度为arr.length-已排好序的元素个数
*/
public static void adjustHeap(int[] arr, int length) {
//对树中的非叶结点进行交换操作
for (int i = length / 2 - 1; i >= 0; i--) {
//找出非叶结点的左子节点2*i+1
int k = 2 * i + 1;
// 如果左子节点小于右子节点, 则k更新
//
if (k + 1 < length && arr[k] < arr[k + 1]) {
k++;
}
//比较非叶结点和左/右子节点
if (arr[i] < arr[k]) {
swapArr(arr, i, k);
}
}
}
// 交换元素到数组的尾部
public static void heapSort(int[] arr) {
for (int i = arr.length; i > 1; i--) {
adjustHeap(arr, i);
swapArr(arr, 0, i - 1);
}
}
public static void swapArr(int[] arr, int index1, int index2) {
int temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
//测试方法
public static void main(String[] args) {
int[] arr = {4, 6, 8, 5, 9, 10, 3};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤