排序算法-堆排序(Java实现)

堆排序的算法思想是利用大根堆最大的数在最顶层,然后把得出的最大的数从这个序列 删除,剩下的数继续构造出大根堆,得到最大的数,这样以此类推得出最后一个数 举一组数
在这里插入图片描述
把这些数字以堆的形式展现
在这里插入图片描述

  1. 我们以最后一棵小子树开构建大根堆,也就是下面红框选中的部分
    在这里插入图片描述
    把31拿出来和子树比较,因为该树只有左子树,所以只需要和左子树进行比较,发现1比31小,所以无需交换,然后换至下一棵树。
  2. 因为是倒叙构建才能不断把数字大的往上浮,所以下一棵树是以3号下标为根的子树,也就是我下面红框选中的部分。
    在这里插入图片描述
    把45拿出来和下面的子树进行比较,左子树是5,右子树是47,比较大的是47,我们用47和45进行比较,发现3号下标的右子树大于该数字,所以47放到3号下标,45放到以8号为根的子树中去找自己的定位,因为8号下标已经没有子树了,所以就只能将45放到8号位置。
    在这里插入图片描述
  3. 下来我们该以2号下标为根的树了,比较完成后没有改变
    在这里插入图片描述
  4. 下来继续根为1号下标的树
    在这里插入图片描述
    因为47和31较大的是47,我们用47和3进行比较 ,47比3大,所以把47放到1号下标的位置,现在的状态是这样的。
    在这里插入图片描述
    本来3是要放在3号下标的,但是因为3号下标下面还有子树,所以不能放到3号下标,继续进行比较,5和45大的是45,45和3比较,45大,所以把45放到3号位置。
    在这里插入图片描述
    Temp继续向下比较,8号位置没有子树了,所以就把3放到8号位置
    在这里插入图片描述
    这样以1号为根的树就完成了大根堆的构建,下来是0号,同理
    最终构建得出的大根堆是
    在这里插入图片描述
  5. 以上就是我们构造一个大根堆的过程,通过大根堆我们可以得到这些数字中的最大数字,也就是现在处于0号下标的47,我们把47和最后9号下标的1进行交换,这样我们就得到了排序的最后面的一个数字。
    在这里插入图片描述
    然后我们把9号位置屏蔽掉,在0号到8号里面再次构建大根堆
  6. 构建完我们就在这些数中又可以得到最大的数字,如下图
    在这里插入图片描述
  7. 这次我们继续吧最大的45扔到最后,也就是和8号位置的3进行交换,交换完是这样子的
    在这里插入图片描述
  8. 依次类推,这样就得到了有序的序列,也就排序完成了。
    下来我们来写代码:
    根据我们的思路,第一步我们肯定要构建一个大根堆,在构建大根堆的过程中我们要了解一个规则:、
    父推子: n2+1(左子树) n2+2(右子树)
    子推父: (n-1)/2
    最后一个子树就是 (array.length-1)/2,从这里开始,我们倒着去求,每次用根和两个子树的最大值进行比较。
    构建完大根堆后,我们只需要去交换元素并且限定范围继续构建大根堆就可以了。
    下面看一下代码实现:

代码如下:

public void heapSort(int[] array) {
    for (int i = (array.length-2)/2; i >= 0 ; i--) {
        adjust(array,i,array.length-1);
    }
    for (int i = 0; i < array.length-1 ; i++) {
        swap(array,0,array.length-i-1);
        adjust(array,0,array.length-2-i);
    }
}
public void adjust(int[] array,int start,int end) {
    int temp = array[start];
    for (int i = (start*2+1); i <= end ; i = i*2+1) {
        if(array[i] < array[i+1] && (i+1)<=end) {
            //i为两棵子树中大的子树的下标
            i++;
        }
        if(temp < array[i]) {
            array[start] = array[i];
            start = i;
        } else {
            break;
        }
    }
    array[start] = temp;
}
public void swap(int[] array,int i,int j) {
    int temp = array[i];
    array[i] = array[j];
    array[j] = temp;
}

堆排序可以和选择排序放到一块理解,他们都是每一趟都会选出一个最值。
整个过程中交换数字都跳跃交换的,所以是不稳定的。

特点:

不稳定
堆排序构建大根堆的过程时间复杂度为O(nlogn),然后后面进行交换,再次进行大根堆的建立,也是O(nlogn),两个是并列的,不论何时,算法时间复杂度不会改变,因为纵然是有序,也会去比较,不能直接break出循环。所以最优最差和平均都是O(nlogn)

最优时间复杂度:

O(nlogn)

最坏时间复杂度:

O(nlogn)

平均时间复杂度:

O(nlogn)
整个过程没有开辟数组,所以空间复杂度为O(1)

空间复杂度:

O(1)

猜你喜欢

转载自blog.csdn.net/weixin_42220532/article/details/88431144
今日推荐