Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/254.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 理解递归以生成置换_C++_Recursion - Fatal编程技术网

C++ 理解递归以生成置换

C++ 理解递归以生成置换,c++,recursion,C++,Recursion,我发现递归,除了像阶乘这样非常直截了当的递归,很难理解。下面的代码段打印字符串的所有排列。有人能帮我理解吗。正确理解递归的方法是什么 void permute(char a[], int i, int n) { int j; if (i == n) cout << a << endl; else { for (j = i; j <= n; j++) { swap(a[i], a[j])

我发现递归,除了像阶乘这样非常直截了当的递归,很难理解。下面的代码段打印字符串的所有排列。有人能帮我理解吗。正确理解递归的方法是什么

void permute(char a[], int i, int n)
{
   int j;
   if (i == n)
     cout << a << endl;
   else
   {
       for (j = i; j <= n; j++)
       {
          swap(a[i], a[j]);          
          permute(a, i+1, n);
          swap(a[i], a[j]);
       }
   }
} 

int main()
{
   char a[] = "ABCD";
   permute(a, 0, 3);
   getchar();
   return 0;
}
void排列(字符a[],整数i,整数n)
{
int j;
如果(i==n)

cout它从所有可能留下的字符中选择每个字符:

void permute(char a[], int i, int n)
{
    int j;
    if (i == n)                  // If we've chosen all the characters then:
       cout << a << endl;        // we're done, so output it
    else
    {
        for (j = i; j <= n; j++) // Otherwise, we've chosen characters a[0] to a[j-1]
        {                        // so let's try all possible characters for a[j]
            swap(a[i], a[j]);    // Choose which one out of a[j] to a[n] you will choose
            permute(a, i+1, n);  // Choose the remaining letters
            swap(a[i], a[j]);    // Undo the previous swap so we can choose the next possibility for a[j]
        }
    }
} 
void排列(字符a[],整数i,整数n)
{
int j;
如果(i==n)//如果我们选择了所有字符,那么:

cout它从所有可能留下的字符中选择每个字符:

void permute(char a[], int i, int n)
{
    int j;
    if (i == n)                  // If we've chosen all the characters then:
       cout << a << endl;        // we're done, so output it
    else
    {
        for (j = i; j <= n; j++) // Otherwise, we've chosen characters a[0] to a[j-1]
        {                        // so let's try all possible characters for a[j]
            swap(a[i], a[j]);    // Choose which one out of a[j] to a[n] you will choose
            permute(a, i+1, n);  // Choose the remaining letters
            swap(a[i], a[j]);    // Undo the previous swap so we can choose the next possibility for a[j]
        }
    }
} 
void排列(字符a[],整数i,整数n)
{
int j;
如果(i==n)//如果我们选择了所有字符,那么:

coutPaulR有一个正确的建议。你必须“手动”(使用任何你想要的工具——调试器、纸张、记录函数调用和特定点的变量)运行代码,直到你理解它。关于代码的解释,我将让你参考quasiverse的优秀答案

也许这种调用图的可视化(字符串稍小)使其工作原理更加明显:

这张图是用铅笔画的


PaulR有一个正确的建议。你必须“手动”(使用任何你想要的工具——调试器、纸张、记录函数调用和特定点的变量)运行代码,直到你理解为止。关于代码的解释,我将让你参考quasiverse的优秀答案

也许这种调用图的可视化(字符串稍小)使其工作原理更加明显:

这张图是用铅笔画的


为了在设计中有效地使用递归,您可以通过假设已经解决了问题来解决问题。 当前问题的心理跳板是“如果我能计算n-1个字符的排列,那么我可以通过依次选择每个字符并附加剩余n-1个字符的排列来计算n个字符的排列,我假装我已经知道如何做”

然后你需要一种方法来做所谓的“见底”递归。因为每个新的子问题都比上一个小,也许你最终会得到一个你真正知道如何解决的子问题


在这种情况下,你已经知道一个字符的所有排列-它只是一个字符。因此你知道如何求解n=1,对于每一个比你能求解的数字多一个的数字,你就完成了。这与所谓的数学归纳法密切相关。

要在设计中有效地使用递归,你需要通过假设你已经解决了这个问题来解决它。 当前问题的心理跳板是“如果我能计算n-1个字符的排列,那么我可以通过依次选择每个字符并附加剩余n-1个字符的排列来计算n个字符的排列,我假装我已经知道如何做”

然后你需要一种方法来做所谓的“见底”递归。因为每个新的子问题都比上一个小,也许你最终会得到一个你真正知道如何解决的子问题


在这种情况下,你已经知道一个字符的所有排列-它只是一个字符。所以你知道如何求解n=1,对于每一个比一个数字多一个的数字,你就可以求解了。这与所谓的数学归纳法密切相关。

尽管这是一个古老的问题,而且已经存在回答了添加我的输入以帮助新访问者的想法。还计划解释运行时间,而不关注递归协调

我已经用C语言编写了这个示例,但是对于大多数程序员来说很容易理解

static int noOfFunctionCalls = 0;
static int noOfCharDisplayCalls = 0;
static int noOfBaseCaseCalls = 0;
static int noOfRecursiveCaseCalls = 0; 
static int noOfSwapCalls = 0;
static int noOfForLoopCalls = 0;

static string Permute(char[] elementsList, int currentIndex)
{
    ++noOfFunctionCalls;

    if (currentIndex == elementsList.Length)
    {
        ++noOfBaseCaseCalls;        
        foreach (char element in elementsList)
        {
            ++noOfCharDisplayCalls;

            strBldr.Append(" " + element);
        }
        strBldr.AppendLine("");
    }
    else
    {
        ++noOfRecursiveCaseCalls;

        for (int lpIndex = currentIndex; lpIndex < elementsList.Length; lpIndex++)
        {
            ++noOfForLoopCalls;

            if (lpIndex != currentIndex)
            {
                ++noOfSwapCalls;
                Swap(ref elementsList[currentIndex], ref elementsList[lpIndex]);
            }

            Permute(elementsList, (currentIndex + 1));

            if (lpIndex != currentIndex)
            {
                Swap(ref elementsList[currentIndex], ref elementsList[lpIndex]);
            }
        }
    }
    return strBldr.ToString();
}

static void Swap(ref char Char1, ref char Char2)
{
    char tempElement = Char1;
    Char1 = Char2;
    Char2 = tempElement;
}      

public static void StringPermutationsTest()
{
    strBldr = new StringBuilder();
    Debug.Flush();

    noOfFunctionCalls = 0;
    noOfCharDisplayCalls = 0;
    noOfBaseCaseCalls = 0;
    noOfRecursiveCaseCalls = 0;
    noOfSwapCalls = 0;
    noOfForLoopCalls = 0;

    //string resultString = Permute("A".ToCharArray(), 0);
    //string resultString = Permute("AB".ToCharArray(), 0);
    string resultString = Permute("ABC".ToCharArray(), 0);
    //string resultString = Permute("ABCD".ToCharArray(), 0);
    //string resultString = Permute("ABCDE".ToCharArray(), 0);

    resultString += "\nNo of Function Calls : " + noOfFunctionCalls;
    resultString += "\nNo of Base Case Calls : " + noOfBaseCaseCalls;
    resultString += "\nNo of General Case Calls : " + noOfRecursiveCaseCalls;
    resultString += "\nNo of For Loop Calls : " + noOfForLoopCalls;
    resultString += "\nNo of Char Display Calls : " + noOfCharDisplayCalls;
    resultString += "\nNo of Swap Calls : " + noOfSwapCalls;

    Debug.WriteLine(resultString);
    MessageBox.Show(resultString);       
}
static int noofffunctioncalls=0;
静态int noOfCharDisplayCalls=0;
静态int noOfBaseCaseCalls=0;
静态int noOfRecursiveCaseCalls=0;
静态int noOfSwapCalls=0;
静态int noOfForLoopCalls=0;
静态字符串排列(char[]elementsList,int currentIndex)
{
++中午电话;
if(currentIndex==elementsList.Length)
{
++noOfBaseCaseCalls;
foreach(elementsList中的char元素)
{
++无障碍显示呼叫;
strBldr.Append(“+”元素);
}
strBldr.附录行(“”);
}
其他的
{
++没有草率的案例调用;
对于(int lpIndex=currentIndex;lpIndex// C program to print all permutations with duplicates allowed
#include <stdio.h>
#include <string.h>

/* Function to swap values at two pointers */
void swap(char *x, char *y)
{
    char temp;
    temp = *x;
    *x = *y;
    *y = temp;
}

/* Function to print permutations of string
   This function takes three parameters:
   1. String
   2. Starting index of the string
   3. Ending index of the string. */
void permute(char *a, int l, int r)
{
   int i;
   if (l == r)
     printf("%s\n", a);
   else
   {
       for (i = l; i <= r; i++)
       {
          swap((a+l), (a+i));
          permute(a, l+1, r);
          swap((a+l), (a+i)); //backtrack
       }
   }
}

/* Driver program to test above functions */
int main()
{
    char str[] = "ABC";
    int n = strlen(str);
    permute(str, 0, n-1);
    return 0;
}