zoukankan      html  css  js  c++  java
  • 位操作与空间压缩

    筛素数法在这里不就详细介绍了,本文着重对筛素数法所使用的素数表进行优化来减小其空间占用。要压缩素数表的空间占用,可以使用位操作。下面是用筛素数法计算100以内的素数示例代码(注2):

    #include <stdio.h>
    #include <memory.h>
    const int MAXN = 100;
    bool flag[MAXN];
    int primes[MAXN / 3 + 1], pi;
    //对每个素数,它的倍数必定不是素数。
    //有很多重复如flag[10]会在访问flag[2]和flag[5]时各访问一次
    void GetPrime_1()
    {
        int i, j;
        pi = 0;
        memset(flag, false, sizeof(flag));
        for (i = 2; i < MAXN; i++)
            if (!flag[i])
            {
                primes[pi++] = i;
                for (j = i; j < MAXN; j += i)
                    flag[j] = true;
            }
    }
    void PrintfArray()
    {
        for (int i = 0; i < pi; i++)
            printf("%d ", primes[i]);
        putchar('\n');
    }
    int main()
    {
        printf("用筛素数法求100以内的素数\n-- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");  
        GetPrime_1();
        PrintfArray();
        return 0;
    }

    运行结果如下:

    截图20141127165746

    在上面程序是用bool数组来作标记的,bool型数据占1个字节(8位),因此用位操作来压缩下空间占用将会使空间的占用减少八分之七。

    下面考虑下如何在数组中对指定位置置1,先考虑如何对一个整数在指定位置上置1。对于一个整数可以通过将1向左移位后与其相或来达到在指定位上置1的效果,代码如下所示:

    //在一个数指定位上置1
        int j = 0;
        j |=  1 << 10;
        printf("%d\n", j);

    同样,可以1向左移位后与原数相与来判断指定位上是0还是1(也可以将原数右移若干位再与1相与)。

    //判断指定位上是0还是1
        int j = 1 << 10;
        if ((j & (1 << 10)) != 0)
            printf("指定位上为1");
        else
            printf("指定位上为0");

    扩展到数组上,我们可以采用这种方法,因为数组在内存上也是连续分配的一段空间,完全可以“认为”是一个很长的整数。先写一份测试代码,看看如何在数组中使用位操作:

    #include <stdio.h>
    int main()
    {
        printf("     对数组中指定位置上置位和判断该位\n");
        printf("--- by MoreWindows( http://blog.csdn.net/MoreWindows )  ---\n\n");
        //在数组中在指定的位置上写1
        int b[5] = {0};
        int i;
        //在第i个位置上写1
        for (i = 0; i < 40; i += 3)
            b[i / 32] |= (1 << (i % 32));
        //输出整个bitset
        for (i = 0; i < 40; i++)
        {
            if ((b[i / 32] >> (i % 32)) & 1)
                putchar('1');
            else 
                putchar('0');
        }
        putchar('\n');
        return 0;
    }

    运行结果如下:

    截图20141127170031

    可以看出该数组每3个就置成了1,证明我们上面对数组进行位操作的方法是正确的。因此可以将上面筛素数方法改成使用位操作压缩后的筛素数方法:

    #include <stdio.h>
    #include <memory.h>
    const int MAXN = 100;
    int flag[MAXN / 32 + 1];
    int primes[MAXN / 3 + 1], pi;
    void GetPrime_1()
    {
        int i, j;
        pi = 0;
        memset(flag, 0, sizeof(flag));
        for (i = 2; i < MAXN; i++)
            if (!((flag[i / 32] >> (i % 32)) & 1))
            {
                primes[pi++] = i;
                for (j = i; j < MAXN; j += i)
                    flag[j / 32] |= (1 << (j % 32));
            }
    }
    void PrintfArray()
    {
        for (int i = 0; i < pi; i++)
            printf("%d ", primes[i]);
        putchar('\n');
    }
    int main()
    {
        printf("用位操作压缩后筛素数法求100以内的素数\n-- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");  
        GetPrime_1();
        PrintfArray();
        return 0;
    }

    同样运行结果为:

    截图20141127170211

    另外,还可以使用C++ STL中的bitset类来作素数表。筛素数方法在笔试面试出现的几率还是比较大的,能写出用位操作压缩后的筛素数方法无疑将会使你的代码脱颖而出,因此强烈建议读者自己亲自动手实现一遍,平时多努力,考试才不慌。

    位操作的压缩空间技巧也被用于strtok函数的实现,请参考《strtok源码剖析 位操作与空间压缩》(http://blog.csdn.net/morewindows/article/details/8740315

    注2.这种筛素数的方法很朴素,会多次重复访问数据,有什么办法能改进一下吗?请看《改进的筛素数方法》一文

  • 相关阅读:
    从12306.cn谈大网站架构与性能优化
    新浪微博的存储思路整理架构分享--微博架构的回顾
    多吃以上食物可以调理内分泌
    脸部护理
    美容实用小知识
    如何把网页或html内容生成图片
    互联网阅读与知识积累流程化实践分享
    怎样与人沟通?
    如何控制情绪
    如何去掉Google搜索的跳转 让你的Google搜索不被reset掉
  • 原文地址:https://www.cnblogs.com/wuyuan2011woaini/p/4126745.html
Copyright © 2011-2022 走看看