堆排序(理解二叉树的节点遍历 )

堆排序(理解二叉树的节点遍历 )

  • 关于二叉树 递归这一块 参考归并排序那一篇

堆的定义

  • 堆是一种数据结构,一种叫做完全二叉树的数据结构

堆的性质

  • 大顶堆:每个节点的值都大于或者等于它的左右子节点的值

  • 小顶堆:每个节点的值都小于或者等于它的左右子节点的值

  • 对于大顶堆:arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]
    
    对于小顶堆:arr[i] <= arr[2i + 1] && arr[i] <= arr[2i + 2]
    

在这里插入图片描述

堆排序的步骤与图解

  • 堆排序的基本思想是:
    1. 将带排序的序列构造成一个大顶堆,根据大顶堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素
    2. 将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆
    3. 重复步骤2,如此反复,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值,然后把它放到大顶堆的尾部。最后,就得到一个有序的序列了
1. 初次构建大顶堆
2. 进行大顶堆排序
3. 堆顶元素下沉
4. 剩余元素再次构建大顶堆
5. 重复3-4
6. 排序完毕

图解

在这里插入图片描述

  1. 如图 初始序列为{33,56,87,112,114,252,96,919}

  2. 将其化为二叉树表示 {33,56,87,112,114,252,96,919}

  3. 首先对 i=8/2-1=3 的节点 也就是从112这个节点进行初次的大顶堆构建

  4. 交换919–112 [33, 56, 87, 919, 114, 252, 96, 112]

  5. 对2号节点 即87 进行排序操作

  6. 交换252–87 [33, 56, 252, 919, 114, 87, 96, 112]

  7. 对1号节点 56 进行操作

  8. 交换919–56 [33, 919, 252, 56, 114, 87, 96, 112]

  9. 子节点发生变化 重复判定子节点

  10. 对当前3号节点 进行操作

  11. 交换114–56 [33, 919, 252, 112, 114, 87, 96, 56]

  12. 对0号节点 33 进行操作

  13. 交换919–33 [919, 33, 252, 112, 114, 87, 96, 56]

  14. 子节点发生变化 重复判定子节点

  15. 对当前1号节点 进行操作

  16. 交换114–33 [919, 114, 252, 112, 33, 87, 96, 56]

  17. 至此 初次大顶堆构建完毕

  18. 接着将交换根节点919与末节点56 进行堆节点下沉 [56, 114, 252, 112, 33, 87, 96, 919]

  19. 除去 当前末节点 对剩余元素再次进行大顶堆操作

  20. 交换根节点与末节点 进行堆节点下沉

  21. 重复19-20 在这里插入图片描述

  22. 堆排序结束 最终结果为:[33, 56, 87, 96, 112, 114, 252, 919]

代码及运行过程

import java.util.Arrays;
public class DuiPaiXu {
    public static void main(String[] args) {
        int[] a = {33,56,87,112,114,252,96,919};
        GouJian(a);
        System.out.println("最终结果为:"+Arrays.toString(a));
    }
    public static void GouJian(int[] a) {
        int ll = a.length;
        DaDingDui(a, ll);//大顶堆的初次构建
        System.out.println(Arrays.toString(a));
        for (int i = a.length - 1; i > 0; i--) {//确保除去最后一个元素外的所有元素都循环到
            JiaoHuan(a, 0, i);//将堆顶元素与末节点元素进行交换
            System.out.println("将堆顶元素与末节点元素进行交换" + Arrays.toString(a));
            ll--;//末节点元素剔除
            PaiXu(a, 0, ll);//除去末节点 剩余元素再次进行大顶堆的构建
            System.out.println("对交换过后重新得到的二叉树进行大顶堆排序操作:" + Arrays.toString(a));
        }

    }
    public static void DaDingDui(int[] a, int ll) {
        for (int i = a.length / 2 - 1; i >= 0; i--) {
            PaiXu(a, i, ll);//从最后一个非叶节点进行排序 
            System.out.println("第"+i+"号节点的排序交换结果"+ Arrays.toString(a));
        }
    }
    public static void PaiXu(int[] a, int dq, int ll) {
        //下沉
        int left = 2 * dq + 1; //该节点的左节点
        int right = 2 * dq + 2;//该节点的右节点
        int max = dq;//记录最大值索引
        if (left < ll && a[max] < a[left]) {
        //如果有左节点 比较大小 大的话更新最大值索引
            System.out.println("左节点大");
            max = left;
        }
        if (right < ll && a[max] < a[right]) {
          //如果有右节点 比较大小 大的话更新最大值索引
            System.out.println("右节点更大");
            max = right;
        }
        if (max != dq) {//如果最大值不是当前索引 (代表在上述的步骤更新过)
            JiaoHuan(a, dq, max);//进行元素交换
            System.out.println("最大值交换" + Arrays.toString(a));
            PaiXu(a, max, ll);//对交换过后的子节点进行再次排序 以免混乱
            System.out.println("节点交换后的排序:" + Arrays.toString(a));
        }

    }
    
