堆排序的注意事项

堆呢,就是完全二叉树,分为大根堆和小根堆,大根堆呢,就是每个节点的值大于它左右孩子的值,小根堆与此恰恰相反。

下图是一个典型的大根堆和小根堆:

堆排序,顾名思义,就是利用堆的性质进行排序,那么如何通过构建堆实现有效的排序?

对于一组数,我们首先要做的就是构建一个堆来存储它们,构建的方法便是将数组中的头一个元素视为根节点的元素,将堆节点从左到右,从上到下进行标号,向下面这样:

容易发现对于节点标号为i的元素,其左右孩子的节点的标号分别为i*2+1,i*2+2,,如此便可实现数组与堆的映射。

每次构建一个大根堆,那么数组对应的第一个元素就是最大元素,将数组第一个与第n个元素互换,那么最大元素便被放到了最后面,接着对剩下的n-1个元素继续构建大根堆,重复之前的操作,最终便实现了数组的升序排序。

首先要建堆,相关代码如下:

  */
    public static void heapify(int[] arrays, int currentRootNode, int size) {

        if (currentRootNode < size) {
            //左子树和右字数的位置
            int left = 2 * currentRootNode + 1;
            int right = 2 * currentRootNode + 2;

            //把当前父节点位置看成是最大的
            int max = currentRootNode;

            if (left < size) {
                //如果比当前根元素要大,记录它的位置
                if (arrays[max] < arrays[left]) {
                    max = left;
                }
            }
            if (right < size) {
                //如果比当前根元素要大,记录它的位置
                if (arrays[max] < arrays[right]) {
                    max = right;
                }
            }
            //如果最大的不是根元素位置,那么就交换
            if (max != currentRootNode) {
                int temp = arrays[max];
                arrays[max] = arrays[currentRootNode];
                arrays[currentRootNode] = temp;

                //继续比较,直到完成一次建堆
                heapify(arrays, max, size);
            }
        }
    }

 

 public static void maxHeapify(int[] arrays, int size) {

        // 从数组的尾部开始,直到第一个元素(角标为0)
        for (int i = size - 1; i >= 0; i--) {
            heapify(arrays, i, size);
        }

    }

建堆时应当注意顺序,即应当采取自底向上的构建方法,因为构建更大的堆要求其子堆先满足要求。


    for (int i = 0; i < arrays.length; i++) {

        //每次建堆就可以排除一个元素了
        maxHeapify(arrays, arrays.length - i);

        //交换
        int temp = arrays[0];
        arrays[0] = arrays[(arrays.length - 1) - i];
        arrays[(arrays.length - 1) - i] = temp;

    }

每次建堆时,都可以排除一个最大元素,因而每次需要排序的数组的长度不断的递减。

如此,利用堆排序,便可以构建出一个有序的数组。

其空间复杂度为O(1),相当于就地排序,时间复杂度为O(nlgn)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值