列举所有长度为n和重量的二元数量,最多是k词典

发布于 2025-01-23 01:15:48 字数 2239 浏览 0 评论 0原文

我正在寻找一种算法,该算法列举了给定长度的所有二进制n词典,并限制了每个数字都被跳过,其中具有锤击权重> k,对于给定的k

例如:对于n = 4k = 2

0000
0001
0010
0011
0100
0101
0110
---- skipped 
1000
1001
1010
---- skipped
1100
---- skipped
---- skipped
---- skipped

当然,最直截了当的方法是在每个循环中添加1个,并检查锤子的重量是否结束阈值。但是,对于较大的n,您跳过的元素数量增加,因此检查每个数字的开销也在增加。因此,我也在寻找一种有效的方法来做到这一点。

更新: 我以迭代的方式重复了 @500-Internal-Server-Error,如下所示,

uint64_t update_stack(uint32_t *stack, uint32_t *sp, const uint64_t n, const uint64_t k) {
    if (stack[*sp] == k) {
        uint32_t i = *sp + 1;

        // walk up
        while (stack[i] == k)
            i += 1;

        // update
        stack[i] += 1;
        const uint32_t val = stack[i];
        const uint32_t altered_sp = i;

        // walk down
        while (i > 0) {
            stack[i - 1] = val;
            i -= 1;
        }

        // fix up stack pointer
        *sp = 0;
        return (1ull << (altered_sp + 1)) - 1;
    } else {
        stack[*sp] += 1;
        return 1ull;
    }
}

void Generate(const uint64_t n, const uint64_t k) {
    uint32_t *stack = (uint32_t *)calloc(n-k+1, sizeof(uint32_t));
    uint32_t sp = 0;

    uint64_t ctr = 0;
    while (ctr < (1ull << n)) {

        // number of k windows the algorithm walks through.
        const uint64_t limit = k+1-stack[sp];

        //print_stack(stack, n, k);

        for (uint64_t cw = limit; cw > 1; --cw) {

            // start printing
            const uint64_t nr_steps = (1ull << cw) - 1ull;
            for (uint64_t i = 0; i < nr_steps; ++i) {
                f(ctr++);
            }

            // skip
            const uint64_t nr_skip = update_stack(stack, &sp, n, k);
            ctr += nr_skip;
        }

        f(ctr++);

        const uint64_t nr_skip = update_stack(stack, &sp, n, k);
        ctr += nr_skip;
    }

    free(stack);
}

这很难,但最终奏效了。我还添加了a benchmark 适用于每个有效值,与幼稚方式相比的加速度。对于n = 20k = 3它的150倍(取决于f)。

I'm looking for an algorithm which enumerates all binary numbers of a given length n lexicoraphically, with the constraint that every number is skipped, which has a hamming weight > k, for a given k.

For example: for n=4 and k=2:

0000
0001
0010
0011
0100
0101
0110
---- skipped 
1000
1001
1010
---- skipped
1100
---- skipped
---- skipped
---- skipped

of course the most straight forward way would be to add 1 in every loop iterations and check if the hamming weight is over the threshold. But for larger n the number of elements you skip increases, so the overhead of checking every number is increasing too. So I'm also looking for an efficient way to do this.

Update:
I reemplented @500-internal-server-error in a iterative way as follows

uint64_t update_stack(uint32_t *stack, uint32_t *sp, const uint64_t n, const uint64_t k) {
    if (stack[*sp] == k) {
        uint32_t i = *sp + 1;

        // walk up
        while (stack[i] == k)
            i += 1;

        // update
        stack[i] += 1;
        const uint32_t val = stack[i];
        const uint32_t altered_sp = i;

        // walk down
        while (i > 0) {
            stack[i - 1] = val;
            i -= 1;
        }

        // fix up stack pointer
        *sp = 0;
        return (1ull << (altered_sp + 1)) - 1;
    } else {
        stack[*sp] += 1;
        return 1ull;
    }
}

void Generate(const uint64_t n, const uint64_t k) {
    uint32_t *stack = (uint32_t *)calloc(n-k+1, sizeof(uint32_t));
    uint32_t sp = 0;

    uint64_t ctr = 0;
    while (ctr < (1ull << n)) {

        // number of k windows the algorithm walks through.
        const uint64_t limit = k+1-stack[sp];

        //print_stack(stack, n, k);

        for (uint64_t cw = limit; cw > 1; --cw) {

            // start printing
            const uint64_t nr_steps = (1ull << cw) - 1ull;
            for (uint64_t i = 0; i < nr_steps; ++i) {
                f(ctr++);
            }

            // skip
            const uint64_t nr_skip = update_stack(stack, &sp, n, k);
            ctr += nr_skip;
        }

        f(ctr++);

        const uint64_t nr_skip = update_stack(stack, &sp, n, k);
        ctr += nr_skip;
    }

    free(stack);
}

which was kinda hard, but it finally worked. I also added a Benchmark, which shows for a simple function f which is applied for every valid value, how much the speedup compared to the naive way. For n=20 and k=3 its 150 times faster (depending on f).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

给不了的爱 2025-01-30 01:15:48

您可以递归地进行。

这是C#中的一个示例(对不起,我现在没有设置C/C ++):

class MainClass
{
    static void Generate(int value, int onesLeft, int bitsLeft, int bits)
    {
        if (bitsLeft > 0)
        {
            Generate(value << 1, onesLeft, bitsLeft - 1, bits);
            if (onesLeft > 0)
                Generate((value << 1) + 1, onesLeft - 1, bitsLeft - 1, bits);
        }
        else
        {
            for (int i = 0; i < bits; i++)
            {
                Console.Write((value >> (bits - i) - 1) & 1);
            }
            Console.WriteLine();
        }
    }

    static void Generate(int bits, int maxOnes)
    {
        Generate(0, maxOnes, bits, bits);
    }

    public static void Main()
    {
        Generate(4, 2);
    }
}

生成(4,2)的输出:

0000
0001
0010
0011
0100
0101
0110
1000
1001
1010
1100

生成(5,1)的输出:

00000
00001
00010
00100
01000
10000

You can do it recursively.

Here's an example in C# (sorry, I am not set up for doing c/c++ right now):

class MainClass
{
    static void Generate(int value, int onesLeft, int bitsLeft, int bits)
    {
        if (bitsLeft > 0)
        {
            Generate(value << 1, onesLeft, bitsLeft - 1, bits);
            if (onesLeft > 0)
                Generate((value << 1) + 1, onesLeft - 1, bitsLeft - 1, bits);
        }
        else
        {
            for (int i = 0; i < bits; i++)
            {
                Console.Write((value >> (bits - i) - 1) & 1);
            }
            Console.WriteLine();
        }
    }

    static void Generate(int bits, int maxOnes)
    {
        Generate(0, maxOnes, bits, bits);
    }

    public static void Main()
    {
        Generate(4, 2);
    }
}

Output for Generate(4, 2):

0000
0001
0010
0011
0100
0101
0110
1000
1001
1010
1100

Output for Generate(5, 1):

00000
00001
00010
00100
01000
10000
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文