原理:
先建立桶,在10个桶内进行取元素个位,入桶,排序后再取元素十位,入桶,排序。......百位,千位.....。
举例:
31,12,5,57,2,31,90,32,95,76
我们先取各个元素的个位。
3
1,1
2,
5,5
7,
2,3
1,9
0,3
2,9
5,7
6
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
1 | 2 | 3 | 0 | 0 | 2 | 1 | 1 | 0 | 0 |
90 | 31 | 12 | 5 | 76 | 57 | ||||
31 | 2 | 95 | |||||||
32 | |||||||||
然后我们出桶,形成序列
90,31,31,12,2,32,5,95,76,57
然后我们对数据取十位。
90,
31,
31,
12,
02,
32,
05,
95,
76,
57
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
2 | 1 | 0 | 3 | 0 | 1 | 0 | 1 | 0 | 2 |
2 | 12 | 31 | 57 | 76 | 90 | ||||
5 | 31 | 95 | |||||||
32 | |||||||||
然后我们出桶,形成序列
2,5,12,31,31,32,57,76,90,95
如果有百位千位等我们继续此操作。
代码:
(用链表最好,我这里使用的数组)
void bucketSort(int a[], int nlen)
{
auto MyDigit = [&]()->int
{
int div = 10;
int digits = 1;
for (int i = 0; i != nlen; ++i)
{
while (a[i] / div)
{
div *= 10;
++digits;
}
}
return digits;
};
int digits = MyDigit();
int divisor = 1;
int **b = new int*[10];
for (int i = 0; i != 10; ++i)
{
b[i] = new int[nlen + 1];
}
int k = 0;
for (int i = 1; i <= digits; i++)
{
for (int ni = 0; ni != 10; ++ni)
{
for (int j = 0; j != nlen + 1; ++j)
{
b[ni][j] = 0;
}
}
for (int j = 0; j<nlen; j++)
{
b[(a[j] / divisor) % 10][++b[(a[j] / divisor) % 10][0]] = a[j];
}
k = 0;
for (int ni = 0; ni != 10; ++ni)
{
for (int j = 1; j <= b[ni][0]; ++j)
{
a[k++] = b[ni][j];
}
}
divisor *= 10;
}
for (int i = 0; i != 10; ++i)
{
delete[] b[i];
b[i] = nullptr;
}
delete[] b;
b = nullptr;
}
总结:
桶排序包含了计数排序和基数排序的思想,是一个不错的排序算法,但是缺点也同样继承了过来自然数[0~K],(正整数K)。纵观这三种线性时间排序(计数排序、基数排序、桶排序)如果我们能够对负数取绝对值,适当的修改代码,生成两组序列,然后再合并起来,是一个很好的选择。桶排序是一个稳定的排序算法。平均时间复杂度也是趋近于O(N)的排序算法。