排序算法-堆排序

1.堆排序(以大顶堆为例)
  (1).堆排序简介:
  堆排序是一个时间复杂度为O(nlog2n)(初始化堆的次数n(几个排序的数字初始化堆几次) × 建堆的过程 log2n(找最大数字的过程))、空间复杂度为O(1)(排序过程并不需要新的空间来存储数据)以及非稳定(建堆的过程可能会改变两个相同数字的相对位置)的排序算法。
  (2).堆排序对数据结构的要求:
  堆排序在排序过程中必须维护一个完全二叉树.我们使用数组来模拟堆,并以下标的方式来构建父节点与子节点存在的物理关系。
  (3).堆排序详解
  ①建立初始堆:从最后一个非叶子节点的父节点开始(计算方式:(数组的长度 - 1 / 2 )- 1),当前父节点与两个子节点进行大小比较,最大的节点应被交换到父节点位置,这一比较过程应从最后一个父节点到根节点,所以是自下而上的。
  ②构造顺序序列:把当前根节点的值和最后一个叶子节点进行交换,这时数组长度减一(叶子节点减一),因为已交换的数字已经排序过。交换过后的堆已不满足大顶堆,因为根节点的值已不是最大值,所以这时的比较操作是从根节点到最后一个父节点,这是一个自上而下的过程。这样的构造排序的过程应维持到仅仅只有最后一个根节点。
  (4).堆排序代码(Java):

/**
 * @author Cookie
 * @Project: DataStructuresAndAlgorithms
 * @Package:sort
 * @date 2019/6/23 12:34
 * @description 堆排序
 **/
public class HeapSort {
    public int[] sort(int[] array){
        if (array == null || array.length < 1){
            return null;
        }
        //第一步应建立初始堆,这是唯一一个自下而上的过程
        buildHeap(array);
        int length = array.length;
        //第二步是构造顺序序列的过程,并且应该不停的构建大顶堆,直到仅剩一个根节点
        while (length > 1){
            //构建顺序序列
            swap(array,0,length - 1);
            //数组长度减一(当前叶子是已排序的节点,所以应该减去)
            length--;
            //构建大顶堆
            heapfy(array,0,length);
        }
        return array;
    }

    //构建堆
    private void heapfy(int[] array, int start, int length) {
        //对于最开始的建堆来说,只是比较当前父节点与其左右子节点的值
        //对于后续交换根节点之后从根节点开始自上而下的比较时,就需要将根节点值一直进行比较直到它到合适的位置
        while (true){
            //当前父节点的左子节点,如果根节点是从下标1开始的,那么左子节点为 2 * start,如果根节点是从下标0开始的,那么左子节点为 2 * start + 1.
            int left = 2 * start + 1;
            //当前父节点的右子节点,如果根节点是从下标1开始的,那么右子节点为 2 * start + 1,如果根节点是从下标0开始的,那么右子节点为 2 * start + 2.
            int right = 2 * start + 2;
            //当前被交换后节点的最大值
            int maxPosition = start;
            if (left < length && array[left] > array[maxPosition]){
                maxPosition = left;
            }
            if (right < length && array[right] > array[maxPosition]){
                maxPosition = right;
            }
            //说明父节点本身是或经过交换后已经是最大值,所以不需要再次进行交换
            if (maxPosition == start){
                break;
            }else {
                int temp = array[maxPosition];
                array[maxPosition] = array[start];
                array[start] = temp;
                //这一步对于自上而下的构建来说相当重要,这会将比较操作继续进行下去直到越界或者已满足堆的条件
                start = maxPosition;
            }
        }
    }

    //交换
    private void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    //自低向上建堆
    private void buildHeap(int[] array) {
        //计算最后一个含有叶子节点的父节点: array.length - 1 / 2 - 1
        for (int i = ( array.length - 1 / 2 )- 1; i >= 0; i--){
            heapfy(array,i,array.length);
        }
    }
}

    (5).堆排序的优点及缺点:
      优点:无论怎么的序列在通过堆排序的方式进行排序之后,它的时间复杂度都是O(n*log2n),并且不需要耗费额外的空间,这可以说是排序算法中时间和空间都最优秀的算法了。
      缺点:维护堆的过程相对麻烦,因为在面对增删改数据的过程都需要去维护。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值