位操作与空间压缩

位操作与空间压缩

本文着重对筛素数法所使用的的素数表进行优化来减小其空间占用。要压缩素数表的空间占用,可以使用位操作。下面是用筛素数法计算100以内的素数示例代码:

#include<stdio.h>
#include<memory.h>

const int MAXN = 100;
bool flag[MAXN];
int primes[MAXN / 3], 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");
    GetPrime_1();
    PrintfArray();
    return 0;
}

在上面程序是用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");
    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;
}

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

#include<stdio.h>
#include<memory.h>
const int MAXN = 100;
int flag[MAXN / 32];
int primes[MAXN / 3], 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 << (1 % 32));
            }
        }
    }
}
void PrintArray(){
    for(int i = 0; i < pi; i++){
        printf("%d ", primes[i]);
    }
    putchar('\n');
}
int main(){
    printf("用位操作压缩后筛素数法求100以内的素数\n");
    GetPrime_1();
    PrintArray();
    return 0;
}

详细参考:https://www.cnblogs.com/zhoug2020/p/4978822.html

上一篇:C语言计算高精度圆周率pi程序的代码


下一篇:C语言通过傅里叶展开式计算圆周率PI的代码