我们知道,桶排序适用于取值范围固定的情形。比如,在1-1000内的整数中随机取100个进行排序。现在考虑一个问题,在(0,1)内随机取10个实数进行排序,该如何使用桶排序的思想呢?这就是本文要解决的问题。
算法:
①数组实现:通过循环遍历获取输入的数据彼此间隔的最小值Gap,均匀在0-1之间取N=(1/Gap+1)个间隔,则待排序的数据落在每个间隔里的数字个数最多为1。定义一维A[N]数组赋初值为0,依次输出不为0时存储的数值。
#include "pch.h"
#include<stdlib.h>
#include<windows.h>
#include<iostream>
using namespace std;
int lengthA = 10;
float A[10];
float B[10000];//足够大
float Gap=1;
//生成0-1之间的随机数(4位小数)
void Value()
{
for (int i = 0; i < lengthA; i++)
{
A[i] = (rand() % 10000) / 10000.0;
}
for (int j = 0; j < lengthA; j++)
{
cout << A[j] << endl;
}
}
//计算生成数的最小间隔Gap(除0以外)
float CulGap(float A[])
{
for (int i = 0; i < lengthA; i++)
{
for (int j = i + 1; j < lengthA; j++)
{
if ((A[i] - A[j] < Gap)&(A[i] - A[j] > -Gap))
{
Gap = abs(A[i] - A[j]);
}
}
}
return Gap;
}
//实现桶式排序的过程
void sort()
{
int BN = 1 / Gap + 1;
for (int i = 0; i < lengthA; i++)
{
int temp = A[i] / Gap;
B[temp] = A[i];
}
for (int j = 0; j < BN; j++)
{
if (B[j] != 0)
{
cout << B[j] << " ";
}
}
}
//主函数,调用实现
int main()
{
Value();
CulGap(A);
sort();
return 0;
}
结果如下:
分析:
这种算法的算法复杂度较高,即O(n*n+m+k),原因是求最小Gap时需要双重循环。一种改进方式是,直接手动设置合适的Gap值,将按照Gap分组的子序列分别使用快速排序方式实现(这里要用链表实现子序列存储)。O(nlogn+m+k),在Gap值设置的比较好的情况下可以无限逼近O(m+k)。
拓展:
想象一个序列{1,10,100,1000,10000},直接桶式排序,需要int a[10000]来存储,造成时间效率降低。如果做预处理对数据进行“压缩”,这里使用取对数log n,序列变成{0,1,2,3,4},只需要int a[5]。所以是否可以通过“压缩函数”来进一步提高时间效率呢?
我觉得ok.