堆排序的Java实现(用最大堆实现从小到大排序)

堆排序原理和示意图不多说了,网上各种有。总结下其最核心的思想:

(1)自底向上,自右向左遍历建堆。这里的底不是指最后一个节点,而是最后一个非叶子节点。每个非叶子节点与其左儿子与右儿子(假如有的话)相比,如果父节点小,那么将左右儿子中较大的那个与父节点交换,然后递归调整被交换的儿子所在的子树,让其继续满足堆性质。

(2)自顶向下调整,使得整个二叉树和其任意子树都满足堆特性。内容和上面建堆中的递归调整一样。注意调整子树时只用调整被交换的那个,而不用左右子树都递归调整。


堆排序算法算是遍历和递归结合的一种典型了。算法中注意父节点和叶子节点的索引对应,感觉绕脑的话用父节点为0,左儿子1,右儿子2多对照下。


下面上算法,具体注释都写在代码里了:

public class HeapSort {

    public static void main(String[] args) {
        int[] array = {2,1,10,2,-1,7,4,78,-100};
        maxHeapSort(array);
        for (int i : array) {
            System.out.print(i + " ");
        }
    }

    public static void maxHeapSort(int[] array) {
        // 建堆,从最后一个非叶子节点开始,自底向上,自右向左遍历建堆
        for (int i = array.length/2 - 1; i >= 0; i--) {
            adjustMaxHeap(array, i, array.length -1);
        }
        // 交换头尾元素并调整堆(最大堆,最大元素在前面,交换后到最后面,形成从小到大排序)
        for (int i = array.length - 1; i > 0 ; i--) {
            swap(array, 0, i); // 交换元素
            adjustMaxHeap(array, 0, i -1);
        }
    }

    public static void adjustMaxHeap(int[] array, int begin, int end) {
        int leftIndex = 2 * begin + 1; // 左儿子索引
        int rightIndex = 2 * begin + 2; // 右儿子索引
        boolean hasLeftChild = leftIndex <= end; // 是否左儿子
        boolean hasRightChild = rightIndex <= end; // 是否有右儿子
        if (hasLeftChild && hasRightChild) {
            // 同时存在左右儿子时,左儿子比右儿子和父节点都要大
            if (array[leftIndex] >= array[rightIndex] && array[leftIndex] > array[begin]) {
                swap(array, begin, leftIndex); // 左儿子上浮
                adjustMaxHeap(array, leftIndex, end); //调整左子树堆
            }
            // 同时存在左右儿子时,右儿子比左儿子和父节点都要大
            else if (array[rightIndex] >= array[leftIndex] && array[rightIndex] > array[begin]) {
                swap(array, begin, rightIndex); // 右儿子上浮
                adjustMaxHeap(array, rightIndex, end); // 调整右子树堆
            }
        }
        // 只存在左儿子而且大于父节点
        else if (hasLeftChild && array[leftIndex] > array[begin]) {
            // 左儿子上浮,此时不用递归调整左子树,因为堆是完全二叉树,左右儿子不满时说明这是最后一个父节点
            swap(array, begin, leftIndex);
        }
    }

    // 交换函数,原理:a ^ a = 0, a ^ 0 = a
    private static void swap(int[] array, int i, int j) {
        array[i] = array[i] ^ array[j];
        array[j] = array[i] ^ array[j];
        array[i] = array[i] ^ array[j];
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值