问题输入:一个最多包含n个正整数的文件,这个文件中的正整数最大不能超过n,n=10000000,这个文件中的数值不能重复。
问题输出:对上述文件中的正整数按从小到大顺序进行排序。
限制条件:最多1M的内存空间是可用的(磁盘空间不限),运行时间要几分钟。
解决分析:用普通的排序方法很难实现(内存太小),所以采用用bit位代表整数的方法,即一个bit位代表一个整数,每个bit所代表的整数由它在bit串中的位置决定(第一个bit代表0000001,第二个bit代表0000002,第三个bit代表0000003,......)。时间负责度:O(n),空间负责读:O(n).
1M=1024kB=1024×1024B=1024×1024×8bit=8388608bit,即1M最多可以代表8388608个整数,而n=10000000,即最少需要10000000个bit位,所以可以分两次来完成排序工作(先完成00000001-5000000范围内的排序,然后再完成5000001-9999999范围内的排序)。
一次排序过程的实现过程:
若要查找某个数是否存在,则只需查看其对应位是否为1即可(若为1,则表示此数存在,否在此数不存在)。
插入、删除的操作类似,将相应的bit位置1或置0.
相关的C语言代码实现如下:
注:位操作主要搞清楚“这一位”属于哪个整数范围,以及“这一位”在这个整数内是第几位。
注意一下几点:
注1:malloc时要多malloc一个int空间大小,而不是多一个字节的大小(因为要转换成int*)。sizeof(int)等于8,不等于32,所以n/(sizeof(int)*8),而不是n/sizeof(int)。
注2、for循环中到n/(sizeof(int)*8)+1,而不是n/sizeof(int)+1。
注3、1要左移32-num%(sizeof(int)*8,而不是31-num%(sizeof(int)*8,因为这里的num是指第几个数,从1开始,而不是从0开始。当num是32整倍数时,1左移32位(GNU中C语言会产生警告,但不影响执行,他会按循环左移的方式移动,所以左移32位,相当于又移动到了原处)。
注4、第num个数是第[(num-1)/(sizeof(int)*8)个整数,而不是第num/(sizeof(int)*8个整数。
下面这个完整的小程序验证以上函数的正确性:
int main(int argc,char* argv[])
{
}