数据结构 ----- 堆排序

​​​​

堆排序

活动地址:CSDN21天学习挑战赛

一、堆排序

1.1 概念

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。
堆是一种树形选择排序方法,它的特点是将一个序列看成是一个二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的位置关系在无序区中选择关键字最大(或最小)的元素;

1.2 查找过程
  • 下面是一个大根堆的建立过程;
  • 首先找到第一个非叶子结点,将其单独看成一颗二叉树,再与其两个孩子结点进行对比,如果孩子结点比它大,则将最大的孩子结点跟它进行交换位置;
  • 当前子树排序完毕后,再寻找下一个非叶子结点继续排序,直到整颗树的非叶子都进行了排序,则第一趟排序结束;
  • 堆排序的排序有可能进行一趟就排序完毕,但是最差情况下需要进行 ( log₂ N )+ 1 次排序,因为最差情况下可能每趟排序只能将一层元素放置在其最终的位置;( N 为 非叶子结点的个数 ,前面的层数有序了,最后一层也自然会有序了 )

在这里插入图片描述

图 1.1
1.3 代码演示
1.3.1
  • 首先建立一个数组存储待排序的序列;
  • 建立一个变量存储最大非结点的坐标位置,因为数组的坐标是从 0 开始的,所以寻找最大非叶子结点坐标的时候需要用长度减去 1 再除 2 ( 堆顶坐标为 1 的时候,所有结点的左孩子结点等于 2 倍自身坐标值,右孩子坐标等于 2 倍自身坐标值 + 1 );
  • 建立一个变量确定除叶子结点外的层数,因为完全二叉树的层数等于( log₂ N )+ 1( N 结点数 ),又因为 num 为最大非叶子结点的坐标,故除叶子结点外的层数等于 ( log₂ num+1 )+ 1;
  • 确定了层数就确定循环次数,再在循环内写入排序的方法,排序的方法有两个参数,一个是待排序的数组,一个是排序的起始位置( 也就是第一个非叶子结点 );

在这里插入图片描述

图 1.2
1.3.2
  • 建立一个变量存储数组的长度;
  • 建立一个循环遍历每一个非叶子结点;
  • 建立一个变量存储当前子树的最大结点的坐标,赋初值为父结点坐标;
  • 建立两个变量分别存储该子树的左右孩子结点坐标( 因为用数组存储,数组初始坐标为 0 ,故计算左孩子坐标时为 i * 2 + 1 ,而右孩子就在左孩子的右边一个单元故右孩子坐标为左孩子坐标 + 1 );

在这里插入图片描述

图 1.3
1.3.3
  • 如果左孩子坐标未超出最大坐标并且左孩子的值大于所存储结点的值,那么将左孩子的坐标拷贝至存储最大元素坐标的辅助空间;
  • 如果右孩子坐标未超出最大坐标并且左孩子的值大于所存储结点的值,那么将右孩子的坐标拷贝至存储最大元素坐标的辅助空间;
  • 如果存储最大元素坐标的辅助变量被改变过,那么将所记录的坐标的值跟父结点的值进行交换;
  • 至此堆排序功能已完成;

在这里插入图片描述

图 1.4
1.3.4
  • 除了上述确定循环次数的方法,还有利用递归的方法;
  • 首先在方法传值时增加一个传入最大需要遍历到的树顶坐标;

在这里插入图片描述

图 1.5
  • 再在判断是否需要交换的语句末尾增加一条递归,递归时将当前子树树顶作为最大遍历到的结点,受更改的结点作为起始遍历坐标;

![在这里插入图片描述](https://img-blog.csdnimg.cn/a1de1341f37844808fc03aeba7cb2869.png

图 1.6
1.4 代码分享
1.4.1 确定循环法
public class test {

    public static void main(String[] args){
        int[] arr = { 8 , 14 , 25 , 16 , 24 , 17 ,28 };
        int num = (arr.length - 1) / 2;
        int n = (int)(Math.log( num + 1 ) / Math.log( 2 )) + 1;
        for (int i = 0; i < n; i++) {
            heapsort( arr , num );
        }
        for ( int e : arr ) {
            System.out.print( e + " " );
        }
    }

    public static void heapsort( int[] arr , int num ) {
        int len = arr.length;
        for (int i = num; i >= 0; i--) {
            int max = i;
            int left = i * 2 + 1;
            int right = left + 1;
            if ( left < len && arr[left] > arr[max] )
                max = left;
            if ( right < len && arr[right] > arr[max] )
                max = right;
            if ( max != i ){
                int temp = arr[i];
                arr[i] = arr[max];
                arr[max] = temp;
            }
        }
    }
}
1.4.2 递归法
public class test {

    public static void main(String[] args){
        int[] arr = { 8 , 14 , 25 , 16 , 24 , 17 ,28 };
        int num = (arr.length - 1) / 2;
        int n = (int)(Math.log( num + 1 ) / Math.log( 2 )) + 1;
        heapsort( arr , 0 , num );
        for ( int e : arr ) {
            System.out.print( e + " " );
        }
    }

    public static void heapsort( int[] arr , int n , int num ) {
        int len = arr.length;
        for (int i = num; i >= n; i--) {
            int max = i;
            int left = i * 2 + 1;
            int right = left + 1;
            if ( left < len && arr[left] > arr[max] )
                max = left;
            if ( right < len && arr[right] > arr[max] )
                max = right;
            if ( max != i ){
                int temp = arr[i];
                arr[i] = arr[max];
                arr[max] = temp;
                heapsort( arr , i , temp );
            }
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jc_caterpillar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值