刷题笔记:排序算法总结(计数、桶排、基数)

计数排序

计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数
算法步骤:

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

代码如下:
下述代码事实上还可以进行优化,即新建的tmp的大小可以限制为max-min+1。

	public static int[] sort(int[] nums){
    
    
//        int min=Integer.MAX_VALUE;
        int max=-Integer.MAX_VALUE;
        int[] res=new int[nums.length];

        for (int i=0;i<nums.length;i++){
    
    
            if (nums[i]>max)
                max=nums[i];
//            if (nums[i]<min)
//                min=nums[i];
        }

        int[] tmp=new int[max+1];

        for (int num:nums){
    
    
            tmp[num]+=1;
        }

        int count=0;
        for (int i=0;i<tmp.length;i++){
    
    
            while (tmp[i]!=0) {
    
    
                res[count++] = i;
                tmp[i]--;
            }
        }
        return res;
    }

桶排序

桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。
算法步骤:

  • 设置一个定量的数组当作空桶;
  • 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  • 对每个不是空的桶进行排序;
  • 从不是空的桶里把排好序的数据拼接起来。
    在这里插入图片描述
	public static double[] bucketSort(double[] arr) {
    
    
        double max=-Integer.MAX_VALUE;
        double min=Integer.MAX_VALUE;

        int bucketNum=arr.length;

        for (int i=0;i<arr.length;i++){
    
    
            if (max < arr[i]){
    
    
                max = arr[i];
            }
            if (arr[i] < min){
    
    
                min = arr[i];
            }
        }

        double d = max - min;
        //初始化桶
        List<LinkedList<Double>> bucketList = new ArrayList<>(bucketNum);
        for (int i = 0; i < bucketNum; i++) {
    
    
            bucketList.add(new LinkedList<>());
        }

        //将元素加入到桶中
        for (int i=0;i<arr.length;i++){
    
    
            int num=(int)((arr[i]-min)/(d/(bucketNum-1)));
            bucketList.get(num).add(arr[i]);
        }

        for (int i=0;i<bucketNum;i++){
    
    
            Collections.sort(bucketList.get(i));
        }

        //输出元素
        int cnt=0;
        for (List<Double> bucket:bucketList){
    
    
            for (Double s:bucket){
    
    
                arr[cnt++]=s;
            }
        }
        return arr;
    }

基数排序

这种是一种非比较排序的方法。按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。
算法步骤:

  • 取得数组中的最大数,并取得位数;
  • arr为原始数组,从最低位开始取每个位组成radix数组;
  • 对radix进行计数排序(利用计数排序适用于小范围数的特点);

在这里插入图片描述

	public static int[] sort(int[] nums){
    
    
        int max=-Integer.MAX_VALUE;
        int exp;

        for (int num:nums){
    
    
            if (num>max)
                max=num;
        }

        for (exp=1;max/exp>0;exp*=10){
    
    
            int[] tmp=new int[nums.length];
            //任何一位数只能在0-9
            int[] buckets=new int[10];

            for (int value:nums){
    
    
                buckets[(value/exp)%10]++;
            }

            //这块进行累加的原因是,确保基数较大的元素能够排在后面,这个针对的是升序排序,然后原本的数组从后往前遍历。如果是降序排序,则基数数组的首位值最大,原数组从前往后遍历。
            //上面这么做的目的是为了维持稳定性
            for (int i = 1; i < 10; i++){
    
    
                buckets[i] += buckets[i - 1];
            }

            for (int i=nums.length-1;i>=0;i--){
    
    
                tmp[buckets[(nums[i]/exp)%10]-1]=nums[i];
                buckets[(nums[i]/exp)%10]--;
            }

            System.arraycopy(tmp,0,nums,0,nums.length);
        }
        return nums;
    }

猜你喜欢

转载自blog.csdn.net/qq_35531985/article/details/112295264
今日推荐