数组排序——堆排序

堆排序

准备知识:

完全二叉树:它在二叉树的基础上多了“完全”这个限制条件,通俗的讲,就是在给一颗二叉树添加结点的时候,添加的次序只能从上到下,从左到右。例如:

请添加图片描述

完全二叉树的特性:

  1. 下标为index结点的父结点的下标为(index-1)/2
  2. 下标为index结点的左孩子的下标为index*2+1
  3. 下标为index结点的右孩子的下标为index*2+2

大根堆:

完全二叉树中,根结点的关键字大于左右两个孩子的关键字,并且它的所有子树都要满足这个条件。
在这里插入图片描述

思路:

先遍历整个数组,将它变成整个大根堆(不需要用到树结构,只需要用到思想即可),即beBigHeap操作(高级一点叫heapInsert)这个过程完成后,无序数组的最大值就在数组的第一个位置;

然后将它与数组的最后一个位置互换,无序部分的长度减1,这个时候无序部分不满足大根堆了,此时需要在将它进行move操作(高级一点叫heapify),变换后又变成了一个大根堆,重复本步操作;

举个例子:

9,2,1,8,4,6

beBigHeap(即heapInsert):

初始:

在这里插入图片描述

index=0:
在这里插入图片描述

index=1:

在这里插入图片描述

index=2:
在这里插入图片描述

index=3:

在这里插入图片描述

index=4:
在这里插入图片描述

index=5:

在这里插入图片描述

move(即heapify):

将数组首尾位置的值互换,得:
在这里插入图片描述

此时仅仅变换跟结点即可,其子树都是大根堆

通过将根结点(下标index=0)与1其左右孩子中的较大者进行交换,得:

在这里插入图片描述

此时整体还不是大根堆,继续交换,此时index=1(下标),通过将结点(下标index=1)与其左右孩子中的较大者进行交换,得:

在这里插入图片描述

此时整体是一个大根堆,重复进行move(heapify)操作,直到无序部分的长度为0;

代码:

``

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        String s = sc.next().toString();
        String[] arr = s.split(",");
        int[] b=new int[arr.length];
        System.out.println("排序前:");
        for (int i =0;i<b.length;i++) {
            b[i]=Integer.parseInt(arr[i]);
            System.out.print(b[i]+",");
        }
        myHeap(b);
        System.out.println("排序后:");
        for (int i =0;i<b.length;i++) {
            System.out.print(b[i]+",");
        }
    }
    public static void myHeap(int b[]){
//        c为有序无序部分的分界线
        int c=b.length-1;
//        复杂度为O(n)
        for (int i=0;i<b.length;i++){
            beBigHeap(b,i);
        }
        while (c>0){   //        复杂度为O(n)
            swap(b,0,c);
            c=c-1;
            move(b,c);          //复杂度为O(log(n))
        }
    }

    private static void beBigHeap(int[] b, int index) {
//      通过不断与父结点进行比较交换,变为大根堆
        while (b[index]>b[(index-1)/2]){
            swap(b,index,(index-1)/2);
            index=(index-1)/2;
        }

    }
    private static void swap(int[] b,int i,int j){
        int t=b[i];
        b[i]=b[j];
        b[j]=t;
    }
    private static void move(int[] b,int last){
        int index=0;
        int left=index*2+1;
        int right=index*2+2;
        int flag=left;
//        last为无序部分的最后一个
        while (left<=last){
//           右孩子存在,并且右孩子大于左孩子
            if(right<=last&&b[left]<b[right]){
                flag=right;
            }
//            左孩子大于右孩子
            else {
                flag=left;
            }
//            如果当前的index的关键字已经比左右孩子中的较大者的关键字大,说明其子树已经是个大根堆,不需要再往下进行
            if(b[index]>=b[flag]){
                break;
            }
            swap(b,index,flag);
//            继续将子树也变成大根堆
            index=flag;
            left=index*2+1;
            right=index+2+2;
        }


    }
}

小结:

,flag);
// 继续将子树也变成大根堆
index=flag;
left=index*2+1;
right=index+2+2;
}

}

}


### 小结:

堆排序的复杂度为O(n*log(n)),重新复习数据结构与算法,堆排序以前课上讲过,不过不是重点,所以也没太关注,现在大三巩固,这个算法确实妙啊,我是先了解堆排序的思想后再自己写代码,其中在heapify中试错了几次,学spring去了,现在回到算法感觉好生疏,还是要坚持学习算法,加油共勉!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值