    public static void JiaoHuan(int[] a, int ding, int di) {
        //交换元素
        int z = a[di];
        a[di] = a[ding];
        a[ding] = z;
    }
}
运行过程:
左节点大
最大值交换[33, 56, 87, 919, 114, 252, 96, 112]
节点交换后的排序:[33, 56, 87, 919, 114, 252, 96, 112]
第3号节点的排序交换结果[33, 56, 87, 919, 114, 252, 96, 112]
左节点大
最大值交换[33, 56, 252, 919, 114, 87, 96, 112]
节点交换后的排序:[33, 56, 252, 919, 114, 87, 96, 112]
第2号节点的排序交换结果[33, 56, 252, 919, 114, 87, 96, 112]
左节点大
最大值交换[33, 919, 252, 56, 114, 87, 96, 112]
左节点大
最大值交换[33, 919, 252, 112, 114, 87, 96, 56]
节点交换后的排序:[33, 919, 252, 112, 114, 87, 96, 56]
节点交换后的排序:[33, 919, 252, 112, 114, 87, 96, 56]
第1号节点的排序交换结果[33, 919, 252, 112, 114, 87, 96, 56]
左节点大
最大值交换[919, 33, 252, 112, 114, 87, 96, 56]
左节点大
右节点更大
最大值交换[919, 114, 252, 112, 33, 87, 96, 56]
节点交换后的排序:[919, 114, 252, 112, 33, 87, 96, 56]
节点交换后的排序:[919, 114, 252, 112, 33, 87, 96, 56]
第0号节点的排序交换结果[919, 114, 252, 112, 33, 87, 96, 56]
[919, 114, 252, 112, 33, 87, 96, 56]
将堆顶元素与末节点元素进行交换[56, 114, 252, 112, 33, 87, 96, 919]
左节点大
右节点更大
最大值交换[252, 114, 56, 112, 33, 87, 96, 919]
左节点大
右节点更大
最大值交换[252, 114, 96, 112, 33, 87, 56, 919]
节点交换后的排序:[252, 114, 96, 112, 33, 87, 56, 919]
节点交换后的排序:[252, 114, 96, 112, 33, 87, 56, 919]
对交换过后重新得到的二叉树进行大顶堆排序操作:[252, 114, 96, 112, 33, 87, 56, 919]
将堆顶元素与末节点元素进行交换[56, 114, 96, 112, 33, 87, 252, 919]
左节点大
最大值交换[114, 56, 96, 112, 33, 87, 252, 919]
左节点大
最大值交换[114, 112, 96, 56, 33, 87, 252, 919]
节点交换后的排序:[114, 112, 96, 56, 33, 87, 252, 919]
节点交换后的排序:[114, 112, 96, 56, 33, 87, 252, 919]
对交换过后重新得到的二叉树进行大顶堆排序操作:[114, 112, 96, 56, 33, 87, 252, 919]
将堆顶元素与末节点元素进行交换[87, 112, 96, 56, 33, 114, 252, 919]
左节点大
最大值交换[112, 87, 96, 56, 33, 114, 252, 919]
节点交换后的排序:[112, 87, 96, 56, 33, 114, 252, 919]
对交换过后重新得到的二叉树进行大顶堆排序操作:[112, 87, 96, 56, 33, 114, 252, 919]
将堆顶元素与末节点元素进行交换[33, 87, 96, 56, 112, 114, 252, 919]
左节点大
右节点更大
最大值交换[96, 87, 33, 56, 112, 114, 252, 919]
节点交换后的排序:[96, 87, 33, 56, 112, 114, 252, 919]
对交换过后重新得到的二叉树进行大顶堆排序操作:[96, 87, 33, 56, 112, 114, 252, 919]
将堆顶元素与末节点元素进行交换[56, 87, 33, 96, 112, 114, 252, 919]
左节点大
最大值交换[87, 56, 33, 96, 112, 114, 252, 919]
节点交换后的排序:[87, 56, 33, 96, 112, 114, 252, 919]
对交换过后重新得到的二叉树进行大顶堆排序操作:[87, 56, 33, 96, 112, 114, 252, 919]
将堆顶元素与末节点元素进行交换[33, 56, 87, 96, 112, 114, 252, 919]
左节点大
最大值交换[56, 33, 87, 96, 112, 114, 252, 919]
节点交换后的排序:[56, 33, 87, 96, 112, 114, 252, 919]
对交换过后重新得到的二叉树进行大顶堆排序操作:[56, 33, 87, 96, 112, 114, 252, 919]
将堆顶元素与末节点元素进行交换[33, 56, 87, 96, 112, 114, 252, 919]
对交换过后重新得到的二叉树进行大顶堆排序操作:[33, 56, 87, 96, 112, 114, 252, 919]
最终结果为:[33, 56, 87, 96, 112, 114, 252, 919]

进程已结束,退出代码0

over

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值