递归生成任意长度的所有“单词”

时间:2015-04-06 07:39:53

标签: c++ recursion nested permutation

我有一个工作函数,可生成特定长度的所有可能“单词”,即

AAAAA
BAAAA
CAAAA
...
ZZZZX
ZZZZY
ZZZZZ

我想将此函数概括为任意长度。

在下面的可编译C ++代码中 iterative_generation()是工作职能和 recursive_generation()是WIP替代品。

请记住,这两个函数的输出不仅略有不同,而且也是镜像的(这对我的实现没有任何影响)。

#include <iostream>
using namespace std;

const int alfLen = 26; // alphabet length
const int strLen = 5;  // string length
char word[strLen];     // the word that we generate using either of the
                       // functions
void iterative_generation() {          // all loops in this function are
    for (int f=0; f<alfLen; f++) {     // essentially the same
        word[0] = f+'A';
        for (int g=0; g<alfLen; g++) {
            word[1] = g+'A';
            for (int h=0; h<alfLen; h++) {
                word[2] = h+'A';
                for (int i=0; i<alfLen; i++) {
                    word[3] = i+'A';
                    for (int j=0; j<alfLen; j++) {
                        word[4] = j+'A';
                        cout << word << endl;
                    }
                }
            }
        }
    }
}

void recursive_generation(int a) {
    for (int i=0; i<alfLen; i++) { // the i variable should be accessible
        if (0 < a) {               // in every recursion of the function
            recursive_generation(a-1); // will run for a == 0
        }
        word[a] = i+'A';
        cout << word << endl;
    }
}

int main() {
    for (int i=0; i<strLen; i++) {
        word[i] = 'A';
    }
    // uncomment the function you want to run
    //recursive_generation(strLen-1); // this produces duplicate words
    //iterative_generation(); // this yields is the desired result
}

我认为问题可能是我在所有递归中使用相同的i变量。在迭代函数中,每个for循环都有自己的变量。

这个的确切后果是什么,我不能说,但递归函数有时会产生重复的单词(例如ZAAAA连续出现两次,**AAA生成两次)。

你能帮我改变递归函数,使其结果与迭代函数的结果相同吗?

修改

我意识到我只需要打印最里面功能的结果。以下是我将其更改为:

#include <iostream>
using namespace std;

const int alfLen = 26;
const int strLen = 5;
char word[strLen];

void recursive_generation(int a) {
        for (int i=0; i<alfLen; i++) {
                word[a] = i+'A';
                if (0 < a) {
                        recursive_generation(a-1);
                }
                if (a == 0) {
                        cout << word << endl;
                }
        }
}

int main() {
        for (int i=0; i<strLen; i++) {
        word[i] = 'A';
        }
        recursive_generation(strLen-1);
}

3 个答案:

答案 0 :(得分:3)

事实证明,你毕竟不需要递归来将你的算法推广到任意长度的单词。

您需要做的就是通过可能的词语“计算”。如果有一个任意的话,你会怎么去下一个字?

记住计数如何适用于自然数。如果你想从123999转到它的后继124000,你用零替换尾随的九,然后递增下一个数字:

123999
     |
123990
    |
123900
   |
123000
  |
124000

注意我们如何将数字视为0到9之间的数字字符串。我们可以对字符串使用与其他字母表相同的想法,例如从A到Z的字符字母:

ABCZZZ
     |
ABCZZA
    |
ABCZAA
   |
ABCAAA
  |
ABDAAA

我们所做的只是用As替换尾随Zs然后递增下一个字符。没什么了不起的。

我建议你现在用C ++自己实现这个想法。为了比较,这是我的解决方案:

#include <iostream>
#include <string>

void generate_words(char first, char last, int n)
{
    std::string word(n, first);
    while (true)
    {
        std::cout << word << '\n';
        std::string::reverse_iterator it = word.rbegin();
        while (*it == last)
        {
            *it = first;
            ++it;
            if (it == word.rend()) return;
        }
        ++*it;
    }
}

int main()
{
    generate_words('A', 'Z', 5);
}

如果您想从左到右计数(如您的示例所示),只需将reverse_iterator替换为iteratorrbegin替换为begin和{{ 1}}与rend

答案 1 :(得分:0)

您的递归解决方案有2个错误:

  1. 如果您需要按字母顺序打印,请&#39; a&#39;需要从0上升,而不是相反

  2. 您只需要在最后一级打印,否则您有重复

    void recursive_generation(int a) {
    for (int i=0; i<alfLen; i++) 
    { // the i variable should be accessible
        word[a] = i+'A';
        if (a<strLen-1) 
            // in every recursion of the function
            recursive_generation(a+1); // will run for a == 0
        else
            cout << word << '\n';
    }
    

    }

答案 2 :(得分:0)

当我从@fredoverflow的回答中获得启发时,我创建了以下代码,它可以相对较快地执行相同的操作。

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>

void printAllPossibleWordsOfLength(char firstChar, char lastChar, int length) {
    char *word = new char[length];
    memset(word, firstChar, length);
    char *lastWord = new char[length];
    memset(lastWord, lastChar, length);
    int count = 0;

    std::cout << word << " -> " << lastWord << std::endl;

    while(true) {
        std::cout << word << std::endl;
        count += 1;
        if(memcmp(word, lastWord, length) == 0) {
            break;
        }
        if(word[length - 1] != lastChar) {
            word[length - 1] += 1;
        } else {
            for(int i=1; i<length; i++) {
                int index = length - i - 1;
                if(word[index] != lastChar) {
                    word[index] += 1;
                    memset(word+index+1, firstChar, length - index - 1);
                    break;
                }
            }
        }
    }

    std::cout << "count: " << count << std::endl;

    delete[] word;
    delete[] lastWord;
}

int main(int argc, char* argv[]) {
    int length;
    if(argc > 1) {
        length = std::atoi(argv[1]);
        if(length == 0) {
            std::cout << "Please enter a valid length (i.e., greater than zero)" << std::endl;
            return 1;
        }
    } else {
        std::cout << "Usage: go <length>" << std::endl;
        return 1;
    }
    clock_t t = clock();
    printAllPossibleWordsOfLength('A', 'Z', length);
    t = clock() - t;
    std:: cout << "Duration: " << t << " clicks (" << ((float)t)/CLOCKS_PER_SEC << " seconds)" << std::endl;
    return 0;
}