非比较排序(计数排序、桶排序、基数排序)

1、计数排序

1、找出待排序的数组中最大和最小的元素
2、统计数组中每个值为 i的元素出现的次数,存入数组 C 的第i项
3、 对所有的计数累加 (从C中的第一个元素开始,每一项和前一项相加)
4、 反向填充目标数组:将每个元素 i放在新数组的第 C[i]项,每放一个元素就将 C[i]减去1
                                  -维基百科

import java.util.Arrays;

/*A:待排序数组   B:辅助数组 C新数组
* ①找出数组A中的最大值和最小值
* ②遍历每个元素,把值为X的元素出现的次数,存到B[X]
* ③从第一项开始,分别计算B[X]与B[X-1]的和,并存到B[X]中(得到X元素前有多少个元素)
* ④依次将B数组中i放到C[i],每放一次,B[i]--
* */
public class CountingSort {

    public static void main(String[] args) {
        System.out.println("未排序前的A:");
        int[]A={2,10,28,19,30,30,28,1,0,29,10,20,20,10,19,29};
        System.out.println(Arrays.toString(A));
        System.out.println("使用计数排序后的A:");
        System.out.println(Arrays.toString(countingsort(A)));
    }
    public static int[] countingsort(int []A){
        //①找最大值和最小值
        int max=Integer.MIN_VALUE;
        int min=Integer.MAX_VALUE;
        for (int i = 0; i <A.length ; i++) {
                min=Math.min(min,A[i]);
                max=Math.max(max,A[i]);
        }
        //②遍历每个元素,把值为X的元素出现的次数,存到B[X]
        int[]B=new int[max-min+1];
        for (int i = 0; i <A.length ; i++) {
            B[A[i]]++;
        }
        //③将数组 B中的元素i,放到新数组C上,每放一次B[i]--
        int [] C=new int[A.length];
        int j=0;
        for (int i = 0; i < B.length; i++) {
            while (B[i]!=0){
                C[j++]=i;
                B[i]--;
            }

        }
    return C;
    }
}
时间复杂度:   

当输入的元素是 n个 0 到 k 之间的整数时,它的运行时间是 O(n+k)

2、桶排序

①找到待排序的数组A的min和max
②桶的数量(A.length)
③遍历数组A,把每个元素放到对应的桶中
④对每个桶的内部进行排序
⑤遍历每个桶

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

/*
①找到待排序的数组A的min和max
②桶的数量(max-min)/(A.length)+1
③遍历数组A,把每个元素放到对应的桶中
④对每个桶的内部进行排序
⑤遍历每个桶
 */
public class BucketSorting {
    public static void main(String[] args) {
        System.out.println("未排序前的A:");
        int[]A={0,30,0,28,19,30,30,28,1,0,29,10,20,20,10,19,29};
        System.out.println(Arrays.toString(A));
        System.out.println("使用桶排序后的A:");
        System.out.println(Arrays.toString(bucketsort(A)));
    }

