// 求N个数的全排列 #include "stdafx.h" #include <iostream> #include <Windows.h> #include <string> using namespace std; #define N 5 int n = 0; void output(int str[N], int begin) { if (begin == N - 1) { for (int i = 0; i < N; i++) { cout<<str[i]<<"\t"; } cout<<endl; n++; return; } for (int p = begin; p < N; p++) { int t = str[p]; str[p] = str[begin]; str[begin] = t; output(str, begin+1); t = str[p]; str[p] = str[begin]; str[begin] = t; } } int _tmain(int argc, _TCHAR* argv[]) { int a[N],i; for (i = 0; i < N; i++) { a[i] = i+1; } cout<<"所有的排序:"<<endl; output(a, 0); cout<<endl<<"共有 "<<n<<"种"<<endl; system("pause"); return 0; }
这是递归算法,相应的时间复杂度和空间复杂度会很大,下面是非递归算法:
要考虑全排列的非递归实现,先来考虑如何计算字符串的下一个排列。如"1234"的下一个排列就是"1243"。只要对字符串反复求出下一个排列,全排列的也就迎刃而解了。
如何计算字符串的下一个排列了?来考虑"926520"这个字符串,我们从后向前找第一双相邻的递增数字,"20"、"52"都是非递增的,"26 "即满足要求,称前一个数字2为替换
数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到"956220",然后再将替换点后的字符"6220"颠
倒即得到"950226"。对于像"4321"这种已经是最“大”的排列,采用STL中的处理方法,将字符串整个颠倒得到最“小”的排列"1234"并返回false。这样,只要一个循环再加上计算
字符串下一个排列的函数就可以轻松的实现非递归的全排列算法。按上面思路并参考STL中的实现源码,不难写成一份质量较高的代码。值得注意的是在循环前要对字符串排序
下!