算法基础 大根堆与堆排序

大根堆与堆排序

堆分为大根堆和小根堆,是完全二叉树。
完全二叉树我们知道,就是不太满的满二叉树;大根,小跟代表,父节点和子节点的关系;如果每一个父节点都不小于它的两个子节点,就可以认为是大根堆了;

堆排序的思路

从定义看,我们就知道了,对于大根堆来说,根节点一定是最大的,那我们就每次把根节点拿走,让大根堆重新排序,然后再取得最大值就可以了嘛;

那么重要的问题就来了,大根堆是怎么从一个普通的堆转换过来的的呢?
其实也很简单,就是说父节点如果比子节点小,就交换一下,如果交换之后,发现下面还有一层,就继续;

然后呢,由于是完全二叉树,就会有这么一个关系:
K[i]是K[2i]和K[2i+1]的父节点;也就是说父节点的位置,和子节点位置是固定的,所以就可以用数组来表示大根堆了;因为位置是确定的嘛;
代码上的话,一定要注意边界,还有就是数组起始位置的0;

代码

 public class HeapSort {
    public static void main(String[] args) {
        int[] array = new int[]{14,4,14};
        HeapSort heapSort = new HeapSort();
        heapSort.heapSort(array, array.length);
        System.out.println(Arrays.toString(array));
    }

    /**
     * 堆排思路,利用大根堆头结点最大的特性<br>
     * 首先将数组调换为大根堆,然后把头结点扔出去<br>
     *     重复这个过程
     * @param array
     * @param n
     * @return
     */
    public int[] heapSort(int[] array, int n) {
        array = buildMaxHeap(array, n);
        for (int i = array.length-1;i>0;i--) {
            swap(array, 0, i);
            adjustHeap(array, 0, i);
        }
        return array;
    }

    private int[] buildMaxHeap(int[] array, int n) {
        //这个边界坑坏我了,数组长度是从一开始计算的;
        //直接除以二就行了,其实k的起始边界并不重要;
        //很可能第一次压根就不会进行调换,实际上因为数组从零开始,
        // 所以有时会多一次调换
        for (int k = array.length >> 1; k >= 0; k--) {
            adjustHeap(array, k, array.length);
        }
        return array;
    }

    private void adjustHeap(int[] array, int k, int length) {
        int temp = array[k];
        for (int j = 2 * k + 1; j < length; j = 2 * k + 1) {
            if (j < length-1 && array[j] < array[j + 1]) {
                j++;
            }
            if (temp > array[j]) {
                break;
            } else {
                array[k] = array[j];
                k = j;
            }
        }
        array[k] = temp;
    }

}

收获

  1. 清楚地弄明白了堆排序的原理
  2. 不敲代码,你完全无法想象调整堆时对边界的限制到底意味着什么;
  3. 原来的代码居然有问题,我都不想活了
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值