在Java,Python等中生成一个集合的powerset有很多例子implementations,但我仍然无法理解实际算法是如何工作的。
算法生成集S的幂集P(S)的步骤是什么?
(例如,{1,2,3,4}的幂集为{{},{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}}。)
UPD:我发现了this解释,但我仍然没有得到它。我试图理解生成功率集的算法,因为我想编写它的并行实现 - 以下顺序Erlang实现具有巨大的堆栈,并且不能计算在8 GB的机器上设置的超过30个元素RAM:powerset(Lst) ->
N = length(Lst),
Max = trunc(math:pow(2,N)),
[[lists:nth(Pos+1,Lst) || Pos <- lists:seq(0,N-1), I band (1 bsl Pos) =/= 0] || I <- lists:seq(0,Max-1)].
UPD2:
此片段返回集合[a,b,c]的所有子集,[a,b,c]除外:
generate_all_subsets([],Full_list,Result) ->
Result;
generate_all_subsets([Element|Rest_of_list],Full_list,Result) ->
Filtered_list = [X || X <- Full_list, X =/= Element],
?DBG("*Current accumulated result: ~w ~n", [Result]),
Result2 = generate_subsets(Element,Filtered_list,[],[]),
?DBG("Generated new result: ~w ~n", [Result2]),
New_result = lists:append(Result,Result2),
?DBG("Got new accumulated result: ~w ~n", [New_result]),
generate_all_subsets(Rest_of_list,Full_list,New_result).
generate_subsets(Main_element,[],Accumulated_list,Result) ->
Result;
generate_subsets(Main_element,[Element|Rest_of_set],Accumulated_list,Result) ->
?DBG("*Generating a subset for ~w ~n", [Main_element]),
New_accumulated_list = lists:flatten([Element|Accumulated_list]),
New_result = [New_accumulated_list|Result],
?DBG("Added ~w to the result: ~w ~n", [New_accumulated_list,New_result]),
generate_subsets(Main_element,Rest_of_set,New_accumulated_list,New_result).
我不确定此代码段是否正确。
答案 0 :(得分:1)
这是非常简单的版本,其性能远远优于rosettacode:
generate([]) -> [[]];
generate([H|T]) -> PT = generate(T),
[ [H|X] || X <- PT ] ++ PT.
如果你想要更好的表现,你可以试试这个:
generate([]) -> [[]];
generate([H|T]) -> PT = generate(T),
generate(H, PT, PT).
generate(_, [], Acc) -> Acc;
generate(X, [H|T], Acc) -> generate(X, T, [[X|H]|Acc]).
但无论如何我怀疑你是否能够构建30个元素集的powerset。根据我的计算,它可能消耗超过16GB。在我的第二版中可能会有一些重复使用列表尾部,但它不会有用。我认为如果你将它作为并行算法实现,你甚至可能无法解决更大问题,因为会有消息复制。