树中最左边的值(Haskell)

Leftmost value in a tree (Haskell)

如何找到树中最左边的值? Leftmost 是通过尽可能长时间地转到当前节点的左子节点所达到的值。

树类型定义为:

1
data Tree a = Leaf | Node a (Tree a) (Tree a) deriving (Show, Eq)

我目前有以下:

1
2
leftest :: Tree a -> Maybe a
leftest (Leaf) = Nothing

leftest 应该返回的示例:

leftest (Node 1 (Node 2 (Node 3 Leaf) Leaf) Leaf)
--> 只需 3

leftest (Node 1 (Node 2 Leaf (Node 3 Leaf)) (Node 4 Leaf Leaf))
--> 只需 2


在你用 Haskell 写一个函数之前,最好先考虑一个关于树中最左边元素的(归纳)定义。

其实你已经写过一部分了:

1
leftest (Leaf) = Nothing

这里你基本上说:"叶子没有最左边的元素"。所以现在的问题是,Tree a (Tree a) (Tree a) 的最左边的值是多少?

我们可以在这里推理几个案例。这里基本上有四种情况:两个子树可以是Leafs 或Tree ...s,对于每一种情况,我们都可以尝试想出一个解决方案:

  • Tree x Leaf Leaf,因此我们有一个没有任何子节点的节点(实际上在大多数有关数据结构的书籍中,就是叶子),在这种情况下,最左边的值是 Tree x Leaf Leaf 携带的值,所以 ,所以我们可以返回Just x
  • Tree x Leaf (Tree _ _ _),这里有一棵树,右边只有一个孩子。由于那个孩子及其所有后代都在右边,因此我们可以再次返回节点的元素,所以 Just x;
  • Tree x (Tree _ _ _) Leaf,这里我们左边只有一个孩子。在这种情况下,这棵树的最左边与左孩子的最左边相同,所以我们在左孩子上递归;和
  • Tree x (Tree _ _ _) (Tree _ _ _),这里节点有两个孩子,但就像我们已经讨论过的,右孩子并不重要,我们可以再次递归左孩子。
  • 所以我们可以写成:

    1
    2
    3
    4
    5
    6
    leftmost :: Tree a -> Maybe a
    leftmost Leaf = Nothing
    leftmost (Tree x Leaf Leaf) = Just x  -- (1)
    leftmost (Tree x Leaf (Tree _ _ _)) = Just x  -- (2)
    leftmost (Tree x c@(Tree _ _ _) Leaf) = leftmost c  -- (3)
    leftmost (Tree x c@(Tree _ _ _) (Tree _ _ _)) = leftmost c  -- (4)

    这确实可行,但比较冗长:既然右孩子不重要,我们为什么要考虑四种情况?我们可以将其限制为两种情况:

    1
    2
    3
    4
    leftmost :: Tree a -> Maybe a
    leftmost Leaf = Nothing
    leftmost (Tree x Leaf _) = Just x  -- (1+2)
    leftmost (Tree x c@(Tree _ _ _) _) = leftmost c  -- (3+4)