堆排序的Java实现

一.堆的构造

堆的构造,最直观的想法就是另外再创建一个新数组,然后从左往右遍历原数组,每得到一个元素后,添加到新数组中,并通过上浮,对堆进行调整,最后新的数组就是一个堆。

上述的方式虽然很直观,也很简单,但是我们可以用更聪明一点的办法完成它。
创建一个新数组把原数组0 ~ length-1的数据拷贝到新数组的1~ length处(舍弃掉索引0)
再从新数组长度的一半处开始往1索引处扫描(从右往左),然后对扫描到的每一个元素做下沉调整即可。

为什么从一半处开始下沉:
因为堆的性质,大于一半的都是叶子结点而叶子节点处于末端不需要再下沉,所以从堆的一半开始下沉即可以。

二.堆的排序

需求:排序后为从小到大的顺序,元素越大,其所处的索引就越大
对构造好的堆,我们只需要做类似于堆的删除操作,就可以完成排序。

  1. 将堆顶元素和堆中最后一个元素交换位置;(即最大的数放到索引最大的位置)
  2. 通过对新的堆顶元素下沉sink调整堆,把最大的元素放到堆顶使其有序(此时最后一个元素不参与堆的调整,因为最大的数据已经到了数组的末尾)
  3. 重复1~2步骤,直到堆中剩最后一个元素。

代码

public class heapSort<T extends Comparable> {

    //堆排序
    public static void sort(Comparable[] source) {
        Comparable[] heap = new Comparable[source.length + 1]; //因为0要被废弃掉
        //构建堆
        createHeap(source, heap);
        //定义一个变量,记录未排序的  索引最大的元素
        int N=heap.length-1; //记录最大索引N,第一轮是数组长度减一
        //循环,交换根节点和未排序的索引最大处的元素
        while(N!=1) {
            swap(heap, 1, N);
            //排除交换后最大元所在索引,也就是排除索引最大数
            N--;
            //对新的索引1处的元素到 N使用sink方法
            sink(heap, 1, N);
        }//把heap再传回source
        System.arraycopy(heap,1,source,0,source.length);
    }

    //创建堆
    private static void createHeap(Comparable[]source ,Comparable[]heap){
        //把source的元素拷贝到heap中,heap中的元素就形成了堆(暂时无序)
            System.arraycopy(source,0,heap,1,source.length);

        //对堆的元素做下沉调整(从长度的一半处,往索引1处逐个使用下沉方法)
            for(int i=(source.length)/2;i>0;i--){
                sink(heap,i,heap.length-1);  //heap是从1开始的,
            }
    }

    private static boolean more(Comparable[] heap,int i,int j){ //比较 
        return (heap[i].compareTo(heap[j])>0);
    }

    private static void swap(Comparable[]heap,int i ,int j){ //交换
        Comparable temp=heap[i];
        heap[i]=heap[j];
        heap[j]=temp;
    }

    private static void sink(Comparable[] heap, int target, int range) { //在0到range范围下沉
        int max = 0;
        while (2 * target <= range) { //循环条件:存在左子结点

            if (2 * target + 1 <= range) { //如果有右子节点
                //1. 找出当前结点的子节点中大的那个max
                if (more(heap, target * 2, target * 2 + 1)) {
                    max = target * 2;
                } else {
                    max = target * 2 + 1;
                }
            } else {
                max = target * 2;
            }
            
            //2. 比较当前结点和max,若当前结点小则需要和max交换
            if (more(heap, max, target)) {
                swap(heap, max, target);
                target = max;  //更新当前结点target
            } else {
                break;
            }
        }

    }


    public static void main(String[] args) {
        String[] arr = {"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"};
        heapSort.sort(arr);
        System.out.println(Arrays.toString(arr));
    }

}

测试结果:[A, E, E, L, M, O, P, R, S, T, X]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值