• 排序


    前言

    排序算法是一个老生常谈问题,目前主要学习了选择排序、冒泡排序、插入排序、归并排序、随机快排、堆排序、计数排序、基数排序,一共八种排序方式。

    名称解释

    稳定性: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

    打印int的二进制

    代码

     public  void print(int number){
            for (int i = 31; i >= 0; i--) {
                /**
                 * << 向左移动,空位补0,被移除的高位丢企
                 * >> 带符号向右移动
                 * >>> 不带符号向右移动 空位补0
                 * & 按位与 1和1 为1 其他为0
                 * | 任何二进制位和0进行0, 任何二进制和1进行为1
                 * ^ 按位异或 任何相同二进制位进行^运算,结果是0;不相同二进制位^运算结果是1.
                 * ~ 运算符 对位求反 1变0, 0变1
                 **/
                System.out.print((number&(1<<i))==0?"0":"1");
            }
        }
    

    选择排序

    代码

    public void selectSort(int[] numbers){
            if (numbers==null||numbers.length<2){
                return;
            }
           for (int i=0;i<numbers.length;i++){
               int min=i;
               for (int j=i+1;j<numbers.length;j++){
                  min= numbers[min]>numbers[j]?j:min;
               }
               exchange(numbers,i,min);
           }
    
        }
    

    冒泡排序

    代码

        public void bubbleSort(int[] numbers){
            if (numbers==null||numbers.length<2){
                return;
            }
            for (int i=numbers.length-1;i>=0;i--){
                for(int j=0;j<i;j++){
                    if (numbers[j]>numbers[j+1]){
                        exchange(numbers,j,j+1);
                    }
                }
            }
        }
    

    插入排序

    代码

    public void insertSort1(int[] numbers){
            if (numbers==null||numbers.length<2){
                return;
            }
            for(int i=0;i<numbers.length;i++){
                for (int j=i;j>0&&numbers[j]<numbers[j-1];j--){
                    exchange(numbers,j,j-1);
                }
            }
        }
    

    归并排序

    代码

      public void sortArrRecursive(int[] arr,int L,int R){
            //如果L==R则不要进行最后的细分
            if (L==R){
                return;
            }
            int mid=(L+R)/2;
            sortArrRecursive(arr,L,mid);
            sortArrRecursive(arr,mid+1,R);
            merge(arr,L,mid,R);
            System.out.println("排序后:"+Arrays.toString(arr));
        }
    
        /**
         * description 将左右两边进行排序后放回原数组中
         * param [arr, l, mid, r]
         * return void
         * author zhuyang
         * createTime 2021/12/1 22:58
         **/
        private void merge(int[] arr, int l, int mid, int r) {
            int i=0;
            int[] help=new int[r-l+1];
            int q=mid+1;
            int OneL=l;
            while (l<=mid&&q<=r){
                help[i++]=arr[l]<arr[q]?arr[l++]:arr[q++];
            }
            while (l<=mid){
                help[i++]=arr[l++];
            }
            while (q<=r){
                help[i++]=arr[q++];
            }
            for (int i1 = 0; i1 < help.length; i1++) {
                arr[OneL++]=help[i1];
            }
    
        }
    

    随机快排

    代码

    public void sort(int[] arr,int l,int r){
            if (l>=r){
                return;
            }
            //这一步将随机生成的l和r进行交换,复杂度就变成了O(logN+N)
            exchange(arr, l+(int)(Math.random()*(r-l+1)), r);
            int[] process = process(arr, l, r);
            sort(arr,l,process[0]-1);
            sort(arr,process[1]+1,r);
        }
        
        /**
         * @Description: 数组arr, 以arr[r]为分界,<=arr[r]的数在左边,
         *               大于的在右边,等于的在中间,每次排序都会排好等于arr[r]的数,然后再排下一个
         * @Author: zhuyang
         * @Date:  2021-12-26
         * @Param: 
         * @return: 
         **/
        public int[] process(int[] arr,int l,int r){
            if (l>=r){
                return new int[]{-1,-1};
            }
            if (l==r){
                return new int[]{l,r};
            }
            int curL=l-1;
            int currR=r;
            int index=l;
            while (index<currR){
                if (arr[index]>arr[r]){
                    exchange(arr,index,--currR);
                }else if (arr[index]<arr[r]){
                    exchange(arr,index++,++curL);
                }else {
                    index++;
                }
            }
            //最后进行r的交换
            exchange(arr,currR,r);
    
            //进行返回
            return new int[]{curL+1,currR};
        }
    

    堆排序

    代码

    public  void heapSort(int[]  arr){
    //        for (int i = 0; i < arr.length; i++) {
    //            insertValue(arr,i);
    //        }
            //该for循环也可以将该数组变成大顶堆
            for (int i = arr.length-1; i >=0; i--) {
                heapify(arr,i,arr.length-1);
            }
            //进行交换,将大顶堆的最开始的非叶子结点进行交换
            exchange(arr,0,arr.length-1);
            //再进行排序,同时排查最末尾元素
            int index=arr.length-1;
            while (index>0){
                heapify(arr,0,index);
                exchange(arr,0,--index);
            }
    
        }
        /**
         * @Description: 将最大元素排至最初非叶子结点
         * @Author: zhuyang
         * @Date:  2021-12-09
         * @Param:
         * @return:
         **/
        private  void heapify(int[] arr, int i, int index) {
            int left=2*i+1;
            while (index>left&&arr[i]<arr[left]){
                int bigIndex=left+1<index&&arr[left+1]>arr[left]?left+1:left;
                int bigNum=arr[bigIndex]>arr[i]?bigIndex:i;
                //当arr[i]即为最大值时,停止交换
                if (i==bigNum){
                    break;
                }
                exchange(arr,i,bigIndex);
                i=bigIndex;
                left=2*i+1;
            }
        }
    

    计数排序

    代码

    /**
         * @Description: 计数排序 计数排序要求,样本是正整数,且范围比较窄
         * @Author: zhuyang
         * @Date:  2021-12-12
         * @Param:
         * @return:
         **/
        public void sortProcess(int[] arr){
            if (arr==null||arr.length==1){
                return;
            }
            //进行计算最大值
            int num= Integer.MIN_VALUE;
            for (int i : arr) {
                num=Math.max(num,i);
            }
            //进行创建桶
            int[] bucket=new int[num+1];
            for (int i = 0; i < arr.length; i++) {
                bucket[arr[i]]++;
            }
            //进行重新排序
            int index=0;
            for (int i = 0; i < bucket.length; i++) {
                while (--bucket[i]>=0){
                    arr[index++]=i;
                }
            }
        }
    

    基数排序

    代码

    /**
         * @Description: 桶排序思想下的排序:基数排序
         *               基数排序要求,样本是10进制的正整数
         * @Author: zhuyang
         * @Date:  2021-12-26
         * @Param: 
         * @return: 
         **/
        public void sortProcess(int[] arr){
            //求最大值
            int max=Integer.MIN_VALUE;
            for (int i : arr) {
                max=Math.max(max,i);
            }
            //获取其深度
            int depth=getDepth(max);
            //进行再次排序
            sortProcess(arr,0,arr.length,depth);
        }
    
        private void sortProcess(int[] arr, int l, int r, int depth) {
            //创建10个桶,因为是10进制 0~9
    
            int[] help=new int[r-l];
            //进行深度遍历
            for (int i = 0; i < depth; i++) {
                int[] barrel=new int[10];
                //进行求arr的每一个数的每一个位数上,总的个数
                for (int i1 = l; i1 < r-l; i1++) {
                    barrel[getDigits(arr[i1],i)]++;
                }
                //进行归并和
                for (int i1 = 1; i1 < barrel.length; i1++) {
                    barrel[i1]=barrel[i1]+barrel[i1-1];
                }
                //进行入桶
                for (int i1 = l; i1 <  r-l; i1++) {
                    int digits = getDigits(arr[i1], i);
                    help[barrel[digits]-1]=arr[i1];
                    barrel[digits]--;
                }
                System.out.println(Arrays.toString(help));
                //进行出桶 出桶这很重要 一定要遵循先入后出原则
                int index=0;
                for (int i1 = r-l-1; i1 >= 0; i1--) {
                    arr[i1]=help[index++];
                }
            }
        }
    
        public int getDepth(int number){
            int num=0;
            while (number>0){
                number=number/10;
                num++;
            }
            return num;
        }
    
        /**
         * @Description: 数 1234324 可以分别取出  1 2 3 4 3 2 4
         * @Author: zhuyang
         * @Date:  2021-12-12
         * @Param:
         * @return:
         **/
        public int getDigits(int number,int depth){
            int pow =(int) (number/(Math.pow(10, depth))%10);
            return pow;
        }
    

    稳定性,时间复杂度,空间复杂度

    image

    总结

    基数排序要求,样本是10进制的正整数,计数排序要求样本必须是正整数。

    Gitee地址

    https://gitee.com/zhuayng/foundation-study/tree/develop/JavaBasis

    XFS
  • 相关阅读:
    H5中获取图片中的主色调
    vue provide/inject响应式
    微信小程序入坑之路
    H5入坑之路
    uni-app状态栏相关问题
    uni-app使用iconfont相关
    uni-app入坑之路
    uni-app自定义导航栏(搜索框和按钮)
    浅析浏览器的渲染过程
    SAP ABAP MB51新增栏位字段
  • 原文地址:https://www.cnblogs.com/xiaofengshan/p/15733614.html
Copyright © 2020-2023  润新知