经典算法题2:递归和字典序的全排列算法
来源:互联网 发布:skynet windows 编辑:程序博客网 时间:2024/05/21 06:30
1,递归的全排列算法
以ABCD为例:
对于ABCD,首先以第一位的字符分为四类:
(1)以A为第一位 ABCD 固定A的位置,A后面跟着BCD的全排列
(2)以B为第一位 BACD (即交换第一个字符A和B的位置),固定B的位置,B后面跟着ACD的全排列
(3)以C为第一位 CBAD (即交换第一个字符A和C的位置),固定C的位置,C后面跟着BAD的全排列
(4)以D为第一位 DBCA (即交换第一个字符A和D的位置),固定D的位置,D后面跟着BCA的全排列
同样的,对于(1)中BCD、(2)中的ACD、(3)中的BAD、(4)中的的BCA的全排列,分别按照上面的形式递归求解。
代码如下:
#include <iostream>using namespace std;template<typename T>void permutation(T array[], int start, int end){ int i; if(array==NULL||start<0||end<0||start>end) return; //reach the end, print array[] if(start == end){ for(i = 0; i <= end; ++i){ cout<<array[i]<<" "; } cout<<endl; return; } for(i = start; i <= end; ++i) { //调换第i个位置与第一个位置 swap(array[i], array[start]); permutation(array, start + 1, end); //恢复数组 swap(array[i], array[start]); }}int main(int argc, char **argv){ char arr[4] = {'A', 'B', 'C', 'D'}; int length=sizeof(arr) / sizeof(arr[0]) - 1; permutation(arr, 0, length) ; return 0;}
2, 字典序全排列算法
字典序排列算法的核心是要找到所有比当前序列大的最小的那个序列,也就是刚好比当前序列大的那个序列。例如1234的下一个字典序为1243,1243刚好比1234大一些。
字典序的实现如下:
设P是1~n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn
1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即 j=max{i|pi<pi+1}
2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即 k=max{i|pi>pj}(右边的数从右至左是递增的,因此k是所有大于pj的数字中序号最大者)
3)对换pj,pk
4)再将pj+1......pk-1pkpk+1......pn倒转得到排列p'=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个排列。
举个栗子:
有数列:23541,要找出它的下一个字典序,具体步骤如下:
1)从右端数字1开始,找到第一个比相邻的右边小的数字,这个数字为3,记下3在数列中的位置 j=1(最左边从0开始数)
2)找出3右边的数字中,第一个比3大的数字,这个数为4,记下这个数的位置 k=3
3)交换位置 j 的数字(3)和位置k 的数字(4),数列变为24531
4)反转位置 j后面的数列(531),最终数列变为24135
24135即为原数列23541的下一个字典序排列。
注意,如果原始序列为54321,已经为最大排列,那么按照上面的方法,是找不到下一个字典序的排列的。
所以,首先要对原始序列进行预处理,有两种方法:
方法1,利用快速排序将原始序列按升序排序,这样就得到最小的排列Pmin
方法2,判断原始序列是不是最大排列Pmax,若是,反转Pmax,使其成为Pmin
实现代码:
//交换数组s中下标为x和y的两个元素值Swap(char *s,int x, int y){ char temp=s[x]; s[x]=s[y]; s[y]=temp;}//反转序列Reverse(char *s,int x, int y){for(;x<y;x++,y--){Swap(s,x,y);}}//快速排序void Qsort(char *s,int low,int high){if(low>=high)return;int start = low;int end = high;int key = s[start];while(start!=end){while(start<end&&s[end]>=key){end--;}s[start]=s[end];while(start<end&&s[start]<=key){start++;}s[end]=s[start];}s[start]=key;Qsort(s,low,start-1);Qsort(s,end+1,high);}bool next_permutation(char *s,int len)int start=len-1;int end=len-1; //s[start-1]>=s[start]中的等号是为了避免序列中有重复的字符而导致的重复的排列 while(start>0&&s[start-1]>=s[start]){start--;}if(start==0)return false;while(end>start-1&&s[start-1]>=s[end]){end--;}Swap(s,start-1,end);Reverse(s,start,len-1);return true;}void permutation(char *s,int len){//快速排序,使原序列为最小一个排列PminQsort(s,0,len-1); /* //也可以不使用Qsort对原序列进行排序,首先判断原序列是否是最大的排列Pmax,如果是的话,反转原序列int boolvalue=0;for(int i=0;i<len-1;i++){if(s[i]<s[i+1]){boolvalue=1;break;}}if(boolvalue==0)Reverse(s,0,len-1); */ do{ for(int i=0;i<len;i++) cout<<s[i]; cout<<endl; }while(next_permutation(s,len));}int main() {char s[]="12345"; int len=strlen(s);permutation(s,len);return 0;}
3,使用C++的STL来实现全排列
如果不想自己写全排列的代码的话,可以直接使用C++的STL中的函数next_permutation. 它的作用是判断一个序列,若存在下一个字典序排列,那么就返回true并产生这个排列,否则返回false。
#include <iostream> #include <algorithm> using namespace std; template <typename BidirectionalIterator> void permutation(BidirectionalIterator array, int len) { sort(array, array + len); do{ for(int i = 0; i < len; ++i){ cout<<array[i]<<" "; } cout<<endl; }while(next_permutation(array, array + len)); } int main() { char s[]="12345"; int len=strlen(s);
permutation(a, len); return 0;
}
参考文章:http://blog.csdn.net/hackbuteer1/article/details/6657435
- 经典算法题2:递归和字典序的全排列算法
- 全排列算法(字典序,递归实现)
- JavaShowAlgorithm-全排列算法递归和字典序实现
- 全排列的递归算法(包括字典序输出和非字典序输出)
- 笔试面试算法经典--全排列算法-递归&字典序实现(Java)
- 全排列算法的字典序排列
- 【算法题】全排列,字典序
- 字典序全排列算法
- 全排列的递归算法
- 全排列的递归算法
- 全排列的递归算法
- 全排列的递归算法!
- 全排列的递归算法
- 全排列的递归算法
- 算法练习 - 字符串的全排列(字典序排列)
- 全排列问题问题的两种算法--递归与字典序
- 算法02:全排列字典序算法
- 关于全排列的递归和非递归算法
- git使用总结
- Android 拖动控件方法(利用onTouch事件,动态调整控件位置)
- 强制去除xcode的编译警告
- Container With Most Water [leetcode]
- mongodb的用户认证
- 经典算法题2:递归和字典序的全排列算法
- datatable数据类型方法
- 车载信息娱乐系统将不再属于汽车厂商
- Android App性能优化(一)之布局优化
- 腾讯2015校园招聘
- lvs、haproxy、nginx 负载均衡的比较分析
- 黑马程序员——多线程
- unicode和字符串之间的转换有两种方式
- LeetCode OJ - Unique Binary Search Trees II