经典的排序算法,桶排序,用到了桶的概念

0准备

 1//建立一个排序用的顺序表结构L
 2#define MAXSIZE 9
 3typedef struct SqList
 4{
 5    int r[MAXSIZE];
 6    int length;
 7}SqList;
 8/*排序的交换函数*/
 9void swap(SqList* L,int i,int j)
10{
11    int temp = L->r[i];
12    L->r[i] = L->r[j];
13    L->r[j] = temp;
14}

桶排序(BucketSort)

桶排序是计数排序的升级版。

桶排序(Bucket sort)的工作的原理

假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序)。

C的版本

 1#define BUCKET_CAP (10)
 2void BucketSort(SqList *L)
 3{
 4    if(L == nullptr || L->length < 2)
 5    {
 6        return;
 7    }
 8
 9    int max = L->r[0], min = L->r[0];
10    //找到最大值最小值
11    for(int i = 0; i < L->length; i++)
12    {
13        if(L->r[i]  > max)
14        {
15            max = L->r[i];
16        }
17        if(L->r[i] < min)
18        {
19            min = L->r[i];
20        }
21    }
22    int bucketCount = (max - min) / BUCKET_CAP + 1;
23    vector<int> buckets[bucketCount];//二维数组,长度为BUCKET_CAP大小的个数为桶的个数
24    // 入桶
25    for (int i = 0; i < L->length; i++) {
26        int idx = (L->r[i] - min) / BUCKET_CAP;			//放入对应的桶
27        buckets[idx].push_back(L->r[i]);
28        if(buckets[idx].size() >= 2)
29        {
30            // 对该桶使用插入排序(因为数据过少,插入排序即可),维持该桶的有序性
31            for (int j = buckets[idx].size() - 1; j > 0; j--) {
32                if (buckets[idx][j] < buckets[idx][j-1]) {
33                    swap(buckets[idx][j], buckets[idx][j-1]);
34                }
35            }
36        }
37    }
38    // 顺序访问桶,得到有序数组
39    for (int i = 0, k = 0; i < bucketCount; i++) {
40        for (int j = 0; j < int(buckets[i].size()); j++) {
41            L->r[k++] = buckets[i][j];
42        }
43    }
44}

Java版本

 1//桶的容量,即每个桶所能放置多少个不同数值
 2//bucketCap这里是2
 3public static ArrayList<Integer> BucketSort(ArrayList<Integer> array, int bucketCap)
 4{
 5    if(array == null || array.size() < 2)
 6    {
 7        return array;
 8    }
 9    
10    int max = array.get(0), min = array.get(0);
11    //找到最大值最小值
12    for(int i = 0; i < array.size(); i++)
13    {
14        if(array.get(i)  > max)
15        {
16            max = array.get(i);
17        }
18        if(array.get(i) < min)
19        {
20            min = array.get(i);
21        }
22    }
23    //获得桶的数量
24    int bucketCount = (max - min) / bucketCap + 1;
25    //构建桶
26    ArrayList<ArrayList<Interger>> bucketArr = new ArrayList<>(bucketCount);
27    ArrayList<Interger> resultArr = new ArrayList<>();
28    for(int i = 0; i < bucketCount; i++)
29    {
30        bucketArr.add(new ArrayList<Integer>());
31    }
32    //将原始数组中的数据分配到桶中
33    for(int i = 0; i < array.size(); i++)
34    {
35        bucketArr.get((array.get(i) - min) / bucketCap).add(array.get(i));
36    }
37    //看桶中数据的分布
38    for(int i = 0; i < bucketArr.size(); i++)
39    {
40        System.out.println("第" + i + "个桶包含数据");
41        PrintArray.printObject(bucketArr.get(i));
42    }
43    //桶内数据在做相关的排序
44    for(int i = 0; i < bucketCount; i++)
45    {
46        if(1 == bucketCap)
47        {
48            for(int j = 0; j < bucketArr.get(i).size(); j++)
49            {
50                resultArr.add(bucketArr.get(i).get(j));
51            }
52        }else
53        {
54            if(1 == bucketCount)
55            {
56                bucketCap--;
57            }
58            System.out.println("对第" + i + "桶中的数据再次用桶进行排序");
59            ArrayList<Integer> temp = BucketSort(bucketArr.get(i), bucketCap);
60            for(int j = 0; j < temp.size(); j++)
61            {
62                resultArr.add(temp.get(j));
63            }
64        }
65    }
66    return reslutArr;
67}

桶的个数,BucketCount = 43 / 10 + 1 = 5

在桶排序中保证元素均匀分布到各个桶尤为关键。

举个反例,有数组[0,9,4,5,8,7,6,3,2,1]要排序,它们都是10以下的数,如果还按照上面的范围[0,10)建立桶,全部的元素将进入同一个桶中,此时桶排序就失去了意义。

实际情况我们很可能事先就不知道输入数据是什么,为了保证元素均匀分不到各个桶中,需要建立多少个桶,每个桶的范围是多少呢?

其实我们可以这样:简单点,首先限定桶的容量,再根据元素的个数来决定桶的个数。当然使用更复杂的方法也是可以的。 桶排序利用函数的映射关系,减少了几乎所有的比较工作。

实际上,桶排序的(K)值的计算,其作用就相当于快排中划分,已经把大量数据分割成了基本有序的数据块(桶)。然后只需要对桶中的少量数据做先进的比较排序即可。