利用堆的结构特性对给定的数组进行排序

前面一篇博客我介绍了Java中堆的结构特性及其代码实现,本篇分析利用堆的结构特性对给定的数组进行排序。
给定一个数组: String[] arr = {"S","O","R","T","E","X","A","M","P","L","E"}
请对数组中的字符按从小到大排序。

实现步骤:

1、构造堆;

2、得到堆中数组1索引处元素,这个值就是最大值;

3、交换数组中1索引处元素与数组中最后一个元素,此时数组中最大的值已放在了最后的位置;

4、对堆进行调整,让除了最后一个元素的剩下所有元素中的最大值处于1索引处;

5、重复2、3、4步骤,直到堆中剩一个元素为止。

API设计:

 堆构造过程 :

堆的构造最直观的方法是:另外创建一个数组,遍历原数组将原数组的元素放入新数组,每次往新数组放入一个元素后就使用上浮算法使该元素处于合适的位置,当所有元素全部放入到新数组,新数组就是一个堆。

上面的方式很直观,也很简单,但是还有一种更聪明的方法。创建一个新数组,将原数组0~length-1索引的元素拷贝到新数组1~length索引处,然后从新数组中间开始往索引1处扫描(从右往左),每扫描到一个元素就对它做下沉操作,这样当扫描结束,我们就得到一个堆。

堆排序过程:

对构造好的堆,我们只需要做类似堆的删除操作,就可以完成数组的排序

1、将堆顶元素和堆最后一个元素交换位置;

2、对堆中临时根结点做下沉调整,使堆中最大元素成为根结点,此时不包括之前被从堆顶替换下来的元素,被替换下来的元素已在数组右边处于排好序的位置;

3、重复1和2操作,直到堆中剩下一个元素

代码实现:

/**
 * @author: xuzhilei6656
 * @create: 2021-12-10 15:41
 * @description: 堆排序
 **/
public class HeapSort {
    //判断heap堆中索引i处的元素是否小于索引j处的元素
    public static boolean less(Comparable[] heap, int i, int j) {
        return heap[i].compareTo(heap[j]) < 0;
    }

    //交换heap堆中i索引和j索引处的元素
    public static void exch(Comparable[] heap, int i, int j) {
        Comparable temp = heap[i];
        heap[i] = heap[j];
        heap[j] = temp;
    }

    //根据原数组source构造处堆heap
    private static void createHeap(Comparable[] source, Comparable[] heap) {
        //把source中的元素拷贝到heap中,heap中的元素就形成一个无序的堆
        System.arraycopy(source, 0, heap, 1, source.length);
        //对堆中的元素做下沉调整()
        for (int i = heap.length / 2; i > 0; i--) {
            sink(heap, i, heap.length - 1);
        }
    }

    //对source数组中的数据从小到大排序
    public static void sort(Comparable[] source) {
        //构建堆
        Comparable[] heap = new Comparable[source.length + 1];
        createHeap(source, heap);
        //定义一个变量,记录未排序元素中的最大索引
        int N = heap.length - 1;
        //
        while (N != 1) {
            //交换索引1处与索引N处的元素值
            exch(heap, 1, N);
            //未排序元素个数-1
            N--;
            //对1到N范围的元素做下沉调整
            sink(heap, 1, N);
        }
        //循环结束,heap中的元素已从小到大排序完成,将数据拷贝到source数组
        System.arraycopy(heap, 1, source, 0, heap.length - 1);

    }


    //在heap中,对target处的元素做下沉操作,范围时0~range
    private static void sink(Comparable[] heap, int target, int range) {
        while (2 * target <= range) {
            //记录较大者的索引值
            int max;
            if (2 * target + 1 <= range) {
                //比较左右子结点的大小,将较大者的索引值给max
                if (less(heap, 2 * target, 2 * target + 1)) {
                    max = 2 * target + 1;
                } else {
                    max = 2 * target;
                }
            } else {
                max = 2 * target;
            }

            //如果当前索引的元素大于max索引处的元素,则当前元素找到了合适位置,结束下沉
            if (!less(heap, target, max)) {
                break;
            }
            //交换当前索引处元素与max索引处元素的位置
            exch(heap, target, max);
            //变换target的值
            target = max;
        }
    }
    
    //测试
    public static void main(String[] args) {
        String[] arr = {"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

}

测试结果:

  以上仅个人学习时随手敲的demo,如有不正确的地方,可以在下方留言指正,谢谢。与各位优快云的伙伴们共勉,每天记录一点点,每天进步一点点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值