document.write('
根据数学性质分析,不难得知,子集个数Sn与原集合元素个数n之间的关系满足如下等式:Sn=2^n-1。
方法一:位图法
具体步骤如下所示。
(1)构造一个和集合一样大小的数组A,分别与集合中的某个元素对应,数组A中的元素只有两种状态:“1”和“0”,分别代表每次
子集输出中集合中对应元素是否要输出,这样数组A可以看作是原集合的一个标记位图。
(2)数组A模拟整数“加1”的操作,每执行“加1”操作之后,就将原集合中所有与数组A中值为“1”的相对应的元素输出。
设原集合为<a,b,c,d>,数组A的某次“加1”后的状态为[1,0,1,1],则本次输出的子集为<a,c,d>。使用非递归的思想,如果有一个
数组,大小为n,那么就使用n位的二进制,如果对应的位为1,那么就输出这个位,如果对应的位为0,那么就不输出这个位。
例如集合{a,b,c}的所有子集可表示如下:
算法的重点是模拟数组加1的操作。数组可以一直加1,直到数组内所有元素都是1。实现代码如下:
def getAllSubset(array,mask,c):
length=len(array)
if length==c:
print "{",
i=0
while i<length:
if mask[i]==1:
print array[i],
i+=1
print "}"
else:
mask[c]=1
getAllSubset(array, mask, c+1)
mask[c]=0
getAllSubset(array, mask, c+1)
if __name__="__main__":
array=[\'a,\'b\',\'c\']
mask=[0,0.0]
getAllSubset(array, mask, 0)
程序的运行结果为:
{abc}
{ab}
{ac}
{a}
{bc}
{b}
{c}
该方法的缺点在于如果数组中有重复数时,这种方法将会得到重复的子集。
算法性能分析:
这种方法的时间复杂度为O(N*2N),空间复杂度O(N)。
方法二、迭代法
采用迭代算法的具体过程如下:
假设原始集合s=<a,b,c,d>,子集结果为r:
第一次迭代:
r=<a>
第二次迭代:
r=<a ab b>
第三次迭代:
r=<a ab b ac abc bc c>
第四次迭代:
r=<a ab b ac abc bc c ad abd bd acd abcd bcd cd d>
每次迭代,都是上一次迭代的结果+上次迭代结果中每个元素都加上当前迭代的元素+当前迭代的元素。
实现代码如下:
def getAllSubset(str):
if str==None or len(str)<1:
print "参数不合理"
return None
arr=[]
arr.append(str[0:1])
i=1
while i<len(str):
lens=len(arr)
j=0
while j<lens:
arr.append(arr[j]+str[i])
j+=1
arr.append(str[i:i+1])
i+=1
return arr
if __name__=="__main__":
result=getAllSubset("abc")
i=0
while i<len(result):
print result[i]
i+=1
程序的运行结果为:
a
ab
b
ac
abc
bc
c
根据上述过程可知,第k次迭代的迭代次数为:2k
-1。需要注意的是,n≥k≥1,迭代n次,总的遍历次数为:2n+1-(2+n),n≥1,所
以,本方法的时间复杂度为O(2n)。
由于在该算法中,下一次迭代过程都需要上一次迭代的结果,而最后一次迭代之后就没有下一次了。因此,假设原始集合有n个元素,
则在迭代过程中,总共需要保存的子集个数为2n-1-1,n≥1。但需要注意的是,这里只考虑了子集的个数,每个子集元素的长度都被视
为1。
其实,比较上述两种方法,不难发现,第一种方法可以看作是用时间换空间,而第二种方法可以看作是用空间换时间。
');