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;
}