排序算法之桶排序
桶排序算是计数排序的一种改进和推广,要比计数排序复杂许多。
桶排序的基本思想:
假设有一组长度为N的待排关键字序列K[1….n]。首先将这个序列划分成M个的子区间(桶)。然后基于某种映射函数 ,将待排序列的关键字k映射到第i个桶中(即桶数组B的下标 i) ,那么该关键字k就作为B[i]中的元素(每个桶B[i]都是一组大小为N/M的序列)。接着对每个桶B[i]中的所有元素进行比较排序(可以使用快排)。然后依次枚举输出B[0]….B[M]中的全部内容即是一个有序序列。bindex=f(key) 其中,bindex 为桶数组B的下标(即第bindex个桶), k为待排序列的关键字。桶排序之所以能够高效,其关键在于这个映射函数,它必须做到:
如果关键字k1 < k2,那么f(k1)<=f(k2)。也就是说B(i)中的最小数据都要大于B(i-1)中最大数据。很显然,映射函数的确定与数据本身的特点有很大的关系。
对N个关键字进行桶排序的时间复杂度分为两个部分:
- 循环计算每个关键字的桶映射函数,这个时间复杂度是O(N)。
- 利用先进的比较排序算法对每个桶内的所有数据进行排序,其时间复杂度为 ∑ O(Ni*logNi) 。其中Ni 为第i个桶的数据量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public class BucketSort {
public static void bucketSort(int[] arr) { if(arr == null && arr.length == 0) return ;
int bucketNums = 10; //这里默认为10,规定待排数[0,100) List<List<Integer>> buckets = new ArrayList<List<Integer>>(); //桶的索引
for(int i=0; i<10; i++) { buckets.add(new LinkedList<Integer>()); //用链表比较合适 }
//划分桶 for(int i=0; i<arr.length; i++) { buckets.get(f(arr[i])).add(arr[i]); }
//对每个桶进行排序 for(int i=0; i<buckets.size(); i++) { if(!buckets.get(i).isEmpty()) { Collections.sort(buckets.get(i)); //对每个桶进行快排 } }
//还原排好序的数组 int k = 0; for(List<Integer> bucket : buckets) { for(int ele : bucket) { arr[k++] = ele; } } } //映射函数 public static int f(int x) { return x / 10; } }
|