您的位置:首页 > 其它

【算法】基数排序应用于浮点数 (Radix sort deal with float number)

2013-10-30 15:40 681 查看
这次的se106的homework有一题对浮点数使用基数排序,做完之后感觉比较有趣。

很多人觉得对浮点数使用基数排序,就是从小数点后面多少位开始使用10进制的方式一位一位排。

但这是计算机保存浮点数,并不是数学上的小数,个人认为这样考虑不妥。应该遵循计算机保存浮点数的格式来排序。

使用 IEEE 的 float 为例:

[b]1.算法思路[/b]

  对于 IEEE 的 float 类型:

  


  最高位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行做变换会原本数位的处理。

  这样,就使用位来对浮点数进行了基数排序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: