数据结构与算法(java):堆排序

本文介绍了堆排序算法的基本思想和操作流程,包括如何构建堆、下沉算法以及排序方法。通过示例代码展示了如何在Java中实现堆排序,将给定字符串数组从小到大排序。最终,经过堆排序,数组`s`变为`[A, E, E, L, M, O, P, R, S, T, X]`。
摘要由CSDN通过智能技术生成

堆排序

介绍

堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最好最坏,平均时间复杂度均为O(nlogn),是不稳定排序。

基本思想
  1. 将待排序序列构造成一个大顶堆(父结点大于两个子结点)
  2. 此时,整个序列的最大值就是堆顶的根结点
  3. 将其与末尾元素进行交换,此时末尾就为最大值
  4. 将末尾这个最大值用排除堆之外,然后将剩余n-1个元素重新构成一个堆,这样就会得到n个元素的次小值,反复执行,按顺序排除出堆的元素就能组成一个有序队列了。
问题描述

给定一个数组,使用堆排序从小到大排序好,或者可以理解为实现小顶堆(父结点小于两个子结点)。
String[] s = {“S”,“O”,“R”,“T”,“E”,“X”,“A”,“M”,“P”,“L”,“E”};

主要方法及其原理:
(1)根据原数组构造出一个堆(createHeap(Comparable[] source, Comparable[] heap)),返回值为空,参数分别是要传入的数组和堆的数组,将传入的数组复制到堆数组中,并用下沉算法调整堆中的元素
(2)下沉算法(sink(Comparable [] heap,int target,int range)),返回值空,target是要下沉调整的元素,range是调整的范围,可以看成是不断变换的堆数组的长度
(3)排序方法(sort(Comparable[] cource)),参数是要传入的数组,每次循环将最大值和堆中最大索引处的值交换,并且排除最大索引处的值,使其不再参与下沉,排除后的值仍在堆中并且处于的数组中的位置没有变,直到循环结束,排除后的值就是按照从小到大的顺序排序,最后再将堆复制到原数组中。

具体操作看代码

代码实现
public class HeapSort {
    //判断heap堆中索引i处的元素是否小于索引j处的元素
    private static boolean less(Comparable[] heap, int i, int j){
        return heap[i].compareTo(heap[j])<0;
    }

//-----------------------------------------------------------------
    //交换heap堆中两指定索引处的值
    private static void exchange(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);
        //对堆中的元素做下沉调整(从长度的一半开始往索引1处开始扫描)
        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;

        //通过循环交换1索引处和排序的元素中最大的索引处的元素
        while(N!=1){
            //交换元素
            exchange(heap,1,N);
            //排序交换后最大元素所在的索引,让它不再参与下沉
            N--;
            //对索引1处的元素进行堆的下沉调整
            sink(heap,1,N);
        }
        //
        System.arraycopy(heap,1,source,0,source.length);
    }

//-----------------------------------------------------------------
    //在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){ //在当前左右结点都存在的情况下比较
                if(less(heap,2*target,2*target+1)){
                    max = 2*target+1;
                }else{
                    max = 2*target;
                }
            }else{
                max = 2*target;
            }
            //2、比较当前结点的值和较大子结点的值
            if (!less(heap, target, max)) {
                break;
            }

            exchange(heap,target,max);
            target = max;
        }
    }
}

测试代码

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

结果:

[A, E, E, L, M, O, P, R, S, T, X]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值