基数排序优化
来源:互联网 发布:危重孕产妇网络直报 编辑:程序博客网 时间:2024/06/03 23:42
1. 原理
基数排序就是先按照个位数字排序,然后按照十位数字排序,接着百位,千位,万位…,最终数组将变成有序数组。
2. 基数排序的分解
- 提取某一位(k位)上的数字
- 除以10^(k-1)
- 对10取余
- 按照提取的这一位上的数字进行计数排序
然后不断的循环上述过程,直到每一位的数字都被遍历。
3. 基的优化
假设数组范围为(0, 1000 * 1000)。
+ 以最基础的10为基,那么上述的循环就要进行6次;
+ 以100为基,那么上述循环只进行3次就可以,而唯一的改变就是在每一次的计数排序过程中,用于计数的数组空间由O(10)变为了O(100);
+ 以1000为基,那么上述循环只需进行2次就可以,这次在每一次的计数排序过程中,用于计数的数组空间由O(10)变为了O(1000);
因此,通过增加基的大小可以显著改善效率。
4. 除法和取余优化
在C和C++中,除法和取余的效率是非常低的,而在基数排序中要反复用到求某一位的数字,最常规的方法就是除法和取余,因此在本算法中需要尽量避免。我们很自然的想到用移位和与操作来取代除法和取余。当然,可以这样操作主要还是因为基数的选取比较自由。
在十进制中可以以10,100,1000为基数,当然也可以在二进制中以8,16,32,64,128,256,512,1024为基数。这样在某一位上的数组就可以用移位和与来操作。
例如:0x5d4f32 = 6115122,以16为基:
从右第一位 = 0x5d4f32 & 0x0F = 2;从右第二位 = (0x5d4f32 >> 4) & 0x0F = 3...从右第六位 = (0x5d4f32 >> 20) & 0x0F = 5
当然,如果数据范围较大,也可以以256为基,再看0x5d4f32:
从右第一位 = 0x5d4f32 & 0xFF = 32;从右第二位 = (0x5d4f32 >> 8) & 0xFF = 4f从右第三位 = (0x5d4f32 >> 16) & 0xFF = 5d
如此,就可以有效的避免除法和取余操作,效率也将大大提高。
5. 占用空间优化
网上代码的普遍做法是:分配空间的大小与数据的位数成正比,如下述代码:
int *bucket = (int *) malloc((end-begin+1) * sizeof(int));
其中end就是最高位,begin为最低位,如果数据范围为(0, 1000 * 1000)。那么上面分配的空间将是6个原始数组大小的空间,实际上只需一个或两个即可。
6. 加速效果
当数组大小 N = 50000000,数据的最大值为 K = 0x7FFFFFFF 时。
串行时间: 3.103s
并行时间: 0.66s
加速比: 4.70倍
当数组大小 N = 80000000,数据的最大值为 K = 0x7FFFFFFF 时。
串行时间: 5.034s
并行时间: 1.053
加速比: 4.78倍
7. 总结
综上,为了有效改善基数排序的效率,用2的n次幂做基数是较好的选择,大的基数,并避免除法和取余操作。
当然,大的基数意味着大的空间占用,但是,如果数据量较大,这个占用相对来说还是很小的。
另外,要考虑数据的范围,如果数据范围是(0, 0xFFFFFFFF),那么,把0xFFFF作为基数,只需两次循环,在计数排序中开辟空间的大小就为O(0xFFFF);如果以0xFFF作为基数,则需三次循环,计数排序中开辟空间的范围也就减小。
也可参考基数排序优化
- 基数排序优化
- 基数排序的性能优化
- 基数排序之代码优化
- 基数排序的性能优化
- UVA 11462 Age sort (基数排序+优化输入输出)
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- 基数排序
- Core Data
- 【c语言】写一个函数返回参数值为1的个数(优化)
- 3.RFID系统及其功能
- Unity3d 人物换装 之 Mesh 合并 (材质合并)
- 从源码分析PHP的SESSION实现机制
- 基数排序优化
- hdoj 1702 ACboy needs your help again!
- 香港机房
- Transform变换
- Reverse Integer
- sqlmap安装
- iOS边城之绘图编程(Core Graghics)
- 欧拉项目第15题
- 老码识途 汇编分析函数调用和局部变量