原创
排列组合问题是算法中很基础又很常用的算法,在我的几篇知识浅薄的博客中也列出了全排列的递归算法,全排列的递归算法
复杂,还有更加优化的算法,过几天我会写新随笔列出;今天,我写了非递归的组合算法,相比于递归的组合算法有所改进,但
是我只是借鉴了大神博客里面的思想,在此附上链接http://www.waitingfy.com/archives/1016
代码是自己编写的,思想水平可能也不高,有错误的地方,请大家指出,赐教了。
解题思路不难理解,用了一种被称为二进制的方法——从N个数中取M个数组合,开辟一个N个空间的数组A,A的数组下标代表了N个
数的下标(N个数存放在另外一个大小为N的数组中),数组A的元素置1,表明选中了这个下标,反之,表示没选中。
问题转换为在数组A中置M个1,不重不漏的找出所有组合的方法如下:
一、先让A中元素全置0,然后将前M个元素置1(代表先选择前M个元素的下标);
二、从A的首元素起向右搜索,当首次遇到当前元素为1,下一个元素为0时,交换两个元素;
三、在二步中将10组合换成01组合后,将元素0前面的所有1元素(假设有T个)全都往前推,直到前T个元素全置为1。
四、此时得到一种组合,可以输出;回到第二步,继续寻找下一种组合,直到A后面的M个元素全部置为1(此时为最后一种组合)。
还是辣个栗子:
从数组 { 1,2,3,4,5 }选出3个元素组合;
数组A的变化为:(蓝色代表10组合的交换,红色代表1的前置)
1 1 1 0 0 —— 7 (我们按权位从左往右计算换成十进制)
1 1 0 1 0 —— 11
1 0 1 1 0 —— 13
0 1 1 1 0 —— 14
1 1 0 0 1 —— 19
1 0 1 0 1 —— 21
0 1 1 0 1 —— 22
1 0 0 1 1 —— 25
0 1 0 1 1 —— 26
0 0 1 1 1 —— 28
按照这种方法,发现换成十进制后的数据从小到大排列(当然,也可以反过来——先将A后面的M个元素置1,接下来的步骤反向操作即可)。
从上可知,这种方法从小到大不重不漏的找出了所有的组合数,首步的前M个元素置1即找出了最小组合数,接下来将10组合换成01组合,并且
将0元素前的1置前是为了求次小组合数,通过从左到右的权位不难理解;在次小组合的基础上我们再求次次小的组合数。
写的代码可能不够简洁、简练,主要是提供给大家一个思路:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #define m 3
4
5 int arr[]={2,5,64,10,55,89};
6
7 void combination(int *p,int M)
8 {
9 int i;
10 for(i=0;i<=sizeof(arr)/4-1;i++)
11 {
12 if(p[i]==1 && p[i+1]==0) //找到'10'组合,交换
13 {
14 p[i]=0;
15 p[i+1]=1;
16 /*
17 int j;
18 int count=0; //统计交换后0前面有多少个1
19 for(j=0;j<i;j++)
20 {
21 if( p[j]==1 )
22 count++;
23 }
24 for(j=0;j<i;j++)
25 p[j]=0;
26 for(j=0;j<count;j++) //把1前置
27 p[j]=1;
28 */
29 int left,right;
30 for(left=0;left<i;left++) // left代表0,right代表1
31 {
32 if( p[left]==0 )
33 {
34 for(right=left+1;right<i;right++)
35 {
36 if( p[right]==1 )
37 {
38 p[left]=1; //交换
39 p[right]=0;
40 break;
41 }
42 }
43 }
44 }
45 int j;
46 for(j=0;j<=sizeof(arr)/4-1;j++)
47 if(p[j]==1)
48 printf("%d ",arr[j]);
49 printf("
");
50 int flag=0;
51 for(j=sizeof(arr)/4-1;j>=sizeof(arr)/4-M;j--)
52 {
53 if(p[j]==0)
54 flag=1;
55 }
56 if(flag==0)
57 break;
58 i=-1; //新的一轮
59 }
60 }
61 }
62
63 int main()
64 {
65 int i;
66 int *p=(int *)malloc(sizeof(int)*(sizeof(arr)/4));
67 for(i=0;i<=sizeof(arr)/4-1;i++) //置0
68 p[i]=0;
69
70 for(i=0;i<=m-1;i++) //前M位置1
71 p[i]=1;
72 int j;
73 for(j=0;j<=sizeof(arr)/4-1;j++)
74 if(p[j]==1)
75 printf("%d ",arr[j]);
76 printf("
");
77 combination(p,m);
78 free(p);
79 return 0;
80 }
2018-04-08