2013-04-22 135 views
7

我编写从列表构建平衡二叉树的函数foldTree。 我必须使用foldr,它没问题,我用它,但我让insertInTree函数递归=(现在我只知道这种方式走过树=))。使用foldr构建平衡二叉树

UPDATE:iam不知道函数insertTree:是否正确计算递归的高度? =((在这里需要一些帮助

是否有可能写insertInTree无递归(一些与until/iterate/unfoldr)或使foldTree功能,无需辅助功能=>莫名其妙短

这是我下面的尝试:?

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

foldTree :: [a] -> Tree a 
foldTree = foldr (\x tree -> insertInTree x tree) Leaf 

insertInTree :: a -> Tree a -> Tree a 
insertInTree x Leaf = Node 0 (Leaf) x (Leaf) 
insertInTree x (Node n t1 val t2) = if h1 < h2 
            then Node (h2+1) (insertInTree x t1) val t2 
            else Node (h1+1) t1 val (insertInTree x t2) 
    where h1 = heightTree t1 
     h2 = heightTree t2 

heightTree :: Tree a -> Integer 
heightTree Leaf = 0 
heightTree (Node n t1 val t2) = n 

输出:当两个子树的高度EQU

*Main> foldTree "ABCDEFGHIJ" 
Node 3 (Node 2 (Node 0 Leaf 'B' Leaf) 'G' (Node 1 Leaf 'F' (Node 0 Leaf 'C' Leaf))) 'J' (Node 2 (Node 1 Leaf 'D' (Node 0 Leaf 'A' Leaf)) 'I' (Node 1 Leaf 'H' (Node 0 Leaf 'E' Leaf))) 
*Main> 
+0

你怎么看树手段的高度?你能定义它吗?这与insertInTree计算的结果相符吗? – 2013-04-22 21:56:37

+0

我从我的作业任务中只有这个定义:二叉树的高度**是从根到最深节点的路径的长度。例如,具有单个节点的树的高度为0;具有三个节点,其根具有两个子节点的树的高度为1;等等。哦!这个高度有些不正确计算=(( – 2013-04-22 22:56:11

+0

是从已经排序的列表创建树的任务吗?你的递归'insertInTree'没问题,你可以使'foldTree = foldr insertInTree Leaf'。除了代码审查类型的东西外,你能否澄清你所问的内容? – jberryman 2013-04-23 04:19:23

回答

4

你插入功能是错误的al,因为如果它已经满了,插入到右边的子树中将增加它的高度。我不清楚这种情况是否会出现在您的代码中。

插入一个新元素放入树显然是正确的方法似乎是

insertInTree x (Node n t1 val t2) 
    | h1 < h2 = Node n (insertInTree x t1) val t2 
    | h1 > h2 = Node n t1 val t2n 
    | otherwise = Node (h+1) t1 val t2n 
    where h1 = heightTree t1 
     h2 = heightTree t2 
     t2n = insertInTree x t2 
     h = heightTree t2n  -- might stay the same 

这将创建几乎平衡树(又名AVL树)。但它会将每个新元素推到树的最底部。

编辑:这些树可以很好地看出与

showTree Leaf = "" 
showTree [email protected](Node i _ _ _) = go i n 
    where 
    go _ (Leaf) = "" 
    go i (Node _ l c r) = go (i-1) l ++ 
    replicate (4*fromIntegral i) ' ' ++ show C++ "\n" ++ go (i-1) r 

尝试

putStr。 showTree $ foldTree“ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890”

是的,你可以写foldTree较短,如

foldTree = foldr insertInTree Leaf 
2

只是想指出的是,公认的答案是好的,但具有一定高度后3平衡将无法正常工作二叉树,因为它没有考虑到插入后左树可能比右边低的事实。

显然,代码可能已经工作增加额外的条件:

insertInTree x (Node n t1 val t2) 
    | h1 < h2 = Node n  t1n val t2 
    | h1 > h2 = Node n  t1 val t2n 
    | nh1 < nh2 = Node n  t1n val t2 
    | otherwise = Node (nh2+1) t1 val t2n 
    where h1 = heightTree t1 
     h2 = heightTree t2 
     t1n = insertInTree x t1 
     t2n = insertInTree x t2 
     nh1 = heightTree t1n 
     nh2 = heightTree t2n 
+0

不,接受的答案采取所有可能性考虑到,并按照广告的方式工作。它创建的树使得对于树中的每个节点,节点的两个分支的深度相差至多1,也就是AVL树。我可以找到3以上的深度没有问题。我用新功能编辑了答案,以可视化的树状方式显示这些树,并提供了一个建议的测试。 – 2016-08-16 18:28:53

+0

只是用你的功能试了一下;对于我的答案中显示的测试用例,我的函数创建了深度为7的树;你确实创造了更加平衡的树,深度为6;代价更复杂。 – 2016-08-16 18:40:18