我会采用的方法是创建一个与字符串长度相同的索引数组,所有元素都初始化为零。然后我们将这个索引数组视为计数器,以枚举源字符串的所有可能映射。0索引将该位置在字符串中映射到该字符的第一个映射,1映射到第二个,以此类推。我们可以通过仅递增数组中的最后一个索引来按顺序遍历它们,在达到该位置的最大映射数时,将其传递到下一个位置。
以您的示例为例,我们有以下映射:
'a' => 'e', 'o'
'b' => 'i'
对于输入字符串"abba",我们需要一个包含四个元素的数组来表示它们的索引:
[0,0,0,0] => "abba"
[0,0,0,1] => "abbe"
[0,0,0,2] => "abbo"
[0,0,1,0] => "abia"
[0,0,1,1] => "abie"
[0,0,1,2] => "abio"
[0,1,0,0] => "aiba"
[0,1,0,1] => "aibe"
[0,1,0,2] => "aibo"
[0,1,1,0] => "aiia"
[0,1,1,1] => "aiie"
[0,1,1,2] => "aiio"
[1,0,0,0] => "ebba"
[1,0,0,1] => "ebbe"
[1,0,0,2] => "ebbo"
[1,0,1,0] => "ebia"
[1,0,1,1] => "ebie"
[1,0,1,2] => "ebio"
[1,1,0,0] => "eiba"
[1,1,0,1] => "eibe"
[1,1,0,2] => "eibo"
[1,1,1,0] => "eiia"
[1,1,1,1] => "eiie"
[1,1,1,2] => "eiio"
[2,0,0,0] => "obba"
[2,0,0,1] => "obbe"
[2,0,0,2] => "obbo"
[2,0,1,0] => "obia"
[2,0,1,1] => "obie"
[2,0,1,2] => "obio"
[2,1,0,0] => "oiba"
[2,1,0,1] => "oibe"
[2,1,0,2] => "oibo"
[2,1,1,0] => "oiia"
[2,1,1,1] => "oiie"
[2,1,1,2] => "oiio"
在我们开始生成这些字符串之前,我们需要一个地方来存储它们,在C语言中,这意味着我们需要分配内存。幸运的是,我们已经知道了这些字符串的长度,并且我们可以计算出我们要生成的字符串数量-它只是每个位置映射数的乘积。
虽然你可以将它们
返回为数组,但我更喜欢使用回调函数逐个返回它们。
#include <string.h>
#include <stdlib.h>
int each_combination(
char const * source,
char const * mappings[256],
int (*callback)(char const *, void *),
void * thunk
) {
if (mappings == NULL || source == NULL || callback == NULL )
{
return -1;
}
else
{
size_t i;
int rv;
size_t num_mappings[256] = {0};
size_t const source_len = strlen(source);
size_t * const counter = calloc( source_len, sizeof(size_t) );
char * const scratch = strdup( source );
if ( scratch == NULL || counter == NULL )
{
rv = -1;
goto done;
}
for (i = 0; i < 256; i++)
num_mappings[i] = 1 + (mappings[i] ? strlen(mappings[i]) : 0);
do {
rv = callback(scratch, thunk);
if (rv != 0) goto done;
for (i = 0; i < source_len; i++)
{
counter[i]++;
if (counter[i] == num_mappings[(unsigned char) source[i]])
{
counter[i] = 0;
scratch[i] = source[i];
continue;
}
scratch[i] = mappings[(unsigned char) source[i]][counter[i]-1];
break;
}
} while(i < source_len);
done:
if (scratch) free(scratch);
if (counter) free(counter);
return rv;
}
}
#include <stdio.h>
int print_each( char const * s, void * name)
{
printf("%s:%s\n", (char const *) name, s);
return 0;
}
int main(int argc, char ** argv)
{
char const * mappings[256] = { NULL };
mappings[(unsigned char) 'a'] = "eo";
mappings[(unsigned char) 'b'] = "i";
each_combination( "abba", mappings, print_each, (void *) "abba");
each_combination( "baobab", mappings, print_each, (void *) "baobab");
return 0;
}