全排列就是指n个元素随机组合,不重复的所有排列方式,如{1,2,3}就有123,132,213,231,312,321一共6种排列方式。
常见的算法实现分为 递归 和 非递归 ,这里我们用一个例子来辅助说明。{1,2,3,4}
递归的实现:递归是一种优雅的思想,层层推进。首先,我们知道要实现1,2,3,4的全排列,每个数都会在第1个位置出现,那我们先固定第1位是1,而后我们要做的就是对后面的3位子序列进行全排列,这时固定子序列的第一位为2。 依此类推,直到子序列只剩1位,返回。画个简图帮助理解。
c++实现
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 //打印数组全部元素 6 void prt(int arr[],int end){ 7 for(int i=0;i<=end;++i){ 8 printf("%d",arr[i]); 9 } 10 } 11 12 void perm(int arr[],int begin,int end){ 13 if(begin==end){ 14 prt(arr,end); 15 printf("\n"); 16 return; 17 } 18 for(int i=begin;i<=end;++i){ 19 swap(arr[begin],arr[i]); //交换两个元素值 20 perm(arr,begin+1,end); 21 swap(arr[begin],arr[i]); 22 } 23 }
非递归的实现:这里采用的是字典序的方式生成全排列,1,2,3,4这4个数,组成形如1234,1243等序列,这些序列中1234最小,4321最大,由此我们从1234开始(或者4321也行),寻找第一个比1234大的序列,是1243;再寻找第一个比1243大的序列,是1324........依此类推,求出所有序列。
具体实现:从右向左开始,找到第一个这样的数A(n-1)<A(n),从A(n)向右找最后一个比A(n-1)大的数A(m),交换A(n-1)和A(m),将A(n)到末尾所有元素逆序。重复上述步骤直到第一个元素。
c++实现:
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 void perm(int arr[],int len){ 6 if(len<2) return; 7 int i,j,temp; 8 do{ 9 //输出当前序列 10 prt(arr,len-1); 11 printf("\n"); 12 i=j=len-1; 13 //向前查找第一个变小的元素 14 while(i>0&&arr[i]<arr[i-1]) --i; 15 temp=i; 16 if(i==0) break; 17 //先后查找第一个比arr[i-1]大的元素 18 while(temp+1<len&&arr[temp+1]>arr[i-1]) ++temp; 19 swap(arr[i-1],arr[temp]); //交换两个值 20 reverse(arr+i,arr+len); //逆序 21 }while(true); 22 }