Java八大排序——堆排序(附Java代码)

1.什么是堆排序

        堆排序是一种基于堆数据结构的排序算法,它的时间复杂度为O(nlogn),空间复杂度为O(1)。堆排序的基本思想是将待排序的序列构建成一个大根堆或小根堆,然后将堆顶元素与堆底元素交换,再对剩余的元素重新构建堆,重复以上步骤直到整个序列有序。堆排序是一种不稳定的排序算法,因为在构建堆的过程中,可能会改变相同元素的相对位置。

2.堆排序步骤

        1.利用完全二叉树构建大顶堆

        2.堆底堆顶进行交换,继续构建大顶堆,堆底不在参与构建

        3. 不断重复2,直到变成有序数组

3.大顶堆

        大顶堆是一种完全二叉树,其中每个节点的值都大于或等于其左右子节点的值。大顶堆的根节点是堆中的最大值。

        如何构建大顶堆?

        第一步:1.定义parent游标,从后往前遍历,指向第一个有孩子的节点

                        2.定义parent的左孩子child,(有孩子一定是左孩子)

                        3.判断parent有没有右孩子,如果有右孩子,左右孩子进行比较,child指向左右孩子当中的最大值

                        4.父子节点进行比较,如果父亲节点的值大,则parent继续向前移动

                        5.如果子节点大于父亲节点,则父子节点进行交换,parent指向child,child指向其左孩子,重复3-5,直到父节点的值大于子节点,或者没有孩子节点。

        第二步:1.堆顶堆底进行交换,除堆底元素之外继续构建大顶堆

                        2. parent直接指向堆顶,定义parent的左孩子child,(有孩子一定是左孩子)

                        3.判断parent有没有右孩子,如果有右孩子,左右孩子进行比较,child指向左右孩子当中的最大值

                        4.父子节点进行比较,如果父亲节点的值大,则parent继续向前移动

                        5.如果子节点大于父亲节点,则父子节点进行交换,parent指向child,child指向其左孩子,重复3-5,直到父节点的值大于子节点,或者没有孩子节点。

                在实际的代码操作中,不需要构建完全二叉树,直接在数组中找到父亲节点和左右孩子节点,arr[i]父亲节点为arr[(i-1)/2],arr[i]的左孩子arr[2i+1],arr[i]的右孩子arr[2i+2]。

3.代码实现

 public static void main(String[] args) {
        int[] arr = new int[]{2, 36, 78, 79, 76, 999, 890, 8, 3};

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

//堆排序
    public static void duipai(int[] arr) {
        //构建大顶堆
        for (int p =(arr.length-2)/2; p>=0 ; p--) {
            adjust(arr,p,arr.length);
        }
        //堆顶堆底进行交换,除堆底外剩余部分构建大顶堆
        for (int i = arr.length-1;i >=0; i--) {
            int temp=arr[i];
            arr[i]=arr[0];
            arr[0]=temp;
            adjust(arr,0, i);
        }
    }
    //维护
    public static void adjust(int[] arr,int parent,int len){
        int child=2*parent+1;
        while (child<len){
            //定义右孩子
            int rchlid=2*parent+2;
            if(rchlid<len&&arr[rchlid]>arr[child]){
                //找到左右孩子当中的最大值
                child=rchlid;
            }
            //父子节点比较
            if(arr[parent]<arr[child]){
                //如果父节点的值小
                int temp=arr[parent];
                arr[parent]=arr[child];
                arr[child]=temp;
                //父节点指向child,child继续向下指
                parent=child;
                child=2*child+1;
            }else {
                //父节点的值大
                break;
            }
        }
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值