2024.12.09学习笔记
昨天说要更新的全排列问题来啦!
题目如下:
按照字典序输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
解题思路:如何理解这道题的解题逻辑-------->我们可以假设n=3,现在我们需要求出1-3的全排列,因为数据较少,我们可以轻易的列出来,1 2 3 , 1 3 2 ,2 1 3 ,2 3 1 ,3 1 2 ,3 2 1,我们可以观察一下这些数的形成规律,首先从1开始直接按照数字大小,一次排出1 2 3这个排列,之后第二个数发生变化,从2变成3,然后再找到除了用过的数1 3以外的其他数作为第三个数,即1 3 2.那么这里我们就找到了1为首元素的所有排列。接下来会让第一个数字依次变化为2,再次寻找相关的不同排列。。。最后我们会得到所有不重复的排列。
关键!!要实现以上的想法,我们就要用到深搜。
这里简单和大家讲解一下深搜在这道题目的运用思路(如果大家还不知道深搜的,可以专门去找深搜专题的文章,都很详细)
我们可以利用循环先找第一层的数,比如先找到了1,然后需要判断这个数是否被用过,防止使用的数出现重复。当没有被使用时我们先将这个数标记一下,表明在这一次接下来我要排的这个排列中,这个数已经用过,后续不能再用。然后将这个数放进一个最终我们会打印出结果的数组中存储。接下来就是关键,我们会再次调用深搜函数,将目前到达的层数放入函数中,通过再次调用该函数寻找第二个数,再次进入循环时,我们又会从1开始查,但是在上一层函数中,我们已经标记了1,所以我们又会开始查2,因为没有被用过,所以2就被放到了数组的第二个,再次调用深搜函数,直到放入的数已经与我们要的排列的个数相等,就将存储数的数组打印出来,然后函数开始回归,要注意的还有一点就是,每次回归我们都要将之前标记的数的标记取消掉,因为要重新开始新的排列
递归的终止条件:因为我们需要全排列,所以必须排列的结果必须由n个数组成,当排列的数达到n时函数开始回归
说明内容较为繁琐,代码更加清楚明了,在代码中也写清了注释,方便整理思路,便于理解和复习
以下是代码:
//1-n的全排列
int n = 0;
int pd[20];
int used[20];
void print()
{
int i;
for (i = 1; i <= n; i++)
{
printf("%5d", used[i]);
}
printf("\n");
return;
}
void dfs(int x)
{
if (x == n)//当到最后一层时,就可以将数组打印出来,然后这个递归将开始回归步骤
{
print();
return;
}
int i;
for (i = 1; i <= n; i++)//要排列的数
{
if (!pd[i])//判断这个数是否使用过
{
pd[i] = 1;//标记节点,代表已经使用,之后不能再用
used[x + 1] = i;//将这个数存储起来,例如x为0时,则x+1表示第一层的位置
dfs(x + 1);//进入函数,寻找下一个节点
pd[i] = 0;//回溯(在一条路径已经完成时,我们要重新找一条路径,则需要将标记的记录删除掉)
}
}
}
如果代码有什么不太清楚的地方,欢迎提问。如果有什么不好的地方,欢迎建议和指正。
感谢观看。
444

被折叠的 条评论
为什么被折叠?



