排序算法Java实现——堆排序

一、基本思路

堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

基本思路:‘将待排元素构造成一个大顶堆,此时整个序列的最大值是堆顶的根节点,将其与末尾元素进行交换,此时末尾就为最大值,然后将剩余n-1个元素重新构造成一个堆,这样会得到n-1个元素的次小值,反复执行,便能得到一个有序序列。

**简单来说:**就是循环执行两步:一、构造大顶堆;二、将根节点元素与末尾元素交换

**举例:**有一序列为:4,6,8,5,9要求按照升序排列
假定初始结构为:
在这里插入图片描述

  1. 构造大顶堆
    1. 找到第一个非叶子节点,arr.length/2-1=5/2-1=1,也就是6,由于[6,5,9]中,9最大,所以6和9交换。
      在这里插入图片描述
    2. 找到第二个非叶子节点4,由于[4,8,9]中,9最大,所以4和9交换。
      在这里插入图片描述
    3. 此时发现子根[4,5,6]结果混乱,所以继续调整,由于[4,5,6]中,6最大,所以4和6交换.
      在这里插入图片描述
      此时就构造成了一个大顶堆。
  2. 将堆顶元素与末尾元素交换,使末尾元素最大。
    在这里插入图片描述
  3. 此时在除去9的n-1个元素中,循环执行1、2步操作,知道得到一个有序序列。
    在这里插入图片描述

二、算法分析

时间:

  1. 构建堆:
    设元素个数为n,则堆的高度k=log(n+1)≈log n,非叶子结点的个数为2^(k-1)-1
    假设每个非叶子结点都需要进行调整,则第i层的非叶子结点需要的操作次数为k-i,
    第i层共有2(i-1)个结点,则第i层的所有结点所做的操作为k*2(i-1)- i*2^(i-1),
    共k-1层非叶子结点,总的操作次数为  
    在这里插入图片描述
    化简可得,上式=2^k-k+1,将k=log(n+1)≈log n代入,得n - log n +1,
    所以,初始化堆的复杂度为O(n)
  2. 调整堆:
    假设根节点和排在最后的序号为m的叶子结点交换,并进行调整,那么调整的操作次数 = 原来m结点所在的层数 = 堆的高度(因为m结点在堆的最后)= log m
    共n个结点,调整的总操作次数为
    在这里插入图片描述
    化简可得,上式=log (n-1)! ≈ nlog n
    所以,调整堆的复杂度为O(n
    log n)

所以,总体复杂度为O(n*log n)
**空间:**可以看到,堆排序的元素构建堆以及调整堆都是在序列上直接进行的,无需另外开辟空间,所以空间复杂度为O(1)。

算法平均时间最好情形最差情形稳定度空间复杂度备注
堆排序O(n l o g 2 n {log_2{n}} log2n)O(n l o g 2 n {log_2{n}} log2n)O(n l o g 2 n {log_2{n}} log2n)不稳定O(1)

三、代码实现

import java.util.Arrays;
/**
 * @author dankejun
 * @create 2020/9/910:21
 */
public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {4, 6, 8, 5, 9};
        heapSort(arr);
    }

    //堆排序方法
    public static void heapSort(int[] arr) {
        int temp = 0;
        System.out.println("堆排序");

//        adjustHeap(arr,1,arr.length);
//        System.out.println("第一次:" + Arrays.toString(arr));
//
//        adjustHeap(arr,0,arr.length);
//        System.out.println("第二次:" + Arrays.toString(arr));
        //调整为大顶堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjustHeap(arr,i,arr.length);
        }

        for (int j = arr.length - 1; j > 0; j--) {
            temp = arr[j];
            arr[j] = arr[0];
            arr[0] = temp;
            adjustHeap(arr,0,j);
        }

        System.out.println("数组:" + Arrays.toString(arr));

    }

    //将数组调整为大顶堆

    /**
     * 将以i对应的非叶子节点的树调整成大顶堆
     * @param arr 待调整的数组
     * @param i 表示非叶子节点在数组中的索引
     * @param length 表示对多少个元素进行调整,逐渐减少
     */
    public static void adjustHeap(int[] arr, int i, int length) {
        int temp = arr[i];
        for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {
            if (k + 1 < length && arr[k] < arr[k + 1]) {
                k++;
            }
            if (arr[k] > temp) {
                arr[i] = arr[k];
                i = k;
            } else {
                break;
            }
        }
        arr[i] = temp;
    }
}

测试序列: int arr[] = {4, 6, 8, 5, 9};
测试结果:
测试结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值