排序——计数排序&&基数排序&&桶排序

121 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第28天,[点击查看活动详情]

这三个排序属于非比较大小的 堆排序之前要把最大堆和最小堆建出来。

计数排序

CountingSort
只能对数字,或者关键字是数字的主的排序。
字符串不能。
是桶排序的一种。
将数字和角标对应起来,角标是递增的,角标对应的格子就是次数。 牺牲空间换时间。

原理

将输入的数据值转化为键存储在额外开辟的数组空间中
线性时间复杂度的排序
输入的数据必须有确定范围的整数。
index+offset=num

特点

时间复杂度:O(n+m)
空间复杂度:O(n+m)
是稳定的

代码

public class CountingSort{
    public static void main(String[] args){
        int[] arr = new int[20];
        Random random=new Random();
        for(int i =0;i<arr.length;i++){
            arr[i]=random.nextInt(50);
        }
        countingSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    private static void countingSort(int[] arr){
        //1,获取最大值和最小值
        int max=arr[0];
        int min=arr[0];
        for(int i=1;i<arr.length;i++){
            if(arr[i]>max){
                max=arr[i];
            }
            if(arr[i]<min){
                min=arr[i];
            }
        }
        //2,创建辅助数组
        int[] temp=new int[max-min+1];
        int offset=min-0;
        
        //3,遍历原数组,将数组的个数统计在新数组中
        for(int i=0;i<arr.length;i++){
            temp[arr[i]-offset]++;
        }
        //4,遍历新数组temp,将统计结果处理
        int index=0;
        for(int i=0;i<temp.length;i++){
            if(temp[i]!=0){
                for(int j=0;j<temp[i];j++){
                    arr[index++]=i+offset;
                }
            }
        }
    }
}

桶排序

BucketSort
是计数排序的升级。
一堆数字针对一个角标。
利用函数的映射关系。确定映射函数

原理

假设数据均匀分布,将数据分到有限数量的桶里,每个桶再分别排序。->递归

特点

时间复杂度:O(n+m)
空间复杂度:O(n+m)
是稳定的
一个桶了就是插入排序
速度与和桶的个数有关。

public class BucketSort{
    public static void main(String[] args){
        int[] arr=new int[20];
        Random random=new Random();
        for(int i = 0;i<arr.length;i++){
            arr[i]=random.nextInt(50);
        }
        bucketSort(arr);
        System.out.println(ArraystoString(arr));
    }
    private static void bucketSort(int[] arr){
        //获取最大值和最小值
        int max=arr[0];
        int min=arr[0];
        for(int i=1;i<arr.length;i++){
            if(arr[i]>max){
                max=arr[i];
            }
            if(arr[i]<min){
                min=arr[i]
            }
        }
        
        //计算桶的数量
        int bucketNum=(max-min)/arr.length+1;
        
        //创建所有的桶
        ArrayList<Integer>[] buckets=new ArrayList[bucketNum];
        for(int i=0;i<buckets.length;i++){
            buckets[i]=new ArrayList<>();
        }
        
        //遍历元素分别进桶
        for(int i=0;i<arr.length;i++){
            buckets[(arr[i]-min)/arr.length].add(arr[i]);
        }
        
        //对每一个桶进行排序
        for(int i=0;i<buckets.length;i++){
            buckets[i].sort(new Comparator<Integer>(){
                @Override
                public int compare(Integer o1,Integer o2){
                    return o1.compareTo(o2);
                }
            });
            System.out.println(i+":"+buckets[i]);
        }
        
        //将桶中的数据放置到原数组中
        int index = 0;
        for(int i = 0;i<buckets.length;i++){
            //while(!buckets[i].isEmpty()){
            //    arr[index++]=buckets[i].remove(0);
            //}
            for(int j=0;j<buckets[i].size();j++){
                arr[index++]=buckets[i].get(j);
            }
        }
    }
}

基数排序

RadixSort

原理

是按照低位先排序,后收集,再按高位排序,后收集。依次,->到最高位。
数论
最大最小的差值,中间过多的元素空插,会影响速率。

特点

时间复杂度:O(n+m)
空间复杂度:O(n+m)
稳定的

代码

public class RadixSort{
    public stayic void main(String[] args){
        int[] arr=new int[20];
        Random random = new Random();
        for(int i = 0;i<arr.length;i++){
            arr[i]=random.nextInt(50);
        }
        radixSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    private static void radixSort(int[] arr){
        //找到最大值
        int max=arr[0];
        for(int i=1;i<arr.length;i++){
            if(arr[i]>max){
                max=arr[i];
            }
        }
        //计算位数
        int radix = (max+"").length();
        //创建桶
       // ArrayLoopQueue循环队列
        //ArrayDeque双端队列
        ArrayLoopQueue<Integer>[] buckets = new ArrayLoopQueue[10];
        for(int i = 0;i<buckets.length;i++){
            buckets[i]=new ArrayLoopQueue<>();
        }
        for(int r=1;r<=radix;r++){
            for(int i=0;i<arr.length;i++){
                buckets[getIndex(arr[i],r)].offer(arr[i]);
            }
            int index=0;
            for(int i=0;i<buckets.length;i++){
                while(buckets[i].isEmpty()){
                    arr[intdex++]=buckets[i].poll();
                }
            }
        }
        
    }
    
    private static int getIndex(int num,int r){
        int ret=0;
        for(int i =1;i<=r;i++){
            ret=num%10;
            num/=10;
        }
        return ret;
    }
}

JAVA虚拟机栈会自动扩容的。
还有种猴子排序。点坐标与点坐标之间进行交换。