排序---桶排序

7.桶排序

  桶排序不同与前几种排序,它不是基于比较的排序方式,而是基于数据状况的排序,我们设置一个定量的数组当做空桶子,寻访序列,并且把项目一个一个放到对应的桶子去,对每个不是空的桶子进行排序,从不是空的桶子里把项目再放回原来的序列,排序结束。

  基于桶排序的计数排序,时间复杂度为O(n),空间复杂度也为O(n)

public class Sort{
    public static void bucketSort(int []arr){
        if(arr==null||arr.length<2)
            return ;
        int max=Integer.MIN_VALUE;
        for(int i=0;i<arr.length;i++){
            max=Math.max(max,arr[i]);
        }
        int []bucket=new int[max+1]; //桶的下标代表数组中数值的大小,所以桶的长度要为数组中的最大值
        for(int i=0;i<arr.length;i++){
            bucket[arr[i]]++; //记数排序,相同值出现的次数
        }
        int i=0;
        for(int j=0;j<bucket.length;j++){
            while(bucket[j]-->0)
                arr[i++]=j  //将排好的数存会原数组
        }
    }
}

​  基于桶的概念延伸出来的一道题,对于一个无序数组,我们希望得出有序后相邻两个数间最大的差值。时间复杂度要求O(n)

public class MaxGap{
    public static int maxGap(int []nums){
        if(nums==null||nums.length<2)
            return 0;
        int len=nums.length;//记录数组的长度
        int min=Integer.MAX_VALUE; //数组中最小的元素
        int max=Integer.MIN_VALUE;//数组中最大的元素
        for(int i=0;i<len;i++){
            min=Math.min(min,nums[i]);
            max=Math.max(max,nums[i]);
        }
        if(min==max)
            return 0;
        //桶的数量为数组的长度加一,
        boolean []hasNum=new boolean[len+1]; //表示桶里是否有数字
        int []maxs=new int[len+1]; 
        int []mins=new int[len+1]; //每个桶中只存放这个桶内的最大值和最小值
        int bid=0; //桶的下标
        for(int i=0;i<len;i++){
            bid=bucket(nums[i],len,min,max); //nums[i]应该放到哪个桶里
            mins[bid]=hasNum[bid]?Math.min(mins[bid],nums[i]):nums[i];
            maxs[bid]=hasNum[bid]?Math.max(maxs[bid],nums[i]):nums[i];
            hasNum[bid]=true;
        }
        //计算相邻非空桶中左桶的最大值和右桶的最小值的差值,找到最大的返回。
        int res=0;
        int lastMax=maxs[0]; //非空左桶的最大值
        int i=1;
        for(;i<=len;i++){
            if(hasNum[i]){
                res=Math.max(res,mins[i]-lastMax);
                lastMax=maxs[i];
            }
        }
        return res;
    }
    public static int bucket(long num,long len,long min,long max){//计算num应该存放在哪个桶
        return (int)((num-min)*len/(max-min));
    }
}

桶排序的延伸题目:

  出现频率最多的K个数

347. Top K Frequent Elements (Medium)

Given [1,1,1,2,2,3] and k = 2, return [1,2].

  设置若干个桶,每个桶存储出现频率相同的数,并且桶的下标代表桶中出现数的频率,即第i个桶中存储的数出现的频率就是i。

把数都放到桶之后,从后向前遍历桶,最先得到的k个数就是出现频率最多的k个数。

public List<Integer>topKFrequent(int []nums,int k){
    Map<Integer,Integer>map=new HashMap<>();
    for(int i=0;i<nums.length;i++){
        map.put(nums[i],map.getOrDefault(nums[i],0)+1);
    }
    List []bucket=new ArrayList[nums.length+1];//构建桶,桶的下标代表数字出现的频率
    for(int key:map.keySet){
        int freqence=map.get(key);
        if(bucket[frequence]==null){
            bucket[frequence]=new ArrayList<>();
            }
        bucket[frequence].add(key);
    }
    List<Integer>res=new ArrayList<>();
    for(int i=bucket.length-1;i>=0&&res.size()<k;i--){
        if(bucket[i]==null)
            continue;
        if(bucket[i].size<=k-res.size())
            res.addAll(bucket[i]);
        else
            res.addAll(bucket[i].subList(0.k-res.size()));
    }
    return res;
}

猜你喜欢

转载自www.cnblogs.com/yjxyy/p/11104318.html