Generate all sequences of bits within Hamming distance t

不问归期 提交于 2019-11-27 16:20:25
George Kastrinis
#include <stdio.h>
#include <stdint.h>
#include <string.h>

void magic(char* str, int i, int changesLeft) {
        if (changesLeft == 0) {
                printf("%s\n", str);
                return;
        }
        if (i < 0) return;
        // flip current bit
        str[i] = str[i] == '0' ? '1' : '0';
        magic(str, i-1, changesLeft-1);
        // or don't flip it (flip it again to undo)
        str[i] = str[i] == '0' ? '1' : '0';
        magic(str, i-1, changesLeft);
}

int main(void) {
        char str[] = "011";
        printf("%s\n", str);
        size_t len = strlen(str);
        size_t maxDistance = len;
        for (size_t i = 1 ; i <= maxDistance ; ++i) {
                printf("Computing for distance %d\n", i);
                magic(str, len-1, i);
                printf("----------------\n");
        }
        return 0;
}

Output:

MacBook-Pro:hammingDist gsamaras$ nano kastrinis.cpp
MacBook-Pro:hammingDist gsamaras$ g++ -Wall kastrinis.cpp 
MacBook-Pro:hammingDist gsamaras$ ./a.out 
011
Computing for distance 1
010
001
111
----------------
Computing for distance 2
000
110
101
----------------
Computing for distance 3
100
----------------
m8mble

First: There is a bijection between hamming dist k bit-vectors and subsets (of n aka v.size()) of kardinality k (the set of indices with changed bits). Hence, I'd enumerate the subsets of changed indices instead. A quick glance at the SO history shows this reference. You'd have to keep track of the correct cardinalitites of course.

Considering efficiency is probably pointless, since the solution to your problem is exponential anyways.

user58697

If Hamming distance h(u, v) = k, then u^v has exactly k bits set. In other words, computing u ^ m over all masks m with k bits set gives all words with the desired Hamming distance. Notice that such set of mask does not depend on u.

That is, for n and t reasonably small, precompute sets of masks with k bits set, for all k in 1,t, and iterate over these sets as required.

If you don't have enough memory, you may generate the k-bit patterns on the fly. See this discussion for details.

gsamaras

In response to Kastrinis' answer, I would like to verify that this can be extended to my basis example, like this:

#include <iostream>
#include <vector>

void print(std::vector<char>&v)
{
    for (auto i = v.begin(); i != v.end(); ++i)
        std::cout << (int)*i;
    std::cout << "\n";
}

void magic(std::vector<char>& str, const int i, const int changesLeft) {
        if (changesLeft == 0) {
                print(str);
                return;
        }
        if (i < 0) return;
        // flip current bit
        str[i] ^= 1;
        magic(str, i-1, changesLeft-1);
        // or don't flip it (flip it again to undo)
        str[i] ^= 1;
        magic(str, i-1, changesLeft);
}

int main(void) {
        std::vector<char> str = {0, 1, 1};
        print(str);
        size_t len = str.size();
        size_t maxDistance = str.size();
        for (size_t i = 1 ; i <= maxDistance ; ++i) {
                printf("Computing for distance %lu\n", i);
                magic(str, len-1, i);
                printf("----------------\n");
        }
        return 0;
}

where the output is identical.


PS - I am also toggling the bit with a different way.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!