C語言中的排列和組合在實(shí)際的應(yīng)用中使用廣泛。
排列算法
*字典序法
*遞增進(jìn)位制數(shù)法
*遞減進(jìn)位制數(shù)法
*鄰位對換法
*遞歸法
1.字典序法
- 對于給定字符集中的字符規(guī)定了一個先后關(guān)系,在此基礎(chǔ)上按照順序依次產(chǎn)生每個排列。
[例]字符集{1,2,3},較小的數(shù)字較先,這樣按字典序生成的全排列是:123,132,213,231,312,321
2. 遞歸法
- 假設(shè)一組數(shù)p= {r1, r2, r3, … ,rn}, 全排列為perm(p),pn = p – {rn}。則perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), … , rnperm(pn)。當(dāng)n = 1時perm(p} = r1。如下所示:
int n = 0;//記錄排列的數(shù)量
void swap(int *a,int *b)
{
int m;
m = *a;
*a = *b;
*b = m;
}
void Permutation(int *a,int start,int end)
{
int i;
if( start > end )
{
for (i = 0; i <= end; ++i)
{
printf("%d",a[i]);
}
printf("\n");
++n;
}
else
{
for (i = start; i <=end; ++i)
{
swap(&a[start],&a[i]);
Permutation(a,start+1,end);
swap(&a[start],&a[i]);
}
}
}
3. 組合算法
- (1)遞歸:
首先從n個數(shù)當(dāng)中選取編號最大的數(shù),然后在剩下的n-1個數(shù)里面選取m-1個數(shù),直到從n-(m-1)個數(shù)中選取1個數(shù)為止。
從n個數(shù)中選取編號次小的一個數(shù),繼續(xù)執(zhí)行1步,直到當(dāng)前的可選編號最大的數(shù)為m。
/// 求從數(shù)組a[1..n]中任選m個元素的所有組合.
/// a[1..n]表示候選集,n為候選集大小,n>=m>0。
/// b[1..M]用來存儲當(dāng)前組合中的元素(這里存儲的是元素下標(biāo)),
/// 常量M表示滿足條件的一個組合中元素的個數(shù),M=m,這兩個參數(shù)僅用來輸出結(jié)果。
void Combine2(int *a,int n,int m,int *b,const int M)
{
for (int i = n; i >= m; --i)
{
b[m-1] = i-1;
if(m > 1)
{
Combine2(a,i-1,m-1,b,M);
}
else
{
for (int j = M-1; j>=0; --j)
printf("%d",a[b[j]]);
printf("\n");
}
}
}
// m為你要從a中的len個數(shù)當(dāng)中選出的數(shù)的個數(shù)。
void Combine(int *a,int len,int m)
{
if(NULL == a || len<1 || m < 1 || m > len)
return ;
int *tmp = (int *)malloc(m*sizeof(int));
Combine2(a,len,m,tmp,m);
free(tmp);
}
- (2) 01轉(zhuǎn)換法:
基本思路是使用一個與候選數(shù)組等長的數(shù)組,其下標(biāo)表示1到N個數(shù),數(shù)組元素的值為1表示其代表的數(shù)被選中,為0則未選中。
流程:
- 首先初始化,將數(shù)組前n個元素置1,表示第一個組合為前n個數(shù)。
- 然后從左到右掃描數(shù)組元素值的“10”組合,找到第一個“10”組合后將其變?yōu)椤?1”組合,同時將其左邊的所有“1”全部移動到數(shù)組的最左端。
- 當(dāng)?shù)谝粋€“1”移動到數(shù)組的n-m的位置,即n個“1”全部移動到最右端時,就得到了最后一個組合。
例如求5中選3的組合:
1 1 1 0 0 //1,2,3
1 1 0 1 0 //1,2,4
1 0 1 1 0 //1,3,4
0 1 1 1 0 //2,3,4
1 1 0 0 1 //1,2,5
1 0 1 0 1 //1,3,5
0 1 1 0 1 //2,3,5
1 0 0 1 1 //1,4,5
0 1 0 1 1 //2,4,5
0 0 1 1 1 //3,4,5