2011.10.21算法学习日志-生成元素的全排列

来源:互联网 发布:win10开机没有网络图标 编辑:程序博客网 时间:2024/05/16 14:45

思维起源于LRJ的那本算法竞赛入门书籍7.2.1生成1~n的全排列,而且最近在BYR论坛上也频繁看到众兄弟们去面试的时候别问起有关全排列的问题。

说明:一下所有全排列输出都按照字典序排列顺序输出。

1.先描述最简单的全排列算法思想吧。

我们尝试用递归的思想解决:先输出最小的数(这一步是递归调用),然后输出第2小的数(又是递归调用),接着输出。。。最后是输出最大的数(这一步又是递归调用)

我们设计递归函数需要一下参数:

1)已经确定的“前缀”序列,以便输出。

2)需要进行全排列的元素集合,以便依次选做第一个元素。

这样,我们得到一个伪代码:

void print_permutatin(序列A,集合S)

{

  if(S为空) 输出序列A

 else 按照从小到大的顺序依次考虑集合S中的每个元素

  {

     print_permutation(在A的末尾添加v后得到的新序列,S-{v});

  }

}

其中A可以用数组表示,集合S根本不用表示,因为它可以由序列A完全确定(A中没有出现的元素都可以选)。唯一要添加的就是一个整数n代表数组A中当前需要确定的位置cur(对应于下面的程序中的eff_n+1)

下面是我理解完LRJ书上的代码后,自己实现的程序:

相比于LRJ的代码,我这个程序不像他的程序局限于1~n的数字,这里可以是任意的数字,字符,都行。

需要注意的是:如果初始给的集合a中有重复的数字或者字符,那么全排列中必定会有相同的排列,怎样编写程序直接只输出不同的排列是一个以后需要思考的问题(恰好是BYR论坛上前段时间一个兄弟说的一个公司的笔试题还是面试题)。



#include<iostream>
#include<algorithm>
using namespace std;
const int N = 5;
int a[N];


void print_permutation(const int eff_n,int *A)
{
if( eff_n == N-1 )
{
for(int i=0; i<N; ++i)
cout<<A[i]<<" ";
cout<<endl;
}
else for( int i = 0 ; i < N; ++i )
{
bool already_exist = false;
for( int j=0; j<=eff_n; ++j)
{
if( A[j] == a[i] )
{
already_exist = true;
break;
}
}
if( !already_exist )
{
A[eff_n+1] = a[i];
print_permutation(eff_n+1,A);
}
}
}


int main()
{
freopen("data_out1.txt","w",stdout);
for(int i=0; i<N; ++i)
a[i] = i;
sort(a,a+N);         //对数组a排序。
int *A = new int[N];
//int A[N];
memset(A,0xff,N*sizeof(int));
print_permutation(-1,A);
delete[] A; A = NULL;
return 0;
}


本次学习的进步之处:明白了怎样充分利用递归来构造全排列。

相关展望:1.好像还有其他的方法可以构造全排列,去学习一下。

                 2.学习怎样生成不重复的全排列。

最近学习安排: 这个周末必须搞定上面这两项,外加可恶又可爱的KMP算法(数据结构+算导 全部看完理解透彻)。