全排列
全排列
- 因为全排列好像一直都没太明白(虽然可以用next_permutation)正好作业里有就顺便记录一下
引入
-
我们都知道,如果是固定个数个全排列,比如1,2,3的全排列,我个人认为最简单的方法是
int n = 3; for(int a = 1;a<=n;a++){ for(int b = 1;b<=n;b++){ for(int c = 1;c<=n;c++){ if(a==b||b==c||a==c)continue; printf("%d %d %d",a,b,c); } } } 套三层循环的意义是,一共有三个位置需要排数,每层循环控制一位上的数字
第5行的if就是用来判断有没有重复的数字,有就跳过
-
那么如果是n个数的全排列呢?
n个数的全排列,就有n位需要填数字,也就是说,需要n层的循环
但是我们正常没办法写出不定层数的循环
这个时候就需要递归了
循环层数的控制
-
如果我们在函数体中写一个循环,在循环体中写一个自调用,那么每进入一次函数,都相当于是循环多了一层
int x=2; void f(int n){ if(n==x) return; for(int i = 0;i<x;i++){ f(n+1); } } f(0); 上面这个函数可以变为
int x = 2; void f(0){ for(int i = 0;i<x;i++){ f(1); } } 再进一步
int x = 2; void f(0){ for(int i = 0;i<x;i++){ for(int j = 0;j<x;j++){ ... } } } 至此,我们就可以通过递归来控制循环的层数了
去重
-
我个人认为,递归函数各层之间似乎不是很容易通信,所以我使用了一个数组传来传去以记录填过的数字
-
既然我们之前定义了一个变量n以记录当前循环层数,那么这个n其实就是当前排列的第n项(见引入部分的代码)
-
那么我们就可以向这一位填入数字,但是填入数字前需要检查这个数字有没有使用过,所以我写了一个Used函数
bool isUsed(int A[],int x,int t){ for(int i = 0;i<x;i++){ if(A[i]==t) return true; } return false; } int f(int A[],int x){ if(x == n){ //输出 return 0; } for(int i = 1;i<=n;i++){ if(isUsed(A,x,i)) continue; A[x] = i; f(A,x+1); } }
递归边界
- 如果已填位数等于总位数,即为这个排列已经排完了,需要输出
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库