要求:输入任意长度的不含重复元素的数组,打印出该数组的全部全排列。
-
方向:考虑使用递归算法
1.问题可拆成子问题:将n个元素的全排列拆成n-1个元素的全排列。
2.边界条件(递归的尽头):只有1个元素时,返回该元素本身。
3.将n个元素全排列拆成n-1个元素全排列,相当于固定了当前元素。 -
算法的实现
void perm(vector<int> &a, int head, int end, int n) {
if (head == end) {
display(a, n);
return;
}
for (int i = head; i <= end; i++) {
swap(a, head, i);
perm(a, head + 1, end, n);
swap(a, head, i);
}
}
实例:a={1,2,3}
程序执行过程:
要对1、2、3全排列,先固定住1,对2、3进行全排列
要对2、3全排列,先固定住2,对3进行全排列
要对3进行全排列,但检测到3只有一个元素,于是3排列完毕(就是3)输出当前组合1、2、3,并返回至上一层2、3的全排列
要对2、3全排列,2已经固定过,便将2与3换位,固定3,对2进行全排列
要对2进行全排列,但检测到2只有一个元素,于是输出当前组合1、3、2
2、3也全排列完毕,再返回上一层,对1、2、3进行全排列
1已经固定过,便将1与2换位,对1、3进行全排列…
以此类推,直至最顶端(1、2、3)完成全排列
3.一些遇到的问题
- 实现用户输入任意数字(无论几个)的全排列:使用动态数组vector容器
关于vector的一些基本操作:
基本方法:指路1
作为函数参数传递:指路2(将动态数组以引用形式传给函数是很重要的,与静态数组不同,将数组名作为参数传入,会被视作值传递,便会发生拷贝构造,即swap函数的交换只发生在函数体内部,无法传出)
4.拓展与思考
- 本题限定的输入条件是“不含重复元素”的数组,如果含重复元素呢?
解决:加入判断是否需要交换的函数"judgeswap"
bool judgeswap(vector<int> &a, int i, int j) {
if(a[i]==a[j]&&i!=j)//不需要交换的条件:两个不同位置元素值相等
return false;
else
return true;
}
再在主要全排列算法中加入该函数即可
更改后如下:
for (int i = head; i <= end; i++) {
if (judgeswap(a, head, i)) {
swap(a, head, i);
perm(a, head + 1, end, n);
swap(a, head, i);
}
}
这样的算法就可以避免在有重复元素的情况下出现多种相同情况重复输出的情况了。
本文介绍了如何使用递归算法实现全排列。针对输入的不含重复元素的数组,通过固定当前位置元素并递归处理其余元素,达到全排列的效果。文章讨论了动态数组vector的使用,以及如何处理含重复元素的情况,通过添加`judgeswap`函数避免重复输出。
1295





