Manually trace recursive functions
在上述问题中,如果答案得到批准,则
void string_permutation(string str, int mid, int end)
{
if (mid == end)
cout << str << endl;
else
{
for (int i = mid; i <= end; i++)
{
swap(str[mid], str[i]);
string_permutation(str, mid + 1, end);
swap(str[mid], str[i]);
}
}
}
假设我们尝试运行以下命令:("abcd", 0, 3)
根据之前给出的答案,"bacd"
是字符串在第一个递归调用(第二个函数调用)期间更改为的第一件事,因此,第一个调用+第一个递归调用如下所示:< / p>
("abcd", 0, 3)
("bacd", 1, 3)
但是,当我教给for循环时,据说for循环的内容是在递增(修改索引)之前完成的。
这意味着在第一次递归调用之前,我们有int i = mid
,这意味着mid == 0
和i == 0
,因此在第一次递归调用之前实际发生的交换是:
swap(str[0], str[0]);
,这意味着传递给递归调用的str仍然是("abcd", 1, 3)
,仍然是abcd
那么为什么另一个问题中的最高答案将字符串更改为"bacd"
?我缺少for循环吗? i
或mid
中的哪个是1,或者答案有误?
谢谢。
答案 0 :(得分:1)
输入第一个函数调用(mid = 0
,end = 3
)。
输入第一次循环迭代(i = 0 = mid
)
将str[0]
与其本身交换。
输入第二个函数调用(mid = 1
,end = 3
)。
输入第一次循环迭代:i = mid = 1
。
将str[1]
与其本身交换。
输入第三个函数调用(mid = 2
,end = 3
)。
输入第一次循环迭代:i = mid = 2
。
将str[2]
与其本身交换。
输入第四个函数调用(mid = end = 3
)。
abcd
。 将str[2]
与其本身交换。
输入第二个循环迭代:i = 3
用str[2]
(str[3]
-> abcd
)交换abdc
。
输入另一个函数调用(mid = end = 3
)。
abdc
。 将str[2]
换回str[3]
(回到abcd
)。
循环已完成。
将str[1]
本身交换
输入第二个循环迭代:i = 2
以此类推...
为了方便阅读,此处复制了程序:
void string_permutation(string str, int mid, int end)
{
if (mid == end)
cout << str << endl;
else
{
for (int i = mid; i <= end; i++)
{
swap(str[mid], str[i]);
string_permutation(str, mid + 1, end);
swap(str[mid], str[i]);
}
}
}
我相信另一个问题的回答者对如何遍历排列有不同的思维模式。无论如何,这是通过调试器运行的结果。
很容易看出该程序调用{{1}} N! (次)时间(每次通话会导致更多string_permutation
的通话,其中end-mid
会增加一)。还很容易看到每对mid
将字符串恢复为函数输入时的样子。在任何给定的swap
处,该算法将从mid
到mid
的每个字符放在位置end
上并递归。通过归纳(基本情况mid
),我们可以看到所有排列都是通过这种方式解决的。
但是,该算法不能正确处理重复字符。我推荐std::next_permutation
。