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

Ste*_*vie 1 ocaml set

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

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

ivg*_*ivg 6

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

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]
Run Code Online (Sandbox Code Playgroud)

如果你想使用真实的套装,就像杰弗里建议的那样.然后我们需要稍微调整算法,因为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"]]
Run Code Online (Sandbox Code Playgroud)

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

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"]]
Run Code Online (Sandbox Code Playgroud)