计算一组所有子集(功率集)

时间:2016-10-19 21:40:26

标签: set ocaml

我正在尝试获取一个函数(作为参数给出一个集合)来返回一个集合,其元素是从主集合形成的所有子集。 例如:{1; 2; 3} - > {{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}}

但是我并不完全知道如何创建一个让我使用一组集合的模块。我应该将它定义为什么类型?

2 个答案:

答案 0 :(得分:5)

一组所有子集称为power set。要实现算法,您实际上并不需要特殊的数据结构,因为您可以使用列表来表示集合。相应地,一组集合将是列表的列表。如,

  

let rec superset = function | [] -> [[]] | x :: xs -> let ps = superset xs in ps @ List.map (fun ss -> x :: ss) ps

以下是一个使用示例:

superset [1;2;3];;
- : int list list = [[]; [1]; [2]; [2; 1]; [3]; [3; 1]; [3; 2]; [3; 2; 1]

如果你想使用真实套装,就像杰弗里建议的那样。然后我们需要稍微调整算法,因为Set模块提供了一点点不同的接口。

  

module S = Set.Make(String)
module SS = Set.Make(S) let superset xs = S.fold (fun x ps -> SS.fold (fun ss -> SS.add (S.add x ss)) ps ps) xs (SS.singleton S.empty)

要运行算法并打印结果,我们需要将其转换回列表,因为OCaml toplevel不知道如何打印集合:

# superset (S.of_list ["1"; "2"; "3"]) |> SS.elements |> List.map S.elements;;
- : S.elt list list =
[[]; ["1"]; ["1"; "2"]; ["1"; "2"; "3"]; ["1"; "3"]; ["2"]; ["2"; "3"];
 ["3"]]

现在,我们可以推广算法,以便它可以在任何有序类型上工作。

  

module Superset(T : Set.OrderedType) = struct module S = Set.Make(T)
module SS = Set.Make(S) let of_set xs = S.fold (fun x ps -> SS.fold (fun ss -> SS.add (S.add x ss)) ps ps) xs (SS.singleton S.empty) end

现在我们可以运行它了:

# module Superset_of_strings = Superset(String);;
# open Superset_of_string;;  
# of_set (S.of_list ["1"; "2"; "3"]) |> SS.elements |> List.map S.elements;;
- : S.elt list list =
[[]; ["1"]; ["1"; "2"]; ["1"; "2"; "3"]; ["1"; "3"]; ["2"]; ["2"; "3"];
 ["3"]]

答案 1 :(得分:1)

如果你想使用标准的Set模块,你可以使用字符串集(比方说)和一组字符串集,如下所示:

# module S = Set.Make(String);;
. . .
# module SS = Set.Make(S);;
. . .

# let s1 = S.singleton "abc";;
val s1 : S.t = <abstr>
# let ss1 = SS.singleton s1;;
val ss1 : SS.t = <abstr>
# List.map S.elements (SS.elements ss1);;
- : S.elt list list = [["abc"]]