算法:排序之桶排序和基数排序
Posted 我们全都爱学习
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法:排序之桶排序和基数排序相关的知识,希望对你有一定的参考价值。
把这两个算法放在一起,因为感觉这两个排序算法的通用性比较小,必须针对具体问题做具体的算法分析设计才能使用。
桶排序:
桶排序假设输入的待排序元素的值可以落在一个值区间内;于是:
遍历待排序数组,按照一定规则,把所有n个元素分布到m个桶中。
每一个桶代表一个区间范围,所以桶和桶之间是排序的。
然后对每一个桶执行桶内排序;桶内排序可以使用任意排序算法。
最后把所有的桶的元素拼接起来返回即可。
举一个例子:
例如要对n个大小为[1..1000]范围整数进行排序,我们设定桶的大小是10,那么我们需要m=100个桶:
把1-10的元素分配到1号桶
把10-20的元素分配到2号桶
把20-30的元素分配到3号桶
...
把990-1000的元素分配到100号桶
分配完之后,针对每一个桶进行桶内排序,任意排序算法,例如快速,插入等等都行。
最后把所有的桶的元素都拼接起来得到排序后输出;因为桶之间是按区间排序的,桶内元素也已经排序好了,所以这一步只要拼接起来就行了。
另外如果我们有1000个桶,那么每个桶最多只有一个元素,这样首次分配完之后,筒内的元素已经是排行好的了(因为只有最多一个元素),就不需要再进行桶内元素的排序,直接执行桶间的拼接输出就行。
桶排序的时间复杂度是接近O(n),但是另外需要辅助空间O(n)。
算法实现:
// get the maximun value from array
int max(int a[], int n) {
int max= a[0];
for(int i = 1; i < n; i++) {
if(a[i] > max) {
max= a[i];
}
}
return max;
}
void sort_bucket(int a[] , int n) {
int bucketlen = max(a, n) + 1;
int bucket[bucketlen] = { 0 };
for (int i = 0; i < n; i++) {
bucket[a[i]]++; // in case there are duplicated elements
}
int j = 0;
for (int i = 0; i < bucketlen; i++) {
while (bucket[i] != 0) {
a[j++] = i; // put element back to array
bucket[i]--;
}
}
}
基数排序:
基数排序(以整形为例),把整数以10进制按每位拆分,然后从最低位到最高位依次比较各个位排序,主要分为两个过程:
分配:先从个位开始,根据位值(0-9)分别放到0~9号桶。
例如13, 个位为3,则放入3号桶中。
收集:再将放置在0~9号桶中的数据按顺序放到数组中。
重复上述1和2的过程,取更高一位,直到最高位排好序为止。
用一个例子说明就比较清楚:
假设待排序数组为:73 22 93 43 55 14 28 65 39 81。
第一步分配,按个位
0号桶:
1号桶:81
2号桶:22
3号桶:73,93,43
4号桶:14
5号桶:55,65
6号桶:
7号桶:
8号桶:28
9号桶:39
第一次收集
81 22 73 93 43 14 55 65 28 39
第二次分配,注意这次按照十位数分配
0号桶:
1号桶:15
2号桶:22,28
3号桶:39
4号桶:43
5号桶:55
6号桶:65
7号桶:73
8号桶:81
9号桶:93
第二次收集
14 22 28 39 43 55 65 73 81 93
我们观察到此时已经排序完成了。
算法实现:
// get the numer in position(start from 1, right to left)
// for example
// numinpos(7463, 1) = 3
// numinpos(7463, 2) = 6
// numinpos(7463, 3) = 4
// numinpos(7463, 4) = 7
int numinpos(int num,int pos) {
int temp = 1;
for (int i = 0; i < pos - 1; i++) {
temp *= 10;
}
return (num / temp) % 10;
}
void sort_radix(int a[], int n)
{
// allocate space
int *radixarrays[10];
for (int i = 0; i < 10; i++) {
radixarrays[i] = (int *)malloc(sizeof(int) * (n+ 1));
radixarrays[i][0] = 0; // index=0 is used to record elements number
}
// we define pos from 1 to 10, because the max int value does
// not exceed 11 numbers.
// (gdb) p/u 0x7fffffff (int)
// $1 = 2147483647
// (gdb) p/u 0xffffffff (unsigned int)
// $2 = 4294967295
for (int pos = 1; pos <= 10; pos++) {
for (int i = 0; i < n; i++) { // allocate stage
int num = numinpos(a[i], pos);
int index = ++radixarrays[num][0];
radixarrays[num][index] = a[i];
}
int j = 0;
for (int i = 0; i < 10; i++) { // collect stage
for (int k = 1; k <= radixarrays[i][0]; k++) {
a[j++] = radixarrays[i][k];
}
radixarrays[i][0] = 0;
}
}
// free space
for (int i = 0; i < 10; i++) {
free(radixarrays[i]);
}
}
所以总体感觉这两个排序算法有一定的关联性,而且通用性都不高,需要对具体待排序元素的性质做分析,才能更好的应用这两个排序算法。
以上是关于算法:排序之桶排序和基数排序的主要内容,如果未能解决你的问题,请参考以下文章