C - 编码串生成算法

时间:2015-06-06 12:20:22

标签: c string

这是其中一个问题,在任何更高级别的语言中都是小菜一碟,但是当用纯C语言编写它时,我不知道该怎么做才能不把我的代码变成一团糟:

我有一个独特字母的字母,一个带有一些数字的字符串,例如“test01test21”。我需要生成所有字符串,这些字符串是用字母替换数字所以(因此每个数字0,1,2,...得到它的字母(不一定是唯一的),我们需要迭代所有可能的字母数字替换,以便生成所有字符串),并以某种方式返回这些字符串。

问题似乎很容易,但我想的越多,问题就越多。当返回结果时,我已经编码了动态字符串列表结构,因此它不是主要问题。我想知道的是如何遍历所有字母数字替换(请记住,数字集不是常数,要在一个字符串中替换的数字可能是{0,1,2}而在另一个字符串中{例如,3,7,9},但它总是一些数字集合,这里有几个我想过的方法:

  1. 我们可以制作10个嵌套for循环,循环遍历字母表,替换10个可能的数字。这个问题 - 它是高度无法编码的,并且做了太多不必要的计算。
  2. 我们可以在最开始制作10个元素的假初始化数组,扫描字符串,标记所有当前数字,将它们复制到其他数组。现在,初始数组将用作数字字母映射,第二个数组(数字集)将以某种方式为我们提供“迭代器帮助器”(我们必须以某种方式遍历数字,如第1点所示,只有这次会有be | number-set |嵌套for-loops而不是10 for循环)。这个问题 - 我仍然不知道如何通过数字集编码迭代,你可以看到它甚至在文本中很快变得复杂 - 我不想想如果我是什么会发生什么用C语言编写代码。
  3. 我真的想不出别的什么。我认为这两种方式都存在缺陷,导致代码非常复杂。问题是 - 当你必须在C中解决这类问题时该怎么办?我会感谢任何有助于我编写代码并以某种方式组织代码的提示......

    示例输出:

    字母“ab”

    字符串“ab01”

    输出{“abaa”,“abab”,“abba”,“abbb”}

3 个答案:

答案 0 :(得分:6)

您必须使用tries数据结构。只需开始阅读您的字符串并构建tries即可。 让我们举个例子,它应该是这样的。

    a             a
    |             |
    b             b
    |            / \
    0    -->    a   b
    |          / \ /  \
    1         a   b    a
              |   |    |
             \0  \0   \0

上面例子中按字符构建的字符:

a ------ b -------  0 -------  1 ------- \0

a ---->  a ------>  a ------>  a ------>   a 
|        |          |          |           |
\0      >b          b          b           b
         |         / \        / \         / \
        \0      >a    b      a   >b      a   b
                 |    |     / \   |     / \ / \
                \0   \0    a   b  \0   a   b   a
                          |   |        |   |   |
                         \0   \0       \0  \0  \0

                              |
                              |
                              v

                              a
                              |
                              b
                            /  \
                           a    b
                          / \  / \
                         a    b   a 
                         |    |   |  
                        \0   \0  \0

现在你所要做的只是遍历尝试。 请查看以下有用的链接以获取帮助:1 2

答案 1 :(得分:2)

扩展我上面的评论:你甚至不需要任何奇特的数据结构。

这是一段非常简单的代码(错误处理和其他铃声以及为了清晰起见而省略的哨声),它们会产生重复的变化:

char the_string[] = "abc12def34";
char *digit_pos[strlen(the_string)];
char replacements[] = "XYZ";
int n = strlen(replacements);

// memoize all digit positions
int k = 0;
for (char *p = the_string; *p; p++)
    if (isdigit(*p))
        digit_pos[k++] = p;

// generate all variations
int bound = pow(n, k);
for (int i = 0; i < bound; i++) {
    // convert 'i' to its digits;
    // use them to index into replacements array
    int tmp = i;
    for (int j = 0; j < k; j++) {
        *digit_pos[j] = replacements[tmp % n];
        tmp /= n;
    }

    printf("%s\n", the_string);
}

答案 2 :(得分:1)

这是一个递归算法,我认为它更接近您的用例:

#include <stdio.h>
#include <string.h>

void printone(const char *alphabet, int rep[], const char *str) {
    char buf[strlen(str) + 1];
    int i, c;
    for (i = 0; (c = str[i]) != '\0'; i++) {
        if (c >= '0' && c <= '9')
            c = alphabet[rep[c - '0']];
        buf[i] = (char)c;
    }
    buf[i] = '\0';
    puts(buf);
}

int printrec(const char *alphabet, int alen, int rep[], int digit, int maxd, const char *str) {
    int count = 0;
    for (;; digit++) {
        if (digit >= maxd) {
            printone(alphabet, rep, str);
            return 1;
        }
        if (!strchr(str, '0' + digit))
            continue;

        for (rep[digit] = 0; rep[digit] < alen; rep[digit]++) {
            count += printrec(alphabet, alen, rep, digit + 1, maxd, str);
        }
        return count;
    }
}

int main(int argc, char **argv) {
    if (argc < 3) {
        fprintf(stderr, "usage: %s alphabet string\n", argv[0]);
        return 1;
    } else {
        int rep[10];
        int count = printrec(argv[1], strlen(argv[1]), rep, 0, 10, argv[2]);
        fprintf(stderr, "%d combinations\n", count);
        return 0;
    }
}