提问人:F. Zer 提问时间:7/28/2023 最后编辑:F. Zer 更新时间:7/29/2023 访问量:95
将排序列表转换为二叉树
Convert a sorted list to a binary tree
问:
我已经对以下树进行了编码:
如
Unir (Unir (Unir Vacio 1 Vacio) 2 Vacio) 5 (Unir Vacio 8 Vacio)
使用以下代数数据类型:
data ABB a = Vacio | Unir (ABB a) a (ABB a)
但是,我定义了以下函数:
list2ABB :: Ord a => [a] -> ABB a
list2ABB [] = Vacio
list2ABB (x:xs) = insertABB x (list2ABB xs)
当我执行时:
list2ABB [1,2,5,8]
我得到不同的结果:
Unir (Unir (Unir (Unir Vacio 1 Vacio) 2 Vacio) 5 Vacio) 8 Vacio
我的定义或编码有问题吗?
编辑:
谢谢大家的回答。在回答其中一个查询时,我发布了我对以下方面的定义:insertABB
insertABB :: Ord a => a -> ABB a -> ABB a
insertABB x Vacio = Unir Vacio x Vacio
insertABB x (Unir ti y td)
| x < y = Unir (insertABB x ti) y td
| x > y = Unir ti y (insertABB x td)
| otherwise = Unir ti y td
答:
1赞
willeM_ Van Onsem
7/28/2023
#1
您的函数每次都会在不平衡的情况下定位项目的插入方式。insertABB
由于列表是排序的,并且您以类似的方式插入它,因此它将从右到左插入项目。因此,它将从一棵空树开始,然后插入最右边的元素。这意味着根元素将是列表中最大的项。foldr
接下来,我们插入一个小于根元素的元素,因此它将是根树左子树的根元素。接下来又是一个较小的元素,即根的左子树的左子树。
如果该过程完成,这意味着所有节点的所有正确子树都将为空,并且数据将以类似链接列表的方式插入。
如果你想生成一个平衡树,你可以使用一个平衡树,比如一个 AVL 树 [wiki]。
由于列表已经排序,我们可以构建一个完整的树。为此,我们首先将项目定位在列表的中间,将其作为根元素,然后将子列表作为子树插入。
例如,我们可以用兔子和的方法工作:
hareTortoise :: [a] -> ([a], [a])
hareTortoise xs = go xs xs
where
go [] ts = ([], ts)
go [_] ~(t : ts) = ([t], ts)
go (_ : _ : hs) ~(t : ts) = let ~(ya, yb) = go hs ts in (t : ya, yb)
然后,我们可以使用它来构造树:
constructSorted :: [a] -> ABB a
constructSorted [] = Vacio
constructSorted [x] = Unir Vacio x Vacio
constructSorted xs = let ~(ls, ~(r:rs)) = hareTortoise xs in Unir (constructSorted ls) r (constructSorted rs)
评论
1赞
F. Zer
7/28/2023
惊人的解释。非常感谢。
0赞
F. Zer
7/28/2023
我遵循了你上一段中的最后一个建议:haskell list2ABB' :: [a] -> ABB a list2ABB' [] = Vacio list2ABB' xs = Unir (list2ABB' ys) z (list2ABB' zs) where n = length xs `div` 2 m = xs !! n (ys, z:zs) = splitAt n xs
0赞
F. Zer
7/28/2023
这对你有意义吗?我正在尝试在数据声明之后构建一个完整的树。ABB a
0赞
Chris
7/29/2023
注释对 Haskell 代码来说是一个糟糕的地方,因为它是对空格敏感的。
0赞
F. Zer
7/30/2023
谢谢你的野兔和方法。什么意思?~
评论
insertABB
Vacio
insertABB