计算包含1的子集的数量

时间:2012-06-04 14:22:13

标签: c algorithm optimization

有一个lengt N的位组(大概是500-700)。我需要得到只包含1的

的每个子集的计数

实施例

N = 32

设置= 0 * 11 * 0 * 111 * 00 * 1 * 0 * 1 * 00 * 1111 * 0 * 11 * 00 * 111 * 000 * 1 * 0 * 1 < / EM> *

Out = { [1] = 4, [2] = 2, [3] = 2, [4] = 1, [5] = 0, ... [32] = 0 }

void get_count(int tab[], int len) {
int *out = calloc(1, sizeof(*out) * INT_BIT * len);
int i, j, k;
int cur;
int count = 0;

for(i = 0; i < len; i++) {
    cur = tab[i];
    for(j = 0; j < INT_BIT; j++) { 
        count += (cur & 1);
        if(!(cur & 1)) { 
            out[count]++; 
            count = 0; 
        }
        cur >>= 1;
    }
}

for(i = 0; i < INT_BIT * len; i++) {
    printf("%d ", out[i]);
}
printf("\n");
free(out);
}

这个简单的操作将执行大约数十亿次。迭代每一点都太慢了。如何优化这个算法?

1 个答案:

答案 0 :(得分:2)

我会使用查找表选择合适的维度(可能是8位或16位密钥)。

在这个查找表中,我将每个键与4个值相关联:

  • 左侧附加的1位数
  • 右侧附有1位数
  • 中间没有附加任何内容的子集数
  • 中间的子集大小

例如,您可以将键11011011与2,2,2相关联,这样您就知道右侧附加了至少1位的左相邻字节将包含其大小为+ 2的子集(当前字节的左侧附加长度),依此类推。

你需要找到一种方法

  • 管理同一个密钥中的多个子集(例如01011010
  • 管理一个包含全1的密钥,以便您必须考虑左字节和右字节,并将密钥长度作为子集长度的一部分。

但是每个在第一个和最后一个位上都有0的键很容易管理,所以你减少了一些可能的键所需的处理量。

我觉得开发很棘手,但它也很有趣,最后你只需要对键进行比较,因为其他所有内容都在查找表中进行了硬编码。当然,我不确定最终的算法是否会超越简单的方法,但在我看来,值得给它一个机会。