您的位置:首页 > 其它

子集生成算法

2008-03-02 17:02 357 查看
问题: 给定一个正整数,列出{1, 2, ···,n}的所有子集

朋友问我这个问题,一时无法作答,才发现,没有受过系统的计算机专业教育,对于我来讲,是个短板,于是,查看书籍,才在离散数学上找到了子集生成算法的基本介绍。
算法介绍:
若集合S包含n个元素x1, x2, ···, xn, 则用一种简介的表示S的子集的方法是,把它表示成由0和 1组成的串,其中,若xk 属于S,则串中的第K个元素为1,否则为0. 例如,若n = 3, 则8(= 23)个串及其对应的子集如下所示:
000 空集 100 {x1 }
001 {x3} 101 {x1, x3}
010 {x2} 110 {x1, x2}
011 {x2, x3} 111 {x1, x2, x3}
通过这个列表,可以看出如何按照上面的次序来生成这些0-1串:先寻找最右边的0,把它变成1,然后把它右边的所有数字都变成0.

给定一个 正整数n和一个由0-1组成的串a1a2···an,计算下某一个子集所对应的0-1串的算法伪代码如下:
步骤1 (初始化)
K = n
步骤2 (寻找最右边的0)
while(k >= 1且ak=1)
k = k -1
endwhile
步骤3(如果存在0, 则形成后续串)
if(k >= 1)
步骤3.1(把最右边的0变成1)
ak = 1
步骤3.2(把ak右边的所有1变成0)
for j=k+1 to n
aj = 0
Endfor
步骤3.3(输出新子集)
打印
otherwise
步骤3.4(不存在0,也就是没有下一个串)
打印全集
endif

下面是问题的实现代码,C++:

#include <iostream>
using namespace std;

int subset(int *pSet, int *pMask, int nlen)
{
if(pSet == NULL)
return -1;
if(pMask == NULL)
return -1;
int k = nlen;

//找到最右边的0
while(k >= 1)
{
if(pMask[k-1] == 1)
k -= 1;
else
break;
}

//pMask串中找到最右边0位,把它变成1,
//并把它右边的所有数字都变成0;
if(k >= 1)
{
//打印当前的子集
cout << "{ " ;
for(int i=0; i<nlen; i++)
{
if(pMask[i] == 1 )
cout << pSet[i] << " ";
}
cout << "}" << endl;
pMask[k-1] = 1;
for(i= k; i<nlen; i++)
{
pMask[i] = 0;
}

subset(pSet, pMask, nlen);
}
//整个pMask串都为1,找不到0位,
else
{
cout << "{ ";
for(int i=0; i<nlen; i++)
cout << pSet[i] << " ";
cout << " }" << endl;
}

return 0;
}

int main(void)
{
int n;
cout << "Please input the numbr n-> " ;
cin >> n;

int *pSet = new int
;
int *pMask = new int
;
if(pSet == NULL)
return -1;
if(pMask == NULL)
return -1;

for(int i=0; i<n; i++)
pSet[i] = i+1;
for(i=0; i<n; i++)
pMask[i] = 0;

subset(pSet, pMask, n);

if(pSet != NULL)
delete[] pSet;
if(pMask != NULL)
delete[] pMask;

return 0;
}



运行结果如下:
Please input the number n-> 3
{ }
{ 3 }
{ 2 }
{ 2 3 }
{ 1 }
{ 1 3 }
{ 1 2 }
{ 1 2 3 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: