利用bit位进行整数排序

问题输入:一个最多包含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、分配内存,n/8个字节

             2、初始化内存:将所有bit位设置为0

             3、排序开始:从第一个数开始遍历,并将其所对应位置的那个bit位设置成1,遍历完成时,排序完成。

若要查找某个数是否存在,则只需查看其对应位是否为1即可(若为1,则表示此数存在,否在此数不存在)。

插入、删除的操作类似,将相应的bit位置1或置0.

 

相关的C语言代码实现如下:

            分配内存: (int*)malloc((n/(sizeof(int)*8)+1)*sizeof(int));  //以整型为单位进行操作,所以此处转换成整型指针   //注1

            初始化:void init_bits(int* d,int n)

                    {
                        int i=0;
                        for(i=0;i<(n/(sizeof(int)*8)+1);i++)//注2
                        d[i]=d[i]&0;
                     }
             将相应位设置成1: void set_bit(int* d,int num)
                               {
                                    int a=0x1;
                                    a=a<<(32-num%(sizeof(int)*8));//注3
                                   d[(num-1)/(sizeof(int)*8)]=d[(num-1)/(sizeof(int)*8)]|a;//注4
                               }
             查看相应位是否为1:int isone(int* d,int num)
                                {
                                    int a=0x1;
                                    a=a<<(32-num%(sizeof(int)*8));
                                    int temp=d[(num-1)/(sizeof(int)*8)];
                                    if((temp&a)==0)
                                         return 0;
                                    else
                                         return 1;
                                 }
注:位操作主要搞清楚“这一位”属于哪个整数范围,以及“这一位”在这个整数内是第几位。

注意一下几点:

注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[])
{
        int j=0,n,x;
        printf("please input the max value, n=");
        scanf("%d",&n);
        int *d=(int*)malloc((n/(sizeof(int)*8)+1)*sizeof(int));
        printf("before init:\n");
        for(j=0;j<(n/(sizeof(int)*8)+1);j++)
                printf("%d  ",d[j]);

        init_bits(d,n);
        printf("\nafter init:\n");
        for(j=0;j<(n/(sizeof(int)*8)+1);j++)
                printf("%d  ",d[j]);

        int i=0;

        for(i=0;i<10;i++)

        {

                printf("\nplease input which bit to be set to 1,x=");
                scanf("%d",&x);
                if(isone(d,x))
                      printf("this bit has been set to 1\n");
                else
                {
                      set_bit(d,x);
                      printf("after set:\n");
                      for(j=0;j<(n/(sizeof(int)*8)+1);j++)
                                printf("%d  ",d[j]);
                }

         }
        free(d);
        return 0;
}

                                  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值