八大排序——堆排序

1.将带排序的序列构造成一个大顶堆,根据大顶堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素;

2.将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆;

3.重复步骤2,如此反复,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值,然后把它放到大顶堆的尾部。最后,就得到一个有序的序列了。

过程图如下:

①:初始化状态,右下角为下标

②: index = 5开始,发现他没有兄弟节点,并且父节点小于它,父节点的计算放方式为:

index = [arr.length - 1] /2

③:接下来index减1,那么index节点变为4,这时候他要和兄弟节点进行对比,发现它比兄弟节和父节点都大

那么他就和父节点机型交换。

④:接下来index减2,他有和兄弟节点进行对比,发现它比兄弟节点大,还比父节点大,那么它和父节点进行交换

④:交换完成之后,发现2号节点不再大于其子节点了,所有需要在交换一次

//选取孩子结点的左孩子结点,继续向下筛选
parent = lChild;
lChild = 2 * lChild + 1;

⑤:检查一下,已将满足最大的条件了,大顶堆已经构建完成

第二步:将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆

①:0号节点是最大值,我们将它与最后一个节点交换位置

②:此时的堆不是大顶堆需要重现构建

③:再次调整,index = 1 ,此时 下标为1的值为5,值大于左右子树,所以 index -1 ,此时值为1.然后需要进行交换

交换完成之后,发现1号节点不再大于其子节点了,所有需要在交换一次

④:交换后的结果是

⑤:0号节点是最大值,我们将它与最后一个节点交换位置

⑥:此时的堆不是大顶堆需要重现构建,此时 index = 1,1号位置大于其孩子节点的值,所以 index -1 ,此时index = 0

0号位置小于其左子树。所以进行交换

⑦:交换后的结果是

⑧:0号节点是最大值,我们将它与最后一个节点交换位置

⑨:此时的堆不是大顶堆需要重现构建,此时 index = 0,0号位置小于其孩子节点的值,左右子树进行计较之后发现右子树更大,所以和右子树进行交换。

⑩:交换后的结果是

十一;0号节点是最大值,我们将它与最后一个节点交换位置

十二:此时的堆不是大顶堆需要重现构建,此时 index = 0,0号位置小于其孩子节点的值,左右子树进行计较之后发现做子树更大,所以和右子树进行交换。

十三:交换后的结果是

十四;0号节点是最大值,我们将它与最后一个节点交换位置

最终我们就能得到最后的答案

 堆排序具有特点:

①:完全二叉树(从上到下,从左到右,每一层的节点都是满的,最下边一层所有的节点都是连续集中在最左边)。

②:二叉树每个结点的值都大于或者等于其左右孩子节点的值称之为大顶堆。

二叉树每个结点的值都小于或者等于其左右孩子节点的值称之为小顶堆。

将数组转换为堆得数据结构:

 规律如下:

N[i]的左节点:N[2i+1]
N[i]的右节点:N[2i+2]
N[i]的父节点:N[(i-1)/2)]

堆排序执行过程:

public static void main(String[] args) {
        int[] arr = {8, 65, 41, 28, 6, 1, 4, 5, 32, 9, 10};
        System.out.println("排序前");
        System.out.println(Arrays.toString(arr));
        System.out.println("排序后");
        headSort(arr);
    }

    public static void headSort(int[] arr) {
        for (int i = (arr.length - 1) / 2; i >= 0; i--) {
            adjustHeap(arr, i, arr.length);               //从第一个非叶子结点从下至上,从右至左调整结构
        }
        for (int i = arr.length - 1; i > 0; i--) {
            int temp = arr[i];                           //堆顶元素和末尾元素交换
            arr[i] = arr[0];
            arr[0] = temp;
            System.out.println(Arrays.toString(arr));
            adjustHeap(arr, 0, i);                  //重新调整堆
        }
    }

    public static void adjustHeap(int[] arr, int parent, int len) {
        int temp = arr[parent];                         //用temp存父节点的值
        int lChild = 2 * parent + 1;                    //定义左孩子
        while (lChild < len) {
            int rChild = lChild + 1;                    //定义右孩子
            if (rChild < len && arr[lChild] < arr[rChild]) {        //判断右孩子是否存在,并且另左孩的值大
                lChild++;
            }
            if (temp >= arr[lChild]) {                              //如果父节点值大于孩子节点直接退出
                break;
            }
            arr[parent] = arr[lChild];                              //否则交换左孩子和父节点的值
            parent = lChild;                                        //左孩子变为父节点
            lChild = 2 * lChild + 1;                                //重新计算左孩子值
        }
        arr[parent] = temp;                                         //将旧的父节点的值赋给新的父节点
    }

输出结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值