对于递归,感觉今天老师的一句话说的很对,想要用递归实现那就是想想怎么从n-1的状态到n的状态,找出了怎么从n-1的状态到n的状态,那么你的递归就出来一大半了,接下来需要注意的就是初始化条件,也就是状态1(或1,2等)的值。
那么对于全排列这个递归实现的话,我们首先是想想状态n-1,怎么我们能实现从状态n-1到状态n的转变呢?我们假设我们现在找出了所有的n-1的全排列,为了简单化我们想在假设我们要找n=3的数字全排列,n-1的全排列即2的全排列,2的全排列很容易找到:1,2;2,1;那么从2的全排列推到3的全排列,我们可以简单的在所有2的全排列后加上数字上,那么我们得到两个数列:1,2,3,;2,1,3;因为3是我们新加入的数字,所以数字3的位置可以位于第1,第2,第3三位,我们现在仅仅放在了第三位,所以我们在得到的两个数列中将数字3分别和第1,第2位调换即可,那么我们一共可以得到2*3=6个排列,即我们n=3的全排列。
我们从上面n=3的数字全排列中,总结出全排列从状态n-1到状态n的规律,即在所有n-1的全排列后加上数字n,让后将最后一位n与所有位上数置换,即可得到状态n的全排列
/*************************************************/
/* 递归产生全排列 */
/*************************************************/
#include<iostream>
using namespace std;
/*初始化全排列字符串*/
char s[20] = {"123456789"};
/*交换函数*/
void swap(int &a, int &b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
/* 递归产生全排列 */
void perm(char *s, int n)
{
if(n == 1)
puts(s);
else
{
for(int i = 0; i <= n-1; ++i)
{
swap(s[i],s[n-1]); // 交换字符
perm(s, n-1); // 递归
swap(s[n-1],s[i]); // 换回来
}
}
}
int main()
{
int n;
puts("请输入全排列长度n"); // 全排列长度
cin >> n;
s[n] = '\0';
perm(s,n);
system("pause\n");
return 0;
}
非递归全排列,用队列模拟实现
/*
非递归全排列实现(队列实现)
思想还是参照递归实现方式,从n-1状态到n状态
*/
#include<iostream>
#include<deque>
#include<string>
using namespace std;
deque<string>s1;
int main()
{
int n;
string s("123456789");
s1.push_back(s);
cout << "输入全排列位数n" << endl;
cin >> n;
if(n == 1) // 实现1位全排列即其本身
{
cout << "1" << endl;
return 0;
}
int i = 1;
while(i < n ) // 产生1到n的全排列
{
deque<int>::size_type t = s1.size(); // i-1状态全排列个数
for(deque<int>::size_type j = 0; j < t ; ++j) // 遍历i-1状态全排列
{
for(int k = 0; k < i+1; ++k) // 由i-1状态全排列产生i状态全排列
{
s = s1[j];
swap(s[k],s[i]);
if(i < n-1) // 达到以求数位n全排列即停止
s1.push_back(s);
else
{
s.erase(n, 9-n);
cout << s << endl;
}
}
}
for(deque<int>::size_type j = 0; j < t ; ++j) // 将所有i-1状态全排列出队列
s1.pop_front();
i++;
}
return 0;
}