<转载>编程珠玑-位排序(bitsort)

 
在《编程珠玑》一书上,有一题是将一堆不重复的数进行排序,这些数的值大小位于[0, 10000000).
然后作者在书后给出的答案确实很精辟,利用位排序将这个问题轻而易举的解决了。
首先弄懂i>>SHIFT相当于i/32,i&MASK相当于i%32.
题目中说了
 
Replace above 2 lines with below 3for word-parallel init
int top =1+ N/BITSPERWORD;
for (i =0; i < top; i++)
a[i] =0;



那么就采用这个,把a数组中的元素都设置为0.

整个程序的思想就是:
            1.每个整数有32位,那么它就可以表示32个数,分别对应每bit位为1.
            2.然后把10000000个数分为1+N/BITSPERWORD组(相当于有这么多个桶),每组包含接近32个数。
上面的解释可能仍不到位,那我们来看具体的函数:
 
对于set函数,我们可以这样理解,
             arr[i>>SHIFT] |= (1<<(i&MASK))可以转化为
             arr[i/32] = arr[i/32] | (1<<(i%32))
i%32必然处于区间[0, 31],那么1<<(i%32)就是将bit位1向前移动(i%32)位,然后和arr[i/32]相或,因而arr[i/32]的第(i%32)位就为1.
 
对于test函数,就是上面过程的反过程了。它是用来判断i个这个数是否存在,即arr[i/32]的相应bit位是否为1.
 
最后,就做排序了,
      for (int i = 0; i < N; i++)
由于[0, N)已经是从小到大排序好的,那么我们只需判断每个数是否存在,若存在,就输出,所以输出结果也就是排序的了。
复制代码
#include <stdio.h>

#define N 10000000
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F

int arr[1+ N/BITSPERWORD];

voidset(int i)
{
arr[i>>SHIFT] |= (1<<(i&MASK));
}

int test(int i)
{
return arr[i>>SHIFT] & (1<<(i&MASK));
}

int main()
{
////先在文本文件中生成N个数
//FILE* file = freopen("in", "w", stdout);
//if (file != NULL)
//{
// for (int i = 0; i < N; i++)
// {
// printf("%d ", N - 1 -i);
// }
// fclose(file);
//}

FILE* in_file = freopen("in", "r", stdin);
FILE* out_file = freopen("out", "w", stdout);

if (in_file != NULL)
{
int d;
while(scanf("%d", &d) != EOF)
set(d);
fclose(in_file);
}

if (out_file != NULL)
{
for (int i =0; i < N; i++)
if (test(i))
printf("%d ", i);
}
fclose(out_file);
return0;
}
复制代码
原文地址:https://www.cnblogs.com/dormant/p/4929670.html