在 haskell 中使用 BST 的幂集
Power set using BST in haskell
我已经使用二叉搜索树在 Haskell 中实现了一个 Set 数据类型。我没有使用任何内置功能,也没有导入任何模块。
我设置的数据类型如下:
data Set a = Empty | Node a (Set a) (Set a) deriving(Show)
我已经编写了一个 toList 函数,以及一个使用插入函数的 fromList 函数。
我还使用 bst 在集合上编写了一个 setmap 和一个 setfoldr 函数。
我现在只遇到一个问题:
-- powerset of a set
-- powerset {1,2} => { {}, {1}, {2}, {1,2} }
powerSet :: Set a -> Set (Set a)
我不知道如何使用这种类型签名实现 powerSet。我不知道我需要为此编写什么样的辅助功能。我对如何使用列表执行此操作有一些线索,但不使用二叉搜索树。如果可以,请分享一些有关如何执行此操作的提示。
提前致谢!
幂集是递归定义的。
空集的幂集是包含空集的集合。
P({}) = {{}}
非空集S
的幂集P
是通过首先选择任意元素x
并将其从S
中移除得到S'
.您递归地竞争 S'
的幂集以获得 P'
。然后将 P
构造为
P = P' ∪ { s ∪ {x} | s ∈ P' }
因此,只要定义了union :: Set a -> Set a -> Set a
和remove :: Set a -> a -> Set a
,将上面的定义翻译成powerset :: Set a -> Set (Set a)
.
应该很简单
(我从上面的所有类型签名中省略了假定的 Ord a
约束。)
例如,
P({}) == {{}}
P({1}) == {{}} ∪ {{1}}
== {{}, {1}}
P({1,2}) == {{}, {1}} ∪ {{2}, {1,2}}
== {{}, {1}, {2}, {1,2}}
等等
您提到您已经实现了 toList
。您可以在此处使用它进入列表路线。
就像在您的 previous question 中一样,这需要实现和使用 fromAscendingList
,以纯粹结构化的方式从列表构建树,没有任何比较,假设列表已经按升序排列了。
这种结构构造不涉及任何元素知识; powerset 函数也应如此:
powerSet :: Set a -> Set (Set a)
powerSet = toList >>> powerList >>> map fromAscendingList
>>> fromAscendingList
-- (foo >>> bar >>> baz) x = baz (bar (foo x))
当然,我们需要以保序方式实现 powerList
,才能正常工作:
powerList :: [a] -> [[a]]
powerList = concat . powers
where
powers :: [a] -> [ [[a]]]
powers [] = [ [[]] ]
powers (x:xs) = [ [[]] ] ++
[ map (x:) a ++ b
| (a:b:_) <- tails (powers xs ++ [[]]) ]
-- > powerList [1,2,3]
-- [[], [1],[2],[3], [1,2],[1,3],[2,3], [1,2,3]]
(一个更简单的替代方案以不同的顺序生成子列表:
powerList' :: [a] -> [[a]]
powerList' (x:xs) = [ s | s <- powerList' xs, s <- [s, x:s]]
powerList' [] = [[]]
-- > powerList' [1,2,3]
-- [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
如果我们直接遵循另一个答案中的集合符号伪代码,生成的代码将产生更乱序的子列表——[3]
会在 [2]
之前出现, 以及 [1]
).
之前
您还需要实施 fromsAcendingList
。最简单的方法是创建高度不平衡的列表树。你可以从那开始。然后也许设计一种方法来创建接近平衡的树,这是更可取的。
作为替代方案,将以上所有内容视为可执行规范并重新实现它以直接处理您的 Set
类型值。 mapTree
是微不足道的(并且已经包含在您的 previous question 中);同时访问边缘节点及其后继节点也是可行的。
出于好奇,我还提供了一个首先生成最长子列表的版本,以供比较:
-- shortest first:
powers :: [a] -> [ [[a]]]
powers [] = [ [[]] ]
powers (x:xs) = [ [[]] ] ++
[ map (x:) a ++ b | (a:b:_) <- tails (powers xs ++ [[]]) ]
-- longest first:
rpowers :: [a] -> [ [[a]]]
rpowers [] = [ [[]] ]
rpowers (x:xs) =
[ map (x:) b ++ a | (a:b:_) <- tails ([[]] ++ rpowers xs) ]
++ [ [[]] ]
> powers [1,2,3]
[[[]], [[1],[2],[3]], [[1,2],[1,3],[2,3]], [[1,2,3]]]
> rpowers [1,2,3]
[[[1,2,3]], [[1,2],[1,3],[2,3]], [[1],[2],[3]], [[]]]
我已经使用二叉搜索树在 Haskell 中实现了一个 Set 数据类型。我没有使用任何内置功能,也没有导入任何模块。
我设置的数据类型如下:
data Set a = Empty | Node a (Set a) (Set a) deriving(Show)
我已经编写了一个 toList 函数,以及一个使用插入函数的 fromList 函数。 我还使用 bst 在集合上编写了一个 setmap 和一个 setfoldr 函数。
我现在只遇到一个问题:
-- powerset of a set
-- powerset {1,2} => { {}, {1}, {2}, {1,2} }
powerSet :: Set a -> Set (Set a)
我不知道如何使用这种类型签名实现 powerSet。我不知道我需要为此编写什么样的辅助功能。我对如何使用列表执行此操作有一些线索,但不使用二叉搜索树。如果可以,请分享一些有关如何执行此操作的提示。 提前致谢!
幂集是递归定义的。
空集的幂集是包含空集的集合。
P({}) = {{}}
非空集S
的幂集P
是通过首先选择任意元素x
并将其从S
中移除得到S'
.您递归地竞争 S'
的幂集以获得 P'
。然后将 P
构造为
P = P' ∪ { s ∪ {x} | s ∈ P' }
因此,只要定义了union :: Set a -> Set a -> Set a
和remove :: Set a -> a -> Set a
,将上面的定义翻译成powerset :: Set a -> Set (Set a)
.
(我从上面的所有类型签名中省略了假定的 Ord a
约束。)
例如,
P({}) == {{}}
P({1}) == {{}} ∪ {{1}}
== {{}, {1}}
P({1,2}) == {{}, {1}} ∪ {{2}, {1,2}}
== {{}, {1}, {2}, {1,2}}
等等
您提到您已经实现了 toList
。您可以在此处使用它进入列表路线。
就像在您的 previous question 中一样,这需要实现和使用 fromAscendingList
,以纯粹结构化的方式从列表构建树,没有任何比较,假设列表已经按升序排列了。
这种结构构造不涉及任何元素知识; powerset 函数也应如此:
powerSet :: Set a -> Set (Set a)
powerSet = toList >>> powerList >>> map fromAscendingList
>>> fromAscendingList
-- (foo >>> bar >>> baz) x = baz (bar (foo x))
当然,我们需要以保序方式实现 powerList
,才能正常工作:
powerList :: [a] -> [[a]]
powerList = concat . powers
where
powers :: [a] -> [ [[a]]]
powers [] = [ [[]] ]
powers (x:xs) = [ [[]] ] ++
[ map (x:) a ++ b
| (a:b:_) <- tails (powers xs ++ [[]]) ]
-- > powerList [1,2,3]
-- [[], [1],[2],[3], [1,2],[1,3],[2,3], [1,2,3]]
(一个更简单的替代方案以不同的顺序生成子列表:
powerList' :: [a] -> [[a]]
powerList' (x:xs) = [ s | s <- powerList' xs, s <- [s, x:s]]
powerList' [] = [[]]
-- > powerList' [1,2,3]
-- [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
如果我们直接遵循另一个答案中的集合符号伪代码,生成的代码将产生更乱序的子列表——[3]
会在 [2]
之前出现, 以及 [1]
).
您还需要实施 fromsAcendingList
。最简单的方法是创建高度不平衡的列表树。你可以从那开始。然后也许设计一种方法来创建接近平衡的树,这是更可取的。
作为替代方案,将以上所有内容视为可执行规范并重新实现它以直接处理您的 Set
类型值。 mapTree
是微不足道的(并且已经包含在您的 previous question 中);同时访问边缘节点及其后继节点也是可行的。
出于好奇,我还提供了一个首先生成最长子列表的版本,以供比较:
-- shortest first:
powers :: [a] -> [ [[a]]]
powers [] = [ [[]] ]
powers (x:xs) = [ [[]] ] ++
[ map (x:) a ++ b | (a:b:_) <- tails (powers xs ++ [[]]) ]
-- longest first:
rpowers :: [a] -> [ [[a]]]
rpowers [] = [ [[]] ]
rpowers (x:xs) =
[ map (x:) b ++ a | (a:b:_) <- tails ([[]] ++ rpowers xs) ]
++ [ [[]] ]
> powers [1,2,3]
[[[]], [[1],[2],[3]], [[1,2],[1,3],[2,3]], [[1,2,3]]]
> rpowers [1,2,3]
[[[1,2,3]], [[1,2],[1,3],[2,3]], [[1],[2],[3]], [[]]]