通用 排列/组合 函数
最近在编写小游戏的过程中发现,排列和组合会经常用到,而两个函数如果每次都编写的话,很容易出错。下面是我编写的通用的排列/组合函数
使用方法参考代码中的注释
#include <iostream>
#include <stdlib.h>
using namespace std;
#define SIZE_N 5
#define SIZE_K 0
/*
combination 通用函数
使用方法:
1. 调用combination(int n, int k, pbcb_callback_T f)。这个里面需要传入使用者自己的回调函数。
2. 回调函数处理长度为n的char数组。某个元素是0,表示没有选中;1,表示选中。
3. 如果回调函数返回true,告诉combination停止处理,返回true;否则combination会一直处理,直到所有组合都结束,然后返回false。
*/
typedef bool (*pbcb_callback_T)(char *);
/*
f 返回为true以后,才会退出整个循环
*/
bool combination_real(int n,int k,pbcb_callback_T f,char *p,char *pp){
if(k==0){
for(int i=0;i<n;i++)
p[i]=false;
return f(pp);
}else if(n==k){
for(int i=0;i<n;i++){
p[i]=true;
}
return f(pp);
}else{
p[0]=false;
if(!combination_real(n-1,k,f,p+1,pp)){
p[0]=true;
return combination_real(n-1,k-1,f,p+1,pp);
}else{
return true;
}
}
return false;
}
/*
c(n,k)
return: c(n,k)的个数,如果失败,返回0
*/
bool combination(int n, int k, pbcb_callback_T f){
char *p;
bool flag;
if(n<0 || k<0 || k>n)
return false;
p = (char*)malloc(n);
if(!p)
return false;
flag = combination_real(n,k,f,p,p);
free(p);
return flag;
}
int g_perm_n;
int g_perm_k;
char *g_p;
pbcb_callback_T g_perm_user_callback;
bool permunation_real(char *p,int num){
if(num==1 || num==0){
return g_perm_user_callback(g_p);
}else{
for(int i=0;i<num;i++){
char ch=p[0];
p[0]=p[i];
p[i]=ch;
if(permunation_real(p+1,num-1))
return true;
p[i]=p[0];
p[0]=ch;
}
return false;
}
}
bool perm_callback(char *p){
//p数组包含了n个元素,其中k个被选中了
//现在需要对k个被选中的进行排列,排列的结果放到g_p中,
//而g_p中只有k个元素,每个元素的值是表示选中n个数据中的那一个,元素的位置是排列的性质
int index=0;
for(int i=0;i<g_perm_n;i++){
if(p[i])
g_p[index++]=i;
}
return permunation_real(g_p,g_perm_k);
}
/*
permunation 通用函数
使用方法:
1. permunation(int n, int k, pbcb_callback_T f)。这个里面需要传入使用者自己的回调函数。
2. 回调函数处理长度为k的char数组p。如果p[3]=10,那说明数字10处于第4个位置。注意:10的标号是从0开始的。也就是0<=p[i]<n
3. 如果回调函数返回true,告诉permunation停止处理,返回true;否则permunation会一直处理,直到所有组合都结束,然后返回false。
*/
bool permunation(int n, int k, pbcb_callback_T f){
bool flag;
if(n<0 || k<0 || k>n)
return false;
g_p = (char*)malloc(k);
if(!g_p)
return false;
g_perm_n = n;
g_perm_k = k;
g_perm_user_callback = f;
flag = combination(n,k,perm_callback);
free(g_p);
return flag;
}
bool test(char *p){
static int counter=0;
for(int i=0;i<SIZE_K;i++){
cout<<(int)p[i]<<" ";
}
cout<<counter++<<endl;
return false;
}
int main()
{
bool flag = permunation(SIZE_N,SIZE_K,test);
return 0;
}