位图排序只适应于没有重复元素的排序。
思想
位图排序的核心思想是:每一位代表一个数字。下面我们用图示的方法进行具体介绍。
我们都知道1个整数占4个字节,1个字节有8位
现在我们定义 int i,则系统分配如下空间:
int i共有32位,可表示32个数字。
若我们定义int a[3],则系统分配如下空间:
int a[3]共有96位,可表示96个数字。
下面看每位是如何表示一个数字的
我们先看一个简单的例子: 18 4 26 3 5这三个数字为例。这三个数字里面最大的是26,所以我们申请一个整数空间int i即可。
第一步:先将所有的位清零
第二步:将要表示数字的对应位的值置1
这样我们就完成了数字用位的表示。
第三步:从最小位开始,若位上的值为1则进行输出,即可完成排序
上例输出的结果为:3 4 5 18 26.
下面我们看一下63 在空间中的表示.63/32+1=2。所以我们需要申请2个整数int a[2]。然后我们需要确定63所在的行与列
确定所在的行(右移5位)
63/32=1,所以在第一行。我们知道右移五位(2^5=32)相当于除以32,因为移位比除法的底层实现简单,所以我们用右移求行。
确定所在的列(&0x1F)
63%32=31,所以在第31列。同样我们可以用&0x1F实现。
表示结果如下所示:
代码
//位图排序
#include<stdio.h>
#include<time.h>
//c语言中定义一个局部变量数组时,若没有赋初值,则数组中的值是随机的。
//若定义全局变量时,则会自动赋值,如int a会赋值a为0.
#define BITSPERWORD 32//一个整型数有4个字节,32位
#define SHIFT 5//确定所在的行,除以32。(相当于右移5位)
#define MASK 0x1F//确定所在的列,求余32.(相当于与0x1F进行与操作)
#define N 100//对100个数进行位图排序
//只能排序0~100的数字
int a[1 + N / BITSPERWORD];//确定所需整数的个数。
void clear(int i)//可以省略。第i位清零。
{
a[i>>SHIFT] &= ~(1 << (i & MASK));
//i >> SHIFT;所在的行。
//i&MASK;所在的列。
//可以不可以:a[i>>SHIF]&=(0<<(i&MASK));
}
void set(int i)//第i位置1.
{
a[i>>SHIFT] |= (1 <<(i& MASK));
}
int test(int i)//判断i位置上是否有数
{
return a[i>>SHIFT] & (1 << (i & MASK));
}
int main()
{
int i;
clock_t start, end;//检测运行时间的代码
start = clock();//检测运行时间的代码
for (i = 0; i < N; i++)
clear(i);
while (scanf_s("%d", &i) != EOF)
set(i);
for (i = 0; i < N; i++)
if (test(i))
printf("%d\n", i);
end = clock();//检测运行时间的代码
printf("运行所花费的时间是=%f\n", ((double)end - start) / CLK_TCK);//检测运行时间的代码
return 0;
}
下面这个给你个我个人觉得好理解一点的代码
#include<iostream>
#define Bit 32
#define shift 5
#define mask 0x1F
#define N 1000
int a[1 + N / Bit];
void clear(int i)
{
a[i >> shift] &= (0 << (i & mask));
}
void set(int i)
{
a[i >> shift] |= (1 << (i & mask));
}
int test(int i)
{
return a[i >> shift] & (1 << (i & mask));
}
void main()
{
int i;
for (i = 0; i < N; i++)
clear(i);
while (scanf_s("%d", &i) != EOF)
set(i);
for (i = 0; i < N; i++)
if (test(i))
printf("%d\n", i);
}