堆排序思路和理解

堆排序思路: 1.先把数组中的元素依次传入构造为大根堆
2.交换根节点(数组第一个元素)和末尾的叶节点(数组最后一个元素)
3. 调整此时交换后的乱序大根堆
4. 调整完毕后,重复2,3步骤
5. 总结: 通过每次将大根堆中的栈顶元素和末尾元素交换,达到将该栈顶元素排好序的目的,依次 循环。
6. 要注意的点:
6-1 注意边界值的控制,设置区间[0, heapSize)为大根堆的范围,以此排除最后一个元素。
6-2 注意不要让当前结点的(交换后的栈顶元素)左右结点越界。
6-3 公式: i表示数组下标。i的左节点下标:2i+1。 右节点下标:2i+2。 父节点下标: (i - 1) / 2

/**
 * @author cj
 * @date 2019/7/8
 * 完全二叉树:除根结点外,每个结点都是从左边开始产生 然后产生右边
 *
 * 数组中构造大根堆实质上是将数组中的元素依次加进来
 * 调整当前元素在数组中的位置,使之对应在大根堆中的位置
 *
 * 堆排序思路:1.先把数组中的元素依次传入构造为大根堆
 * 2.交换根节点(数组第一个元素)和末尾的叶节点(数组最后一个元素)
 * 3. 调整此时交换后的乱序大根堆(a[0]到a[a.length - 2])
 * 4. 调整完毕后,重复2,3步骤
 * 注意:堆排序传的heapSize是数组最后一个数的下标,而该数是不属于堆的
 */
public class HeapSort {
    public static void heapSort(int[] a) {
        if(a == null || a.length < 2) {
            return;
        }
        for (int i = 0; i < a.length; i++) {
            heapInsert(a, i);//将每个元素依次插入,形成大根堆
        }
        int heapSize = a.length;
        swap(a, 0, --heapSize);//将大根堆的根节点和最后一个节点交换
        while(heapSize >= 1) {
            //[0, heapSize-1]为堆,heapSize指向的元素不在堆内
            heapify(a, 0, heapSize);//调整交换后的大根堆 heapSize指向当前堆右边界+1
            swap(a, 0, --heapSize);//继续将大根堆的根节点和最后一个节点交换
        }
    }

    //生成大根堆
    public static void heapInsert(int[] a, int index) {

        while(a[index] > a[(index - 1) / 2]) { //当前的值比父节点大则交换
            swap(a, index, (index + 1)/2);
            index = (index - 1) / 2; //交换后设置下标为父节点下标,继续比较
        }
    }



    /**
     * 传入一个大根堆[]a,该大根堆中的某个节点被替换了,index:被替换的节点的下标
     * heapify()实现的功能是将该大根堆调整为正确的大根堆
     * @param a 已经被排序为大根堆的数组a
     * @param current  当前被替换的节点下标
     * @param heapSize 指向堆的右边界 [index, heapSize)区间为大根堆
     */
    public static void heapify(int[] a, int current, int heapSize) {
        int leftNode = 2 * current + 1;//当前节点下标的左节点下标
        while (leftNode < heapSize) { //抵达至当前堆的叶节点。不能等于最后一个元素,因为最后一个元素是被交换的元素,该元素不属于堆了
            //先判断右节点是否存在,若存在则比较左节点和右节点的最大值 返回下标
            int larger = leftNode + 1 < heapSize && a[leftNode+1] > a[leftNode] ?
                    leftNode + 1 : leftNode;//注意a[leftNode + 1] > a[leftNode]不能交换顺序
            if(a[current] < a[larger]) {
               swap(a, larger, current);
               current = larger;//重置current指针的指向
                leftNode = 2 * current + 1;//指向current的下一个左节点
            } else {
                break;//当前的数大于等于a[larger],堆排序中等于a[larger],不会大于
            }
        }
    }


    public static void swap(int[] a, int i, int j) {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
    public static void main(String[] args) {
         int[] a= new int[]{4,3,1,7,2};
         heapSort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值