本文一共提供了4种全排列的方法,包括递归非字典序版本、递归字典序版本、标准库版本和BFS字典序版本,当然BFS非字典序实现相对于BFS字典序版本更加简洁,稍加修改即可。

说明:递归版本基于网上现有代码修改而成,标准库版本参照msdn sample修改而成,最后的BFS版本是由本人在看到题目后思考而来,并实现之(递归版本很久之前写过),所有四种算法都加了模板。当然BFS版本效率相对于递归要快,相对于STL版本则较慢,仅仅提供一种思路而已

注:对于这种小算法,自己主动思考可以开阔思路,而且想出一种新思路感觉会很不错;对于已成型的经典或者复杂算法,新思路的空间会非常小,所以可以以掌握为主。

  1.  

/**
 @description: generating permunation
 @author: seiyagoo
 @create: 2013.10.10
 @modified: 2013.10.11
 **/

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <list>
  5. #include <queue>
  6. #include <iterator>
  7. #include <algorithm>
  8. using namespace std;
  9.  
  10. #define MAX 10
  11. int used[MAX]; //用来标记数字是否已经在前面使用过
  12. int result[MAX]; //存放结果
  13. int array[MAX] = {,,,,,,,,,};
  14.  
  15. void swap(int x, int y){
  16.  
  17. int temp = array[x];
  18. array[x]=array[y];
  19. array[y]=temp;
  20.  
  21. return;
  22. }
  23.  
  24. template<typename T>
  25. void printArray(T array[], int size){
  26. int i;
  27.  
  28. for (i=;i<size;i++)
  29. cout << array[i] << " ";
  30. cout << endl;
  31.  
  32. return;
  33. }
  34.  
  35. /*递归(非字典序)*/
  36. template<typename T>
  37. void recur_permute(T array[], int begin, int end)
  38. {
  39. int i;
  40. if (begin==end)
  41. {
  42. printArray(array, end+);
  43. return;
  44. }
  45. else{
  46. //for循环遍历该排列中第一个位置的所有可能情况
  47. for (i=begin; i<=end; i++){
  48. swap(begin, i); //循环变换第一个位置
  49. recur_permute(array, begin+, end); //DFS
  50. swap(begin, i); //回溯,保持原排列
  51. }
  52. }
  53. }
  54.  
  55. /*递归(字典序)*/
  56. template<typename T>
  57. void lexi_recur_permute(T array[], int begin, int end)
  58. {
  59. int i;
  60. if (begin == end+)
  61. {
  62. printArray(result, end+);
  63. return;
  64. }
  65. else{
  66. for (i=; i<=end; i++){
  67. if(!used[i]) //没有标记
  68. {
  69. used[i]=; //标记
  70. result[begin]=array[i]; //记录结果
  71. lexi_recur_permute(array, begin+, end);
  72. used[i]=; //回溯
  73. }
  74.  
  75. }
  76. }
  77. }
  78.  
  79. /*STL(字典序)*/
  80. template<typename T>
  81. void stl_permute(T array[], int size)
  82. {
  83. vector<T>::iterator begin, end;
  84. vector<T> Pattern(size) ;
  85. ostream_iterator<T> out_it(cout, " ") ;
  86.  
  87. //int size=sizeof(array)/sizeof(T);
  88.  
  89. for(int i=; i<size; i++)
  90. Pattern[i]=array[i];
  91.  
  92. begin = Pattern.begin() ;
  93. end = Pattern.end() ;
  94.  
  95. do
  96. {
  97. copy(begin, end, out_it) ;
  98. cout << endl ;
  99. }while ( next_permutation(begin, end) );
  100. }
  101.  
  102. int get_factorial(int n)
  103. {
  104. if(==n || ==n) return ;
  105. else return n*get_factorial(n-);
  106. }
  107.  
  108. /*给定元素个数n,以及数组p,返回全排列的序号*/
  109. template<typename T>
  110. int perm2num(int n, T *p){
  111. int i, j, num=,k=;
  112. for (i=n-;i>=;i--)//注意下标从0开始
  113. {
  114. for (j=i+;j<n;j++)
  115. if (p[j]<p[i]) num+=k;//是否有逆序,如有,统计
  116. k*=n-i; //每一轮后k=(n-i)!,
  117. }
  118. return num;
  119. }
  120.  
  121. /*BFS(字典序)*/
  122. template<typename T>
  123. void bfs_permute(T array[], int size)
  124. {
  125. int idx=;
  126. int cnt=get_factorial(size);
  127.  
  128. list<T> ls;
  129. queue<list<T>> q;
  130.  
  131. ls.push_back(array[]);
  132.  
  133. q.push(ls);
  134. while(!q.empty())
  135. {
  136. list<T> cur_perm = q.front();
  137. if(cur_perm.size() == size) //第n层的第一个元素长度等于size,循环结束
  138. break;
  139. if(cur_perm.size() != idx) //不相等
  140. idx++;
  141.  
  142. q.pop();
  143.  
  144. list<T>::iterator it = cur_perm.end();
  145. while( it!=cur_perm.begin() )
  146. {
  147. cur_perm.insert(it, array[idx]); //插入
  148. q.push(cur_perm);
  149. it=cur_perm.erase(--it); //还原
  150.  
  151. --it; //向前一步找插入点
  152.  
  153. if( it==cur_perm.begin() ) //第一个插入点特殊处理并结束
  154. {
  155. cur_perm.push_front(array[idx]);
  156. q.push(cur_perm);
  157. cur_perm.clear();
  158. break;
  159. }
  160. }
  161. }
  162. print_queue(q, size, cnt);
  163. }
  164.  
  165. template<typename T>
  166. void print_queue(queue<list<T>> q, int size, int cnt)
  167. {
  168. vector<list<T>> vec(cnt);
  169. T* perm=new T[size]; //存储当前排列
  170.  
  171. /*映射*/
  172. while(!q.empty())
  173. {
  174. list<T> cur_perm=q.front();
  175. q.pop();
  176. list<T>::iterator it=cur_perm.begin();
  177.  
  178. int idx=,i=;
  179. int n=size;
  180. while(it!=cur_perm.end())
  181. {
  182. perm[i++]=*it++;
  183. }
  184.  
  185. //当前排列放入全排列对应位置
  186. idx=perm2num(size, perm);
  187. vec[idx]=cur_perm;
  188. }
  189. delete []perm;
  190.  
  191. /*输出*/
  192. vector<list<T>>::iterator vit=vec.begin();
  193. for(;vit!=vec.end();vit++)
  194. {
  195. list<T> cur_perm=*vit;
  196. list<T>::iterator lit=cur_perm.begin();
  197. for(;lit!=cur_perm.end();lit++)
  198. {
  199. cout<<*lit<<" ";
  200. }
  201. cout<<endl;
  202. }
  203. }
  204.  
  205. int main(){
  206. recur_permute(array, , );
  207. lexi_recur_permute(array, ,);
  208. stl_permute(array, );
  209. bfs_permute(array, );
  210. return ;
  211. }

