全排列问题
void swap(char &a,char &b) { int t = a; a = b; b = t; } void permutation(char *a,int beg,int end) { if(beg == end) { cout<<a<<endl; } else { for (int i=beg;i<end;++i) { swap(a[beg],a[i]); permutation(a,beg+1,end); swap(a[beg],a[i]);//细心,竟然把这个忘记 } } } void Reversal(char *a,int beg,int end) { while (beg<end) { swap(a[beg],a[end]); ++beg; --end; } } bool GenPermutation(char *a,int n)//n指长度 { for (int i = n-1;i>0;--i) { if (a[i-1]<a[i]) { for (int j =n-1;j>i-1;--j) { if (a[j] >a[i-1]) { swap(a[j],a[i -1 ]); Reversal(a,i,n-1); cout<<a<<endl; return true; } } } } return false; } int main() { char a[] = "abc"; cout<<a<<endl; while(GenPermutation(a,sizeof(a)-1)); //permutation(a,0,sizeof(a)-1); }
一、递归实现
从集合中依次选出每一个元素,作为排列的第一个元素,然后对剩余的元素进行全排列,如此递归处理,从而得到所有元素的全排列。以对字符串abc进行全排列为例,我们可以这么做:以abc为例
固定a,求后面bc的排列:abc,acb,求好后,a和b交换,得到bac
固定b,求后面ac的排列:bac,bca,求好后,c放到第一位置,得到cba
固定c,求后面ba的排列:cba,cab。代码可如下编写所示:
二、字典序排列
把升序的排列(当然,也可以实现为降序)作为当前排列开始,然后依次计算当前排列的下一个字典序排列。
对当前排列从后向前扫描,找到一对为升序的相邻元素,记为i和j(i < j)。如果不存在这样一对为升序的相邻元素,则所有排列均已找到,算法结束;否则,重新对当前排列从后向前扫描,找到第一个大于i的元素k,交换i和k,然后对从j开始到结束的子序列反转,则此时得到的新排列就为下一个字典序排列。
生成给定全排列的下一个排列 所谓一个的下一个就是这一个与下一个之间没有字典顺序中相邻的字符串。这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
839647521的下一个排列.
从最右开始,找到第一个比右边小的数字4(因为4<7,而7>5>2>1),再从最右开始,找到4右边比4大的数字5(因为4>2>1而4<5),交换4、5,此时5右边为7421,倒置为1247,即得下一个排列:839651247.用此方法写出全排列的非递归算法如下
算法的目的是要得到词典顺序,因为4是第一个比右边小的数字,所以4之后的串7521肯定是从从大到小的,所以将4和5交换后要对这个字串翻转