    private static int[] bucketsort(int[] A) {
        int max=Integer.MIN_VALUE;
        int min=Integer.MAX_VALUE;
        //找最值
        for (int i = 0; i <A.length ; i++) {
            max=Math.max(max,A[i]);
            min=Math.min(min,A[i]);
        }
        //计算桶的数目
        int buckets=A.length;
        //把A中的元素分别放到对应的桶中,用ArrayList来实现桶
        ArrayList<ArrayList<Integer>> bucketArray=new ArrayList<>(buckets);
        for (int i = 0; i <buckets ; i++) {
            bucketArray.add(new ArrayList<Integer>());

        }
        //遍历元素,并放到桶里面
        for (int i = 0; i <A.length ; i++) {
            int bucketsNum=getBucket(A[i],buckets,min,max);
            bucketArray.get(bucketsNum).add(A[i]);

        }
        //对每个桶内部进行排序
        for(int i = 0; i < bucketArray.size(); i++){
            Collections.sort(bucketArray.get(i));
        }
        System.out.println(bucketArray.toString());
        //合并每个桶
        int count=0;
        int[] result=new int[A.length];
        for(int i = 0; i < bucketArray.size(); i++){

            for (int j=0;j<bucketArray.get(i).size();j++){
                    result[count]=bucketArray.get(i).get(j);
                    count++;
            }

        }



        return result;
    }
    public static int getBucket(int num,int buckets,int min,int max){
        return  (int)((num-min)*(buckets-1)/(max-min));
//(num-min)/(max-min)表示这个数在(max-min)所占比重,
//再乘以桶的个数就得到对应桶的编号
    }

时间复杂度:
当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间O(n)

3、基数排序

基数排序(英语:Radix sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

基数排序的核心思想就是:按照从低位到高位依次比较排序

算法如下:
输入:待排序的数组A

  ①创建10个桶,编号分别0,1,2,3…9,每个桶可容纳的元素为A.length个元素
   int[ ] [ ] bucket=new int [10 ][A.length ];
  ②依次取A中元素的个位进行排序,覆盖原数组
     取A中元素的十位进行排序
     取A中元素的百位进行排序
           .
           .
           .
  

 

代码
import java.util.Arrays;
public class RadixSorting {
    public static void radixsorting(int[] A){
        //创建10个桶,每个桶可以放A.length个元素
       int[][] bucket=new int[10][A.length];
       //找出最大值和最小值,并确定有几位(也可以手动给出)
        int min=Integer.MAX_VALUE;
       int max =Integer.MIN_VALUE;
        for (int i = 0; i <A.length ; i++) {
             max=Math.max(A[i], max);
             min=Math.min(A[i],min);
        }
        int maxcopy=max;
        int digits=0;
        while(maxcopy!=0){
            maxcopy=maxcopy/10;
            digits++;
        }
        //控制分离数字的每一位
        int split= 1;
        for (int i = 1; i <digits+1 ; i++) {
            int[] bucketmessage=new int[10];//用来记录每个桶内有多少个数字
            //用num来分离,数字的每一位
            int bnum=0;
            for (int j = 0; j < A.length; j++) {
                bnum=(A[j]/split)%10;
                bucket[bnum][bucketmessage[bnum]]=A[j];
                bucketmessage[bnum]++;
            }
            //把排过序的桶里面的数据取出来覆盖,A
            int count1=0;
            int count2=0;
            for (int j = 0; j < 10; j++) {
                while (bucketmessage[j]!=0){
                    A[count1++]=bucket[j][count2++];
                    bucketmessage[j]--;

                }
                count2=0;
            }
            split=split*10;
        }
    }
    public static void main(String[] args) {
        int [] A={10,123,348,123,442,567,89,38,109,108,75,118,234,289,530};
        System.out.println("未排序前的A数组");
        System.out.println(Arrays.toString(A));
        radixsorting(A);
        System.out.println("排序后的A数组");
        System.out.println(Arrays.toString(A));
    }
}


#4、练习:桶排序的扩展应用

  给定一个数组, 求如果排序之后, 相邻两数的最大差值, 要求时 间复杂度O(N), 且要求不能用非基于比较的排序。

分析:
①待排序数组A有n个元素,那么就构建n+1个桶,那么肯定会有空桶存在,由此可以推断出,最大差值不在桶的内部,可定在相邻的桶之间;
②构建三个数组
·int [ ] hasnum : 用来记录桶中是否含有元素;
·int [ ] mins :用来桶中的最小值
·int [ ] maxs :用来桶中的最大值
③从编号为1的桶,依次取桶最小值-前一个桶的最大值,从而得到最大差值。

代码如下:

import java.util.Arrays;
public class exercise_maxGap {
    public  static int maxgap(int[]A){
        int[] bucket=new int[A.length+1];
        int max=Integer.MIN_VALUE;
        int min=Integer.MAX_VALUE;
        for (int i = 0; i <A.length ; i++) {
            min=Math.min(min,A[i]);
            max=Math.max(max,A[i]);
        }
        int getBnum=0;
        boolean[]hasnum= new boolean[A.length + 1];
        int[]mins  = new int[A.length+1];
        int[]maxs  = new int[A.length+1];
        //把数组中的每个元素都放到桶中,并记录桶内的最大值和最小值
        for (int i = 0; i <A.length ; i++) {
            getBnum=(int)((A[i]-min)*(A.length))/(max-min);
          mins[getBnum]=hasnum[getBnum] ? Math.min(A[i],mins[getBnum]):A[i];
          maxs[getBnum]=hasnum[getBnum] ? Math.max(A[i],maxs[getBnum]):A[i];
          hasnum[getBnum]=true;
        }
        //开始找最大差值了
        int result=0;
        int lastmax=maxs[0];
        for (int i = 1; i <A.length ; i++) {
                if (hasnum[i]==true){
                    result=Math.max(result,mins[i]-lastmax);
                     lastmax=maxs[i];
                }
        }
        return result;
    }
    public static void main(String[] args) {
        int [] A={10,123,348,123,442,567,89,38,109,108,75,118,234,289,530};
        System.out.println("A数组:");
        System.out.println(Arrays.toString(A));
        System.out.println("相邻的数字间最大的差值为:");
        System.out.println(maxgap(A));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值