最后再附上STL版本算法思路及修改后的代码(仅仅为了可读性):

思路

给定已知序列P =  A1A2A3.....An
对P按字典排序,得到P的一个最小排列Pmin = A1A2A3....An ,满足Ai > A(i-1) (1 < i <= n)
从Pmin开始,找到刚好比Pmin大的一个排列P(min+1),再找到刚好比P(min+1)大的一个排列,如此重复。
1.从后向前(即从An->A1),找到第一对为升序的相邻元素,即Ai < A(i+1)。
  若找不到这样的Ai,说明已经找到最后一个全排列,可以返回了。
2.从后向前,找到第一个比Ai大的数Aj,交换Ai和Aj。
3.将排列中A(i+1)A(i+2)....An这个序列的数逆序倒置,即An.....A(i+2)A(i+1)。因为由前面第1、2可以得知,A(i+1)>=A(i+2)>=.....>=An,这为一个升序序列,应将该序列逆序倒置,所得到的新排列才刚刚好比上个排列大。
4.重复步骤1-3,直到返回。
这个算法是C++ STL算法next_permutation的思想。
 
代码
  1. template <class BidirectionalIterator>
  2. bool next_permutation(BidirectionalIterator first,
  3. BidirectionalIterator last) {
  4. BidirectionalIterator i=last;
  5. if (first == last || first==--i) return false; //单个元素或空则无下一个排列,且使i指向最后一个元素
  6. for(;;) {
  7. BidirectionalIterator ii = i--; //i在前,ii在后,循环查找直至*i>=*ii
  8. if (*i <*ii) { //第一个非降序的元素(即*i)
  9. BidirectionalIterator j = last;
  10. while (!(*i <*--j)); //在降序序列[ii,last)中从后往前查找第一个大于*i的数
  11. iter_swap(i, j); //交换*i,*j,则[ii,last)依然为降序序列
  12. reverse(ii, last); //翻转[ii,last)为升序
  13. return true;
  14. }
  15. if (i == first) { //没找到连续的两个升序数,则已经是降序序列,直接翻转全部序列
  16. reverse(first, last);
  17. return false;
  18. }
  19. }
    }

