分桶排序

  桶排序采用了分而治之的思想。在处理大量数据的排序时,如果收到内存和时间的限制时,我们将数据进行拆分到小单元,单元内进行排序,这样就可以使用小内存排序大数据。也可以使用多线程排序小单元数据,最后进行数据合并完成整个数据的排序。

在桶排序中关键点是数据分桶的处理。如果需要排序的数据不是线性递增的,就可能导致分桶数据不均匀,极端情况出现数据全部分到一个桶中,编程单个算法排序了。桶排序适合均匀分布的相对比较密集的数据

代码demo实现

import java.util.ArrayList;
import java.util.List;
/** * @author zhw * @description * @date 2021-04-13 19:27 */
public class BucketSort {
   
	//设置桶内数据大小
    private static final int BUCKET_SIZE = 10;

    public Integer[] bucketSort(Integer[] arr){
   
    	//桶数量
        int bucketNumber = arr.length % BUCKET_SIZE == 0 ? arr.length / BUCKET_SIZE : arr.length / BUCKET_SIZE + 1;
        //桶创建
        Bucket[] buckets = new Bucket[bucketNumber];
        for (int i = 0;i<buckets.length;i++){
   
            buckets[i] = new Bucket();
        }
        //数据分桶
        for(int i = 0;i<arr.length;i++){
   
            int index = arr[i] / bucketNumber;
            //将空间一致的数据分到同一个桶中
            Bucket bucket = buckets[index>bucketNumber?bucketNumber-1:index];
            bucket.add(arr[i]);
        }
        //开始排序
        int index = 0;
        for(int i = 0;i<buckets.length;i++){
   
            Integer[] sort = buckets[i].sort();
            //数据合并
            for(int j = 0;j<sort.length;j++){
   
                arr[index++] = sort[j];
            }
        }
        return arr;
    }
    private class Bucket{
   
    	//桶内计数
        private int num = 0;
        List<Integer> data = new ArrayList<>();
        public Bucket add(Integer d){
   
            num++;
            data.add(d);
            return this;
        }
        public Integer[] sort(){
   
            Integer[] integers = data.toArray(new Integer[data.size()]);
            quickSort(integers);
            return integers;
        }
		//桶内使用快排
        private void quickSort(Integer[] arr){
   
            qsort(arr, 0, arr.length-1);
        }
        private void qsort(Integer[] arr, int low, int high){
   
            if (low < high){
   
                int pivot=partition(arr, low, high);        //将数组分为两部分
                qsort(arr, low, pivot-1);                   //递归排序左子数组
                qsort(arr, pivot+1, high);                  //递归排序右子数组
            }
        }
        private int partition(Integer[] arr, int low, int high){
   
            int pivot = arr[low];     //枢轴记录
            while (low<high){
   
                while (low<high && arr[high]>=pivot) --high;
                arr[low]=arr[high];             //交换比枢轴小的记录到左端
                while (low<high && arr[low]<=pivot) ++low;
                arr[high] = arr[low];           //交换比枢轴小的记录到右端
            }
            //扫描完成,枢轴到位
            arr[low] = pivot;
            //返回的是枢轴的位置
            return low;
        }

    }
}

测试

public class Test {
   
    public static void main(String[] args) {
   
        BucketSort bucketSort = new BucketSort();
        Integer[] a = {
   2,3,4,5,676,74,23,4,5,6,1,23,4,5,323,542,35,435,234,53,1324,345,3453,1234};
        Integer[] integers = bucketSort.bucketSort(a);
        System.out.println(Arrays.asList(integers).toString());
    }
}

从10亿数据中找出中位数?

假设这10亿数据都是无符号整数。我们可以创建2^16个桶。我们取数据中的高16位进行分桶,分桶方式如下:

每个桶都记录桶中数据数量num,然后将各个桶的num相加,得到中位数落到哪个桶内,然后将桶内数据进行排序后得到中位数。