【算法】基数排序应用于浮点数 (Radix sort deal with float number)
2013-10-30 15:40
681 查看
这次的se106的homework有一题对浮点数使用基数排序,做完之后感觉比较有趣。
很多人觉得对浮点数使用基数排序,就是从小数点后面多少位开始使用10进制的方式一位一位排。
但这是计算机保存浮点数,并不是数学上的小数,个人认为这样考虑不妥。应该遵循计算机保存浮点数的格式来排序。
使用 IEEE 的 float 为例:
[b]1.算法思路[/b]
对于 IEEE 的 float 类型:
![](http://images.cnitblog.com/blog/490808/201310/30153904-1b9fd7056c114a20892f5d917eddd7fc.gif)
最高位31位是符号位,30~23位是阶码位,22~0位是尾数位。
IEEE的 float 类型有一个特性,就是从0到30位(除了符号位)对数字的大小的重要性依次增大,这样就可以和整数各位的排序一样了。
有一个例外问题就是符号位导致正负数的排序出现的问题,例如对于一个4位的 IEEE 方式编码的浮点数,最高位是符号位,后面3位为尾数位。
用传统的基数排序将会得到如下结果:
产生的问题是 先是正数从小到大排,再是负数从大到小排。
为了解决这个问题,可以做两种处理:
1. 将排列之后的序列的正数倒置,就形成了从大到小的序列。
2. 先将正数做一个处理,符号位从0置成1,再将负数做一个处理,全部取反,排列完后再恢复。
我们使用第2种方法(因为感觉更有趣)。
[b]2.代码实现[/b]
第3行将输入的浮点数做如上处理。之后做传统的基数排序。
以一个byte为单元,产生256个不同的key,对于4个byte的 float,一共循环4次。
第22行做变换会原本数位的处理。
这样,就使用位来对浮点数进行了基数排序。
很多人觉得对浮点数使用基数排序,就是从小数点后面多少位开始使用10进制的方式一位一位排。
但这是计算机保存浮点数,并不是数学上的小数,个人认为这样考虑不妥。应该遵循计算机保存浮点数的格式来排序。
使用 IEEE 的 float 为例:
[b]1.算法思路[/b]
对于 IEEE 的 float 类型:
![](http://images.cnitblog.com/blog/490808/201310/30153904-1b9fd7056c114a20892f5d917eddd7fc.gif)
最高位31位是符号位,30~23位是阶码位,22~0位是尾数位。
IEEE的 float 类型有一个特性,就是从0到30位(除了符号位)对数字的大小的重要性依次增大,这样就可以和整数各位的排序一样了。
有一个例外问题就是符号位导致正负数的排序出现的问题,例如对于一个4位的 IEEE 方式编码的浮点数,最高位是符号位,后面3位为尾数位。
用传统的基数排序将会得到如下结果:
0 : 0000 1 : 0001 2 : 0010 4 : 0100 -1 : 1001 -2 : 1010 -7 : 1111
产生的问题是 先是正数从小到大排,再是负数从大到小排。
为了解决这个问题,可以做两种处理:
1. 将排列之后的序列的正数倒置,就形成了从大到小的序列。
2. 先将正数做一个处理,符号位从0置成1,再将负数做一个处理,全部取反,排列完后再恢复。
我们使用第2种方法(因为感觉更有趣)。
[b]2.代码实现[/b]
void radix_sort(float input[], int length) { // positive: sign bit set 0 to 1 // negative: all bit trans // 32bits split into 4 bytes, sort 1 byte 1 time for (int i=0; i<length; i++) reinterpret_cast<int&>(input[i]) = (reinterpret_cast<int&>(input[i])>>31 & 0x1)? ~reinterpret_cast<int&>(input[i]) : reinterpret_cast<int&>(input[i]) | 0x80000000; vector<float> bucket[256]; for (int i=0; i<4; i++) { for (int j=0; j<length; j++) bucket[reinterpret_cast<int&>(input[j])>>(i*8) & 0xff].push_back(input[j]); int count = 0; for (int j=0; j<256; j++) { for (int k=0; k<bucket[j].size(); k++) input[count++] = bucket[j][k]; bucket[j].clear(); } } // after sort, recover for (int i=0; i<length; i++) reinterpret_cast<int&>(input[i]) = (reinterpret_cast<int&>(input[i])>>31 & 0x1)? reinterpret_cast<int&>(input[i]) & 0x7fffffff : ~reinterpret_cast<int&>(input[i]); }
第3行将输入的浮点数做如上处理。之后做传统的基数排序。
以一个byte为单元,产生256个不同的key,对于4个byte的 float,一共循环4次。
第22行做变换会原本数位的处理。
这样,就使用位来对浮点数进行了基数排序。
相关文章推荐
- 算法总结系列之五: 基数排序(Radix Sort)
- 算法学习-基数排序(radix sort)卡片排序(card sort) C++数组实现
- 算法总结系列之五: 基数排序(Radix Sort)
- 学习算法-基数排序(radix sort)卡片分类(card sort) C++数组实现
- 【算法导论学习-015】基数排序(Radix sort)
- 算法总结系列之五: 基数排序(Radix Sort)
- 算法总结系列之五: 基数排序(Radix Sort)
- 小小c#算法题 - 9 - 基数排序 (Radix Sort)
- How to deal with large number of threads in clients
- Radix sort 基数排序
- 基于非比較的排序:计数排序(countSort),桶排序(bucketSort),基数排序(radixSort)
- (算法设计技巧与分析)RadixSort
- 基数排序(Radix Sort)
- 基数排序(RadixSortC语言)
- 基数排序(RADIX SORT
- 排序算法-基数排序(RadixSort)
- 基数排序(radixSort)
- 排序1+3:基数排序(RadixSort),希尔排序(ShellSort)和快速排序(QuickSort)
- 基数排序(radix sort)
- 基数排序(radixSort)