最近笔试了一个关于组合算法的非递归算法,以前写过递归的算法,http://blog.csdn.net/dremi/archive/2007/12/15/1940723.aspx
但这次要用非递归去实现,在有限的时间里,确实没有想的太周到,只是大概的思想写了一下,可能也有点紧张了。现在再来把它完整的来实现, 包括算法思想:代码
#include
"
stdafx.h
"
#include < iostream >
void print( int a[], int n, int b[])
... {
for(int i = 0; i < n; i++)
std::cout<<b[i]<<" ";
std::cout<<" -------> ";
for(int i = 0; i < n; i++)
if(b[i])
std::cout<<a[i]<<" ";
std::cout<<" ";
}
/**/ //
// 非递归实现从a数组(n个)中选取m个的组合排列
// int b[]: 中的b[i] = 1是表示a[i]选上,否则表示没有选上
// 算法的思想:
// 利用n个0,1来表示一种组合排列。像n = 5, m = 3,则
// 排列可以为:
/**/ /*
111<-00
1101<-0
11<-001
1011<-0
101<-01
1<-0011
0111<-0
011<-01
01<-011
00111
其中"<-"表示箭头右边的0和左边的1交换,还要把从这个交换位置(即0的位置)起右边所有的1都放在一起,
并且紧跟在此位置后面,然后在是其它的0,如下面变换:
11001--->10110
首先找到那个交换点:
11001---->10101------->10 110
^ ^^
交换点 交换后 把交换点后面的1都紧放在它的后面去
*/
/**/ //
void combine( int a[], int n, int m, int b[] )
... {
int cnt = 0; //记录交换点1的个数
int index ; //记录交换点的位置
int i;
//初始化b[] = {0}
memset(b, 0, sizeof(int)*n);
//让前m个b[]为1
for(i = 0; i < m; i++) b[i] = 1;
print(a, n, b);
do
...{
cnt = 0;
for(index = n - 1; index > 0; index--)
...{
if(b[index] == 0 && b[index-1] == 1) // 扫描到"10"
break;
if(1 == b[index] ) cnt++; //统计1的个数
}
if(index > 0)
...{
int t = b[index];
b[index] = b[index - 1];
b[index - 1] = t;
//右边cnt个"1"紧跟其后
for( i = 1; i <= cnt; i++)
b[i + index] = 1;
for(i = i + index; i < n; i++) b[i] = 0;//再把cnt个"1"后面加上"0"
print(a, n, b);
}
//当从右向左扫描,index <= 0表示0已经都转到左边去了,应该退出
}while(index > 0);
}
int _tmain( int argc, _TCHAR * argv[])
... {
int a[] = ...{1, 2, 3, 4, 5, 6};
int b[10];
combine(a, 6, 3, b);
system("pause");
return 0;
}
#include < iostream >
void print( int a[], int n, int b[])
... {
for(int i = 0; i < n; i++)
std::cout<<b[i]<<" ";
std::cout<<" -------> ";
for(int i = 0; i < n; i++)
if(b[i])
std::cout<<a[i]<<" ";
std::cout<<" ";
}
/**/ //
// 非递归实现从a数组(n个)中选取m个的组合排列
// int b[]: 中的b[i] = 1是表示a[i]选上,否则表示没有选上
// 算法的思想:
// 利用n个0,1来表示一种组合排列。像n = 5, m = 3,则
// 排列可以为:
/**/ /*
111<-00
1101<-0
11<-001
1011<-0
101<-01
1<-0011
0111<-0
011<-01
01<-011
00111
其中"<-"表示箭头右边的0和左边的1交换,还要把从这个交换位置(即0的位置)起右边所有的1都放在一起,
并且紧跟在此位置后面,然后在是其它的0,如下面变换:
11001--->10110
首先找到那个交换点:
11001---->10101------->10 110
^ ^^
交换点 交换后 把交换点后面的1都紧放在它的后面去
*/
/**/ //
void combine( int a[], int n, int m, int b[] )
... {
int cnt = 0; //记录交换点1的个数
int index ; //记录交换点的位置
int i;
//初始化b[] = {0}
memset(b, 0, sizeof(int)*n);
//让前m个b[]为1
for(i = 0; i < m; i++) b[i] = 1;
print(a, n, b);
do
...{
cnt = 0;
for(index = n - 1; index > 0; index--)
...{
if(b[index] == 0 && b[index-1] == 1) // 扫描到"10"
break;
if(1 == b[index] ) cnt++; //统计1的个数
}
if(index > 0)
...{
int t = b[index];
b[index] = b[index - 1];
b[index - 1] = t;
//右边cnt个"1"紧跟其后
for( i = 1; i <= cnt; i++)
b[i + index] = 1;
for(i = i + index; i < n; i++) b[i] = 0;//再把cnt个"1"后面加上"0"
print(a, n, b);
}
//当从右向左扫描,index <= 0表示0已经都转到左边去了,应该退出
}while(index > 0);
}
int _tmain( int argc, _TCHAR * argv[])
... {
int a[] = ...{1, 2, 3, 4, 5, 6};
int b[10];
combine(a, 6, 3, b);
system("pause");
return 0;
}
测试结果如下: