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}的所有子集可表示如下:
\"TIM截图20190815170926.jpg\"
 算法的重点是模拟数组加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。
 其实,比较上述两种方法,不难发现,第一种方法可以看作是用时间换空间,而第二种方法可以看作是用空间换时间。

 

');