【问题标题】:Check if binary tree is complete - haskell检查二叉树是否完整 - haskell
【发布时间】:2021-12-25 14:48:51
【问题描述】:

我有一棵二叉树:

data Btree a = Leaf a | Unary (Btree a) a | Binary (Btree a) a (Btree a) deriving Show

以及一些可以使用的示例:

ex1 = Binary (Binary (Leaf 0) 1 (Leaf 2)) 3 (Unary (Leaf 4) 5)
ex2 = Binary (Unary (Leaf 1) 2) 3 (Binary (Leaf 4) 5 (Leaf 10))
ex3 = Binary (Binary (Leaf (0,"a"))(1,"z")(Leaf (2,"x")))(3,"y")(Binary (Leaf (4,"b"))(5,"c")(Leaf (6,"d")))

我需要确定树是否完整,如果根与任何叶子之间的距离始终相同,直到 1,那么一棵树是完整的,所有最深的叶子都位于其他叶子的左侧,并且最多有一个内部节点应位于倒数第二级。

这是我目前所拥有的

complete :: Btree a -> Bool
complete x = fst $ go x where
  go (Leaf _) = (True, 0)
  go (Unary left _) = (leftTrue, 1 + leftCount) where 
    (leftTrue, leftCount) = go left
  go (Binary left _ right) = (leftTrue && rightTrue &&
                            leftCount == rightCount,
                            1 + leftCount + rightCount) where
    (leftTrue, leftCount) = go left
    (rightTrue, rightCount) = go right

ex1 & ex3 应该返回 true,但只有 ex3 是。我相信一元部分是问题所在。

【问题讨论】:

  • 根据定义,Unary 节点是一棵不完整的树,这意味着如果您看到它,您可以提前返回。那时不需要递归。
  • @chepner 我将如何实现它? go (Unary left _) = (True, 0) or (False, 0) 不起作用
  • 抱歉,我把完全二叉树和完全二叉树混淆了。
  • (如果您正在寻找一个 full 二叉树,那么 go (Unary _ _) = (False, 0) 可以工作,其中 0 可以是类型检查的任何值,因为您最终会忽略值。)
  • 破坏你的帖子。

标签: haskell binary-tree


【解决方案1】:

此答案取决于Unary 部分中的代码更改,如下所示:(leftTrue, 1 + leftCount) -> (False, 1 + leftCount)

您的解决方案的主体是go 函数。 函数返回子树 左右子树是否完全平衡,子树有多少节点。 所有深度都相同,就像在 ex3 中一样。 但是如果你没有 2^n-1 个节点和 2^(n-1) 个叶子,就不可能构建那棵树。 在您的问题的描述中,允许表示任何节点数的不平衡很少。 Ex1 满足 ex2 不满足的规则。 Ex3 根据你的定义也是完整的。

在代码下,我对例子做了ASCII艺术。

我的解决方案不计算子树的数量节点。它计算最大和最小深度,因为它允许我揭示树的任何级别的非法不平衡。 布尔值表示子树是否满足完整树的条件。 它检查:

  1. 最多相差一个
  2. 左子树的最小深度大于或等于右树的最大深度。

上面的检查还包含关于倒数第二级的一个一元节点的条件。

你能猜出这个地方属于什么...吗?

data Btree a = Leaf a | Unary (Btree a) a | Binary (Btree a) a (Btree a) deriving Show

ex1 = Binary (Binary (Leaf 0) 1 (Leaf 2)) 3 (Unary (Leaf 4) 5)
ex2 = Binary (Unary (Leaf 1) 2) 3 (Binary (Leaf 4) 5 (Leaf 10))
ex3 = Binary (Binary (Leaf (0,"a"))(1,"z")(Leaf (2,"x")))(3,"y")(Binary (Leaf (4,"b"))(5,"c")(Leaf (6,"d")))

complete :: Btree a -> Bool
complete x = fst $ go x

go :: Btree a -> (Bool,(Int,Int))
go (Leaf _) = (True, (0, 0))
go (Unary left _) = (leftMaxDepth == 0, (1 + leftMaxDepth, 0)) where 
  (leftIs, (leftMaxDepth, leftMinDepth)) = go left
go (Binary left _ right) =
  ( leftIs && rightIs
    ...
    , (1+newMaxDepth
    , 1+newMinDepth )) where
      newMaxDepth = max leftMaxDepth rightMaxDepth
      newMinDepth = min leftMinDepth rightMinDepth
      (leftIs, (leftMaxDepth, leftMinDepth)) = go left
      (rightIs, (rightMaxDepth, rightMinDepth)) = go right

&& leftMinDepth >= rightMaxDepth && newMaxDepth - newMinDepth <= 1

ex1: 是的

      3
     / \
    /   \
   1     5
  / \   /
 0   2 4

深度:[3,3,3,2]

ex2: 错误

      3
     / \
    /   \
   2     5
  /     / \
 1     4   10

深度:[3,2,3,3]

ex3: 是的

             (3,"y")
             /     \
           /         \
    (1,"z")          (5,"c")
    /    \            /    \ 
(0,"a")  (2,"x")  (4,"b")  (6,"d")

深度:[3,3,3,3]

【讨论】:

    【解决方案2】:

    此答案取决于Unary 部分中的代码更改,如下所示:(leftTrue, 1 + leftCount) -> (False, 1 + leftCount)

    https://web.cecs.pdx.edu/~sheard/course/Cs163/Doc/FullvsComplete.html

    全二进制 rtee:

    完全二叉树:

    您的解决方案依赖于完整的二叉树。 你的练习是关于检查二叉树是否完整。 算法很好,但检查leftCount == rightCount 应该更改。 满二叉树的最小深度等于最大深度, 并且左子树的节点数与右子树相同。

    在完全二叉树中,情况比较困难: 设完整二叉树的节点数为x,则 x = 2^m-1+n,其中 m 是树的最小深度并且 0

    1. 如果左右子树的最小深度相同,则右子树一定是满的。
    2. 如果左子树的最小深度等于右子树的最小深度加一,则左子树一定是满的。
    getMinDepthAndRest :: Int -> (Int,Int)
    getMinDepthAndRest x = getMinDepthandRest' x 0
    
    
    getMinDepthAndRest' :: Int -> Int -> (Int,Int)
    getMinDepthAndRest' x m'
      | x < 2^m'-1 = (m'-1,x-2^(m'-1)+1)
      | otherwise   = getMinDepthandRest' x (m'+1)
                    
    complete :: Btree a -> Bool
    complete x = fst $ go x where
      go (Leaf _) = (True, 1)
      go (Unary left _) = (leftCount == 1, 1 + leftCount) where 
        (leftTrue, leftCount) = go left
      go (Binary left _ right) = (leftTrue && rightTrue &&
                                (m1==m2 && n2==0) || (m1==m2+1 && n1==0),
                                1 + leftCount + rightCount) where
        (m1,n1) = getMinDepthAndRest leftCount
        (m2,n2) = getMinDepthAndRest rightCount
        (leftTrue, leftCount) = go left
        (rightTrue, rightCount) = go right
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-16
      • 1970-01-01
      • 2015-07-23
      相关资源
      最近更新 更多