#include <stdio.h>
--- --- --- --- --- --- 生成全排列(递归) --- --- --- --- --- ---
参数解释:s[]:需要生成排列的数组,m:起始下标,n:结束下标
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void perm(int s[],int m,int n)
{
int i,t;
if (m == n) //结束排列,输出
{
for(i = 0; i <= n; i++) printf("%d ",s[i]);
printf("/n");
}
else
for (i = m; i <= n; i++)
{ //把第i个元素换到起始位置
t = s[i]; s[i] = s[m]; s[m] = t;
perm(s,m+1,n); //除起始位置外,其他元素递归排列
t = s[i]; s[i] = s[m]; s[m] = t; //位置复原
}
}
--- --- --- --- --- -- 生成非全排列(递归) --- --- --- --- --- -
原理:与生成全排列相似,区别在于,取最后一个元素的时候,全排列
只有一个可选元素,所以可以直接输出;而非全排列则需要从几
个元素中选出一个,所以还要用循环把这些元素都取一次
参数解释:从下标m到n的元素中取k个做排列
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void permk(int a[],int m,int n,int k)
{
int i,j,t;
if (k == 1 && m <= n) //递归到最后取一个的时候
{
for(i = m; i <= n; i++)
{
if(m > 0) //输出前面排好的元素
for(j = 0; j <= m-1; j++)
printf("%d ",a[j]);
printf("%d/n",a[i]); //输出最后一个
}
}
else if(k > 1)
for (i = m; i <= n; i++)
{ //把第i个元素换到起始位置
t = a[i]; a[i] = a[m]; a[m] = t;
permk(a,m+1,n,k-1); //在剩下的元素中取k-1个
t = a[i]; a[i] = a[m]; a[m] = t; //位置复原
}
}
--- --- --- --- --- --- 生成组合(递归) --- --- --- --- --- --- --- ---
原理:与计数排序类似,计数排序是每个元素与后面的比较,而组合是
每个元素与其后面的元素组合,不考虑其前面的元素,以此避免重复。
例:10个元素中取4个,则第1个元素的取值范围是下标0-6(因剩下的3个
元素只能在第1个元素的后面取,所以第1个元素后面必要至少还有3个元素);
若第1个元素取下标0,则第2个元素的取值范围是下标1-7,……;
若第1个元素取下标1,则第2个元素的取值范围是下标2-7,……;
若第1个元素取下标3,第2个元素取下标5,则第三个元素的取值范围是
下标6-8,……
参数解释:从数组a的,下标m到n的元素中,
取k个放入数组t,其中这k个中的第一个放入t[s]
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
void combine(int a[],int m,int n,int k,int t[],int s)
{
int i;
if (k == 0) //结束组合,输出
{
for(i = 0; i < s; i++)
printf("%d ",t[i]);
printf("/n");
}
else
for (i = m; i <= n-k+1; i++)
{
t[s] = a[i]; //取出第i个
combine(a,i+1,n,k-1,t,s+1);
} //第i+1个开始一直到最后所有的元素中,取k-1个
}
--- --- --- --- --- --- --- 调用 --- --- --- --- --- --- ---
void main()
{
int a[5] = {1,2,3,4,5},t[3]={0};
perm(a,0,4); //全排列
permk(a,0,4,3); //(非全)排列
combine(a,0,4,3,t,0); //组合
}