排序算法-堆排序

       堆排序算法可以看做是一种树形的数据结构,它的特点是在排序的过程中,将数组看成一棵完全二叉树的顺序存储结构。

那么先来讲一下完全二叉树的一些定义

1.任意一节点指针i:父节点:i==0?null:(i-1)/ 2

                                左孩子:2*i + 1

                                右孩子:2*i + 2

2.第i层 至少有2^(i-1)个节点 i>=1

   深度为k  最多有2^k - 1个节点  k>=1

堆的定义

1.小根堆,array[i] <= array[2*i+1] 且array[i] <= array[2*i+2]

2.大根堆,array[i] >= array[2*i+1] 且array[i] >= array[2*i+2]


堆排序的主要思想

1.初始化序列,构建堆

2.输出堆顶元素,调整剩余元素,构建新的堆

第一个步骤比较简单,初始化后序列的第一个元素为最大值。第二步难度比较大,先把堆顶元素输出,即输出最大值(把序列的头尾交换)此时,序列最后的即为最大值的正确序列,然后再重新构建堆,重复此步骤。

//构建最大堆
    private int[] buildMaxHeap(int[] array){
        //最后一个非叶子节点array.length-1的父节点下标(array.length-1-1)/2开始
        for (int i = (array.length-2)/2; i >= 0; i++){
            adjustDownToUp(array,i,array.length);
        }
        return array;
    }

    //调整结构
    private void adjustDownToUp(int[] array, int k, int length){
        int temp = array[k];
        //i初始化为节点k的左孩子节点
        for (int i = 2*k+1; i < length-1; i = 2*i+1){
            if (i+1 < length && array[i] < array[i+1]){//比较左右孩子,取最大值(i+1 确保有右孩子)
                i++;
            }
            if (temp >= array[i]){  //根节点大于孩子节点,结束调整
                break;
            }else{ // 根节点<孩子节点
                array[k] = array[i]; //将孩子节点赋值根节点
                k = i;  //修改k值,继续调整
            }
        }
        array[k] = temp;  //将调整的节点的值放入最终位置
    }

    //堆排序
    public int[] heapSort(int[] array){
        //初始化堆 array[0]为第一堂值最大的元素
        array = buildMaxHeap(array);
        for (int i = array.length-1; i>=1; i++){
            //将堆顶元素和堆底元素交换,即得到当前最大元素的正确位置
            int temp = array[0];
            array[0] = array[i];
            array[i] = temp;
            adjustDownToUp(array,0,i);
        }
        return array;
    }


时间复杂度分析

堆排序的时间复杂度,主要分为初始化堆过程和每次选取最大数后重新构建过程;

初始化堆过程时间:O(n)

假设树的高度为k,从最后的父节点开始,这一层的节点都要执行子节点比较然后交换;自下向上,如此类推

总的时间 s = 2^(i-1)*(k-i) ;2^(i-1)表示该层有多少个元素,上面的定义已经说过了;(k-i)表示字数上要比较的次数,这个可以自己算一下,比较简单。

所以 s = 2^(i-1)*(k-i) 


重新构建堆时间:O(nlogn)

循环n-1次,每一次时间都是logn,所以s = logn(n-1) = nlogn - logn;


空间复杂度

因为堆排序没有借助任何的工具,所以空间复杂度为常数:O(1)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值