堆排序

堆排序

升序->大顶堆

降序->小顶堆

步骤

(1)构造堆

(2)取下堆顶值,继续构造堆

(3)循环(2)直到堆中剩下最后一个元素,排序完成

构造堆

举例 构造大顶堆

找到最后一个非叶子节点的下标,arr.length/2-1

从右往左,从下往上,构造大顶堆

第一轮

 

第二轮

第三轮

(1)拿到索引节点的值,存到temp中,比较索引节点的左右孩子,寻找较大的孩子

(2)如果发现左(右)孩子比temp节点值大,就把左(右)孩子的值赋给索引节点

(3)把左(右)孩子当作新的索引节点(双亲节点),比较索引节点的左右孩子,寻找较大的孩子

(4)如果发现左孩子比(temp节点值)大,就把左孩子的值赋给索引节点

(5)。。。重复上面。。。

(n-1)直到孩子索引超过数组长度结束循环

(n)将temp节点值赋值给最后一个孩子索引(结束循环的索引)的双亲节点

取下堆顶值,继续构造堆

交换了对顶元素,大顶堆被破坏,需要从堆顶从上往下修复

代码

package com.tree;

import java.util.Arrays;

/**
 * @program: DataStructures
 * @description: 堆排序
 * @author: XuDeming
 * @date: 2020-01-03 09:03:04
 *
 * 升序->大顶堆
 * 降序->小顶堆
 **/
public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {16, 7, 6, 18, 17, 8};
        heapSort(arr);
    }

    public static void heapSort(int arr[]) {

        // (1)构造一个大顶堆
        // arr.length/2-1 找到最后一个非叶子节点的下标
        // 从右往左,从下往上,构造大顶堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjustHeap(arr, i, arr.length);
        }

        // (2)将堆顶元素与末尾元素交换,将最大元素"下沉"到末尾
        // (3)重新调整堆结构,构造大顶堆,交换...
        for (int i = arr.length - 1; i > 0; i--) {
            int temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;
            // 交换了对顶元素,大顶堆被破坏,需要从堆顶从上往下修复
            adjustHeap(arr, 0, i);
        }

        System.out.println(Arrays.toString(arr));

    }

    /**
     *
     * @param arr 待调整数组
     * @param parentIndex 双亲节点下标
     * @param length 待调整数组长度
     */
    public static void adjustHeap(int[] arr, int parentIndex, int length) {

        // 获取双亲节点 方便后续比较
        int temp = arr[parentIndex];

        // 索引指向左孩子下标
        int index = parentIndex * 2 + 1;

        while (index < length) {
            // 获取右孩子下标
            int rChildIndex = index + 1;

            // 如果有右孩子 且 右孩子比左孩子大
            if (rChildIndex < length && arr[rChildIndex] > arr[index]) {
                // 索引指向右孩子下标
                index = rChildIndex;
            }
            // 如果孩子节点比双亲节点大
            if (arr[index] > temp) {
                // 将孩子节点值 赋值 给双亲节点
                arr[parentIndex] = arr[index];
                // 将孩子节点的下标作为待调整的双亲 继续调整
                parentIndex = index;
                // 索引指向左孩子下标
                index = parentIndex * 2 + 1;
            } else { // 双亲节点已经最大
                break;
            }
        }
        // 将一开始双亲节点的值赋值给索引节点
        arr[parentIndex] = temp;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值