堆排序

堆排序

前情提要

  1. 堆排序是利用堆这种数据结构而设计的一种算法
  2. 堆是具有以下性质的完全二叉树:
    (1)每个结点的值都大于等于其左右子节点的值,称为大顶堆
    (2)每个结点的值都小于等于其左右子节点的值,称为小顶堆
  3. 采用堆排序时,一般升序使用大顶堆;降序使用小顶堆

基本思想

  1. 将待排序序列构造成一个大顶堆;此时,整个数列的最大值就是堆顶的根节点
  2. 将堆顶元素与末尾元素进行交换,此时末尾元素就成为了最大值,然后将剩余的n-1个元素重新构造成一个堆,这样会得到第n个元素的次小值,如此反复执行,数组将成为一个有序数组。

实现步骤

  1. 将待排序序列构造成一个大顶堆

    (使用for循环,自下向上,自左向右,查找非叶子节点,进行此叶子节点为根节点的树的大顶堆构成,)第一个非叶子节点取法:i=arr.length/2-1,之后逐步减一直至i=0

  2. 此时,数组中最大的数在index=0的位置,将其与数组最后一个元素交换,交换后大顶堆构成被破坏,对前数组长度减一个元素重新进行大顶堆构成,由于只有树的顶部不符合大顶堆构成,故只需要对index=0进行一次大顶堆构成

  3. 循环操做步骤2,从数组的最后一个元素开始,逐步递减,直至数组的第二个元素结束(for(int i=arr.length-1;i>0;i--))。此操作完成后数组将排序完成

  4. 重要步骤:大顶堆如何构成,传入节点i,构造以i为根节点的树的大顶堆:
    (1)获取i的左右子节点,比较拿到最大的
    (2)将拿到的最大子节点与i进行比较,若子节点大于当前节点,值交换,并将当前结点变为i进行下一次循环。否则直接跳出循环。

代码实现

//编写一个堆排序的方法
 //调用对排序方法实现数组的升序排序
    public static void main(String[] args) {
        int[] arr={4,6,8,5,9};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }

public static void heapSort(int[] arr){
    //我们将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆
    for(int i=arr.length/2-1;i>=0;i--){//arr.length/2-1取的是最后一个非叶子节点的节点
        adjustHeap(arr,i,arr.length);
    }
    //交换
    for(int j=arr.length-1;j>0;j--){
        arr[0]=arr[0]^arr[j];
        arr[j]=arr[j]^arr[0];
        arr[0]=arr[0]^arr[j];
        /**
           * 上面的for循环已经将树调整为了大顶堆,
           * 在此次for循环交换中只是破坏了其树的根的元素不符合大顶堆;
           * 因此只需完成i=0时的二叉树调整
           */
        adjustHeap(arr,0,j);
    }
}

//将一个数组(二叉树)调整成一个大顶堆
/**
 *功能:完成将以i为根节点的树的大顶堆实现
 * @param arr:待排序数组
 * @param i:表示非叶子节点在数组中的下标
 * @param length:对多少个元素继续调整,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*i+1){// k=2*i+1:i的左子节点
        if(k+1<length && arr[k+1]>arr[k]){//k+1:i的右子节点;当i的右子节点存在且大于其左子节点时,k++;
            k++;
        }
        if(arr[i]<arr[k]){
            arr[i]=arr[k];
            i=k;
        }else {
            break;//此处可以break的原因:调整树时,是从下向上,从左到右。
        }
        //当for循环结束一次后,我我们已经将以i为父节点的树的最大值跳到了最顶部
        arr[i]=temp;
    }
}

代码实现图解

复杂度与稳定性

稳定性:若数组中出现重复元素,若排序后重复元素还按照源数组中的先后顺序排列,则称之为稳定,否则为不稳定

in-place:不占用额外内存

n:数据规模

排序算法 平均时间复杂度 最好情况 最坏情况 空间复杂度 排序方式 稳定性
堆排序 O(n log n) O(n log n) O(n log n) O(1) In-place 不稳定

posted on 2021-05-03 22:05  凡人精灵  阅读(108)  评论(0)    收藏  举报

导航