Hal Fulton 的《Ruby之道》里面有一个输出幂集的程序。
看了老半天都没看明白,所以加了几条输出,发现了如下规律:
其实它采用的是递归的思想(只不过把递归展开了而已) ,有一半的集合含有某个元素,另一半不含。
为了验证,写了一个递归版本的程序:
不由得感叹:大师的算法学得这么好!
- class Array
- def powerset
- num = 2**size
- ps = Array.new(num, [])
- self.each_index do |i|
- #print "i := #{i}/n"
- a = 2**i
- b = 2**(i+1) - 1
- j = 0
- while j < num-1
- #print "j := #{j}, (#{j+a}..#{j+b})/n"
- for j in j+a..j+b
- ps[j] += [self[i]]
- #print "ps[#{j}] = #{ps[j]}/n"
- end
- #print "j := #{j}/n"
- j += 1
- end
- end
- ps
- end
- end
- x = [1, 2, 3, 4]
- y = x.powerset
- print "{"
- for i in 0 ... y.size-1
- print "{#{y[i].join(", ")}}, "
- end
- print "{#{y[-1].join(", ")}}}/n"
- # y is now:
- # [[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]
- # print {{}, {1}, {2}, {1, 2}, {3}, {1, 3}, {2, 3}, {1, 2, 3}, {4}, {1, 4}, {2, 4}, {1, 2, 4}, {3, 4}, {1, 3, 4}, {2, 3, 4}, {1, 2, 3, 4}}
其实它采用的是递归的思想(只不过把递归展开了而已) ,有一半的集合含有某个元素,另一半不含。
为了验证,写了一个递归版本的程序:
- class Array
- def divide_and_conquer(ps, i, j, level)
- print "level #{level}: (#{i}..#{j})/n"
- if level == 0
- ps[j-1] += [self[0]]
- else
- half = (j - i)/2
- divide_and_conquer(ps, i, i+half, level-1)
- divide_and_conquer(ps, i+half, j, level-1)
- for i in i+half ... j
- ps[i] += [self[level]]
- end
- end
- end
- def powerset
- num = 2**size
- ps = Array.new(num, [])
- self.divide_and_conquer(ps, 0, num, size-1)
- ps
- end
- end
- x = [1, 2, 3, 4]
- y = x.powerset
- for i in 0 ... y.size
- print "#{y[i]}/n"
- end
- print "{"
- for i in 0 ... y.size-1
- print "{#{y[i].join(", ")}}, "
- end
- print "{#{y[-1].join(", ")}}}/n"
- # y is now:
- # [[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]
- # print {{}, {1}, {2}, {1, 2}, {3}, {1, 3}, {2, 3}, {1, 2, 3}, {4}, {1, 4}, {2, 4}, {1, 2, 4}, {3, 4}, {1, 3, 4}, {2, 3, 4}, {1, 2, 3, 4}}
不由得感叹:大师的算法学得这么好!