void perm(int list[], int k, int m) { if ( ) { copy(list,list+m,ostream_iterator<int>(cout," ")); cout<<endl; return; } for (int i=k; i<m; i++) { swap(&list[k],&list[i]); ( ); swap(&list[k],&list[i]); } }
void perm(int list[], int k, int m) { if ( ) { copy(list,list+m,ostream_iterator<int>(cout," ")); cout<<endl; return; } for (int i=k; i<m; i++) { swap(&list[k],&list[i]); ( ); swap(&list[k],&list[i]); } }
k!=m 和 perm(list,k+1,m)
k==m 和 perm(list,k+1,m)
k!=m 和 perm(list,k,m)
k==m 和 perm(list,k,m)
#include <stdio.h> #include <iterator> #include <iostream> using namespace std; void swap( int *p, int *q) { int temp; temp = *p; *p = *q; *q = temp; } void perm(int list[], int k, int m) { if ( k==m ) { copy(list,list+m+1,ostream_iterator<int>(cout," ")); cout<<endl; return; } for (int i=k; i<=m; i++) { swap(&list[k],&list[i]); ( perm(list,k+1,m) ); swap(&list[k],&list[i]); } } int main(void) { int A[3] = {1,2,3}; perm(A, 0, 2); }
void perm(int list[], int k, int m) {
if (k == m){//递归出口:考虑只重排一个元素[即k = m]
copy(list, list + m + 1, ostream_iterator<int>(cout, " "));
cout << endl;
return;
}
for (int i = k; i <= m; i++) {//只考虑两个元素
swap(list[k], list[i]);//递归前交换
perm(list, k + 1, m); //递归
swap(list[k], list[i]);//交换后再换回来
}
}
void perm(int list[], int k, int m) { if (k == m) { copy(list,list+m,ostream_iterator<int>(cout," ")); cout<<endl; return; } for (int i=k; i<m; i++) { swap(list[k],list[i]); perm(list, k+1, m); swap(list[k],list[i]); } } int main( void ) { int list[] = { 1, 2, 3 }; perm(list, 0, 3); }
//全排列的递归实现 #include <stdio.h> #include <string.h> void Swap(char *a, char *b) { char t = *a; *a = *b; *b = t; } //k表示当前选取到第几个数,m表示共有多少数. void AllRange(char *pszStr, int k, int m) { if (k == m) { static int s_i = 1; printf(" 第%3d个排列\t%s\n", s_i++, pszStr); } else { for (int i = k; i <= m; i++) //第i个数分别与它后面的数字交换就能得到新的排列 { Swap(pszStr + k, pszStr + i); AllRange(pszStr, k + 1, m); Swap(pszStr + k, pszStr + i); } } } void Foo(char *pszStr) { AllRange(pszStr, 0, strlen(pszStr) - 1); } int main() { printf(" 全排列的递归实现\n"); printf(" --by MoreWindows( http://blog.csdn.net/MoreWindows )--\n\n"); char szTextStr[] = "123"; printf("%s的全排列如下:\n", szTextStr); Foo(szTextStr); return 0; }
1 - n-1的全排列为(n-1)!
1 - n的全排列为(n)! = n * (n-1)!
高中时候理解这个递推公式;全排列n是在n-1个数的全排列基础上插入第n个数,共有n种插入方法
现在看了这个题也可以这样理解,在n-1个数的全排列基础上,将n插到第0个位置,然后从0个位置开始,第0号位置与其他1 - n-1号位置元素交换,交换得到1 + n-1种序列(插入0位置也算一种)。上面这个算法就是按照这个思路递归的。
void perm(int list[], int k, int m)
{
if (k == m)
{
copy(list, list + m+1, ostream_iterator<int>(cout, " "));
cout << endl;
return;
}
for (int i = k; i <= m; i++)
{
if (i == k) {
perm(list, k + 1, m);
}
else {
swap(list[k], list[i]);;
perm(list, k + 1, m);
swap(list[k], list[i]);
}
}
}
加个if判断可以较少和自身位置元素交换,可以减少交换次数。性能来说,对于int数组,数组元素和自身交换需要时间和if判断所消耗时间差不多。但对于交换需要较长时间的类型,就会有比较好的效率
对与int[8]{ 1,2,3,4,5,6,7,8};源代码需要交换13856次,改进后代码需要交换80638次
#include <iostream>
#include <algorithm>
#include <iterator>
void perm(int list[], int k, int m)
{
if (k == m)
{
copy(list, list + m + 1, std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;
return;
}
for (int i = k; i <= m; i++)
{
std::swap(list[k], list[i]);
(perm(list, k + 1, m));
std::swap(list[k],list[i]);
}
}
int main(int argc, const char* argv[])
{
int list[] = {1, 2, 3, 4 ,5};
perm(list, 0, 4);
return 0;
}