十大经典排序算法系列博客——>传送门
桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。
总结起来就是一句话:按值划分成多个区间, 每个区间排序, 最后合并。
算法步骤:
-
设置一个定量的数组当作空桶;
-
遍历输入数据,并且把数据一个一个放到对应的桶里去;
-
对每个不是空的桶进行排序;
-
从不是空的桶里把排好序的数据拼接起来。
-
动画演示:
#include <bits/stdc++.h>
using namespace std;
// 打印数组
void print_array(int *arr, int n) {
if(n==0){
printf("ERROR: Array length is ZERO\n");
return;
}
printf("%d", arr[0]);
for (int i=1; i<n; i++)
printf(" %d", arr[i]);
printf("\n");
}
int* sort_array(int *arr, int n) {
int i;
int maxValue = arr[0];
for (i = 1; i < n; i++)
if (arr[i] > maxValue) // 输入数据的最大值
maxValue = arr[i];
// 设置10个桶,依次0,1,,,9
const int bucketCnt = 10;
vector<int> buckets[bucketCnt];
// 桶的大小bucketSize根据数组最大值确定:比如最大值99, 桶大小10
// 最大值999,桶大小100
// 根据最高位数字映射到相应的桶,映射函数为 arr[i]/bucketSize
int bucketSize = 1;
while (maxValue) { //求最大尺寸
maxValue /= 10;
bucketSize *= 10;
}
bucketSize /= 10; //桶的个数
// 入桶
for (int i=0; i<n; i++) {
int idx = arr[i]/bucketSize; //放入对应的桶
buckets[idx].push_back(arr[i]);
// 对该桶使用插入排序(因为数据过少,插入排序即可),维持该桶的有序性
for (int j=int(buckets[idx].size())-1; j>0; j--) {
if (buckets[idx][j]<buckets[idx][j-1]) {
swap(buckets[idx][j], buckets[idx][j-1]);
}
}
}
// 顺序访问桶,得到有序数组
for (int i=0, k=0; i<bucketCnt; i++) {
for (int j=0; j<int(buckets[i].size()); j++) {
arr[k++] = buckets[i][j];
}
}
return arr;
}
int main() {
int n;
scanf("%d", &n);
int *arr;
arr = (int*)malloc(sizeof(int)*n);
for (int i=0; i<n; i++) scanf("%d", &arr[i]);
arr = sort_array(arr, n);
print_array(arr, n);
return 0;
}
若要在桶排序的同时实现对数组的去重, 则用以下代码(将每个桶的容量看做1)
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int n;
bool a[1005]={0};
int c;
int count=0;
cin>>n;
for(int i=0;i<n;i++)//输入数据,存放到数组对应的位置,表示该对应位置有数据了(而且还省了排序)
{
cin>>c;
a[c]=1;
}
for(int i=0;i<1005;i++)//计算占了位置的数据有多少个,每个桶不管有几个相同数据,这里之后+1,所以可以说直接去重了
{
if(a[i]==1)
count+=1;
}
cout<<count<<endl;
for(int i=0;i<=1005;i++)//按顺序输出来
{
if(a[i]==1)
cout<<i<<" ";
}
return 0;
}