经典排序算法——堆排序——Java实现及算法解析

本文介绍了堆排序的基本概念,包括最大堆和最小堆的定义。堆排序是一种时间复杂度为O(nlogn)的排序算法,通过构建和调整最大堆来实现。文章详细讲解了Java代码实现堆排序的思路,包括构建最大堆和沉降法调整的过程,并给出了完整的Java代码示例。
摘要由CSDN通过智能技术生成


一、前言

1. 什么是堆?

堆是一种重要的数据结构,它是一种完全二叉树。堆分为最大堆和最小堆,最大堆任意子树根节点不小于任意子结点,即每一个父节点一定大于其两个左右子节点;最小堆则与之相反,最小堆的根节点不大于任意子结点。底层如果用数组存储数据的话,假设某个元素为序号为 i (Java数组从0开始,i为0到n-1),如果它有左子树,那么左子树的位置是2i+1,如果有右子树,右子树的位置是2i+2,如果有父节点,父节点的位置是(n-1)/2 向下取整。
两种类型的堆的示意图

2. 堆排序的概念

所谓堆排序就是利用堆这种数据结构的性质来对数组进行排序,在数组的非降序排序中,需要使用的就是最大堆,因为根据最大堆的性质可知,最大的值一定在堆顶。堆排序一种不稳定的排序算法,其时间复杂度为O(nlogn)

堆排序其实也是一种选择排序,是一种树形选择排序。只不过直接选择排序中,为了从 R[1···n] 中选择最大记录,需比较 n-1 次,因此 n 次交换时间复杂度为O(n)。以大顶堆升序排序为例,每次将堆顶值沉入到底部并且重新构建大顶堆的时间复杂度为O(log2n)。因此堆排序的整体时间复杂度为O(nlogn)。

二、堆排序的Java代码实现

1. 算法思想

  • (1)构建最大堆;
  • (2)选择顶,并与第0位置元素交换,堆长度减 1;
  • (3)由于步骤(2)的的交换可能破环了最大堆的性质,即第0位置的元素不再是最大元素,则需要重新调整堆maxHeap(沉降法,下面会针对代码部分详细讲解),根据实际情况重复步骤(2),直至堆列表长度为 0 ,即升序排序完成。

堆排序中最重要的算法就是maxHeap,该函数假设一个元素的两个子节点都满足最大堆的性质(即左、右子树都是最大堆),只有根元素可能违反最大堆性质,那么把该元素以及左右子节点的最大元素找出来,如果该元素已经最大,那么整棵树都是最大堆,程序退出,否则交换根元素与最大元素的位置,继续调用maxHeap构建最大元素所在的子树。

2. Java代码解析

我们根据排序思路,逐步解析代码过程(完整代码在后面)。首先我们要根据输入的初始化序列,使得我们的堆结构成为最大堆。代码从堆最后一个非叶子结点( i = arr.length/2-1 )开始从下至上,从右至左调整堆结构,调整结构方法即为maxHeap方法。例如下图中堆,即从 index 为 9 / 2 - 1 = 3 的位置开始调整以 index = 3为顶的子树,将最大值升到顶部。
在这里插入图片描述
部分代码(构建大顶堆):

		//1.构建大顶堆
        for(int i = arr.length/2-1; i >= 0; i--){
   
            //从堆最后一个非叶子结点从下至上,从右至左调整结构
            maxHeap(arr, i, arr.length);
        }

从 i = arr.length/2-1 节点开始,调用maxHeap方法,升降堆中的值调整堆结构。

  public static void maxHeap(int[] arr, int i, int length){
   
      int temp = arr[i];
      for(int k = i*2 +1; k < length; k = k*
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值