generating permunation——全排列(算法汇总)的更多相关文章

  1. generating permunation

    generating permunation——全排列(算法汇总) #include <iostream> #include <string> #include <vec ...

  2. 排序算法汇总(C/C++实现)

    前言:     本人自接触算法近2年以来,在不断学习中越多地发觉各种算法中的美妙.之所以在这方面过多的投入,主要还是基于自身对高级程序设计的热爱,对数学的沉迷.回想一下,先后也曾参加过ACM大大小小的 ...

  3. 全排列算法的JS实现

    问题描述:给定一个字符串,输出该字符串所有排列的可能.如输入“abc”,输出“abc,acb,bca,bac,cab,cba”. 虽然原理很简单,然而我还是折腾了好一会才实现这个算法……这里主要记录的 ...

  4. 不会全排列算法(Javascript实现),我教你呀!

    今天我很郁闷,在实验室凑合睡了一晚,准备白天大干一场,结果一整天就只做出了一道算法题.看来还是经验不足呀,同志仍需努力呀. 算法题目要求是这样的: Return the number of total ...

  5. 边缘检测matlab算法汇总

    边缘检测matlab算法汇总 1.      基于一阶微分算子检测边缘图像 一阶微分边缘算子又称梯度边缘算子,它是利用图像在边缘处的阶跃性,及图像梯度在边缘去得极大值得特征性进行边缘检测. Sobel ...

  6. JavaScript 数据结构与算法之美 - 十大经典排序算法汇总(图文并茂)

    1. 前言 算法为王. 想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手:只有内功深厚者,前端之路才会走得更远. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 ...

  7. PHP字符串全排列算法

    <?php /** * PHP字符串全排列算法 */ $results = []; $arr = []; function bfs($start) { global $arr; global $ ...

  8. 全排列算法--递归实现(Java)

    求一个n阶行列式,一个比较简单的方法就是使用全排列的方法,那么简述以下全排列算法的递归实现. 首先举一个简单的例子说明算法的原理,既然是递归,首先说明一下出口条件.以[1, 2]为例 首先展示一下主要 ...

  9. 排列算法汇总(下一个排列,全排列,第K个排列)

    一.下一个排列 首先,STL提供了两个用来计算排列组合关系的算法,分别是next_permutation和prev_permutation. next_permutation(nums.begin() ...

随机推荐

  1. lighttpd启动不了,libssl.so.4&amp;libcrypto.so.4 缺失

    lighttd的出错日志在 log/out_lighttpd 里,当lighttd启动不了时候,这里文件中会说明原因. 今天的报错是 error while loading shared librar ...

  2. 使用gnu automake编译helloworld

    使用gnu automake编译helloworld 按照许多介绍automake基本步骤的教程中的说法,我在尝试使用automake编译helloworld示例程序的时候,仍然遇到了几个小坑,所幸后 ...

  3. JavaScript 实现表格单列按字母排序

    <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title> ...

  4. 免费的EmBitz可替代Keil MDK开发STM32、NXP项目

    一.背景 由于使用之前开发STM32是基于Keil MDK编译环境开发的,由于该软件是收费的,想用个免费开源的软件来替代Keil,EmBitz编译器是免费的,可以完全替代开发.下载程序支持J-Link ...

  5. 5.Zookeeper的两种安装和配置(Windows):单机模式与集群模式

    转自:https://blog.csdn.net/a906998248/article/details/50815031

  6. [RxJS] How To get the results of two HTTP requests made in sequence

    switchMap can chain two HTTP requests together, creating one request based on the results of the fir ...

  7. cocos2d-x 3.x游戏开发学习笔记(1)--mac下配置cocos2d-x 3.x开发环境

    打开用户文件夹下.bash_profile文件,配置环境 vim ~/.bash_profile //按键i,进行插入编辑(假设输错d进行删除一行) 环境配置过程例如以下: 1.首先配置下androi ...

  8. [D3] Make D3 v4 Charts Responsive with the viewBox attribute

    Making SVGs responsive is unfortunately not as simple as adding some media queries. This lesson intr ...

  9. Linux中IRC通讯工具Pidgin的基本用法

    这是我发在南昌大学开源小组里的一篇教程 IRC IRC是个古老的产物,在图形界面流行之前就出现了.可是在现在非常多开源社区都是利用IRC来进行团队交流或对用户提供技术支持的,比方维基百科,所以还是有必 ...

  10. OpenNI2获取华硕XtionProLive深度图和彩色图并用OpenCV显示

    使用OpenNI2打开XtionProLive时有个问题,彩色图分辨率不管怎样设置始终是320*240,深度图倒是能够设成640*480,而OpenNI1.x是能够获取640*480的彩色图的. 彩色 ...