产生所有排列
来源:互联网 发布:常见的机构域名 编辑:程序博客网 时间:2024/06/05 17:41
问题描述:以字典顺序产生所有排列。假定集合set是连续的并且按从小到大顺序排列好了的,并且有n个元素。
思路:算法的思路分成两个部分:A是递归产生以某个数字开头的排列,B是调用A来依次生成 1为第一位的所有排列,2为第一位的所有排列,....n为第一位的所有排列。
下面是A部分的详细思路:
1.以1234为例子。从右到左来寻找< (j=i+1,i>0)。
2.接着再从右到左查找第一个比大的元素,然后将二者交换位置,再将到集合末尾逆序。这样就找到了1234的按字典顺序的下一个元素。
3.递归进行。要注意递归的一个关键就是递归的结束条件。这里,以1开头的排列的最后一个数是1432,也就是说最后一个元素到第2个元素(第一个元素为1,肯定不能动)都没有<,也就是说,第二位及以后的元素都按照逆序排列好了,也就是找到了最后一个元素。这就是递归结束的条件。
A部分的代码如下:
1 //find out all of the permutation in the set with first element 1 to n. 2 void find_next() 3 { 4 set_print(); 5 int index_i,index_j,index_k; 6 flag=0; 7 for(index_i=n-2;index_i>0;index_i--) 8 if(set[index_i]<set[index_i+1]) 9 {10 index_j=index_i+1;11 flag=1;12 break;13 }14 if(flag==0)15 return ;16 for(index_k=n-1;index_k>0;index_k--)17 if(set[index_k]>set[index_i])18 break;19 swap(&set[index_i],&set[index_k]);20 reverse(index_j,n-1);21 22 find_next();23 }
下面是B部分的详细思路:
1.B部分的算法主要负责执行A算法之后的增大首位的转折点,举个例子,就是1432的下一个元素是2134,从首位是1变到了首位是2。
2.当A算法执行完后,元素是1432,这时,将第4位与第1位交换,就会得到2431,那么,很容易看出除了第一位之外其余都是按照逆序排列的,2431肯定不是1432的下一个数,2431与1432之间肯定还存在有符合条件的排列。于是,将除了第一位之外的元素逆序,就可达到目的,即2134。这才是1432的下一个元素。
3.当到达2431后,即2开头的最后一个元素,又将第3位与第一位交换,再将首位之后的元素逆序,即可得到3开头的第一个数。
4.那么,可以总结出,当首位为1时,就将最后一位与首位交换;当首位为2时,就将倒数第2位与首位交换;当首位为3时,就将倒数第3位与首位交换.....依次类推。这其中的道理很容易想明白。这样持续n次,所有结果就都得到了。
B部分的代码如下:
1 int count=1; 2 int i=n-1; 3 while(i>=0) 4 { 5 set[0]=count++; 6 find_next(); 7 swap(&set[0],&set[i]); 8 reverse(1,n-1); 9 i--;10 }
完整的代码如下:
1 #include <stdio.h> 2 #define MAX 1000 3 4 int n=4; 5 int set[MAX]={1,2,3,4}; 6 int flag=0; 7 8 //swap a and b 9 void swap(int *a,int *b)10 {11 int temp=*a;12 *a=*b;13 *b=temp;14 }15 16 //reverse a range of a set17 void reverse(int start,int end)18 {19 int index_r=0;20 int new_end=end-start;21 for(index_r=0;index_r<=new_end/2;index_r++)22 swap(&set[index_r+start],&set[new_end-index_r+start]);23 24 }25 26 void set_print()27 {28 int index;29 for(index=0;index<n;index++)30 printf("%d ",set[index]);31 printf("\n");32 }33 34 //find out all of the permutation in the set with first element 1 to n.35 void find_next()36 {37 set_print();38 int index_i,index_j,index_k;39 flag=0;40 for(index_i=n-2;index_i>0;index_i--) 41 if(set[index_i]<set[index_i+1])42 {43 index_j=index_i+1;44 flag=1;45 break;46 }47 if(flag==0)48 return ;49 for(index_k=n-1;index_k>0;index_k--)50 if(set[index_k]>set[index_i])51 break;52 swap(&set[index_i],&set[index_k]);53 reverse(index_j,n-1);54 55 find_next();56 }57 58 int main()59 {60 int count=1;61 int i=n-1;62 while(i>=0)63 {64 set[0]=count++;65 find_next(); 66 swap(&set[0],&set[i]);67 reverse(1,n-1);68 i--;69 }70 return 0;71 }
参考资料:《C语言名题精选百则技巧篇》
如果你觉得我的文章对你有帮助,请推荐一下,非常感谢!
<script type="text/javascript"><!--google_ad_client = "ca-pub-1944176156128447";/* cnblogs 首页横幅 */google_ad_slot = "5419468456";google_ad_width = 728;google_ad_height = 90;//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
- 产生所有排列
- 产生所有排列
- 产生所有排列---旋转法------2013年1月22日
- 产生所有排列---字典顺序-----2013年1月23日
- 如何产生全排列?
- 随机排列数组的产生
- 产生 X 个数 的排列
- 产生均匀随机排列数组
- 一组数所有排列
- 生成所有排列
- 所有不同的排列
- 字符串的所有排列
- 字符串的所有排列
- 产生[n]所有置换
- 回溯法 求所有子集 所有排列
- 输出串的所有排列
- NWPU-NOJ-穷举所有排列
- 输出字符串的所有排列
- Android连接SQLServer详细教程(数据库+服务器+客户端)
- Oracle数据库的增删改查(简单操作)
- Thinkpad笔记本无法从U盘启动,无法用光盘装win7的解决办法
- .net 生成一年范围内的年月日表格并填充需要的数据
- myeclipse修改文件编码问题---乱码解决方法
- 产生所有排列
- 最近思想一些变化
- Linux 设备驱动篇之-------I2c设备驱动(待续)
- 互联网史话----十亿美金之51
- 彻底说明二维数组数组名和指针的关系
- java源码剖析之HashMap
- CXF入门
- Ten Places to Go for SharePoint Development Information
- C判断一个数是不是素数