data AVL t = Empty | Node t (AVL t) (AVL t) Int
deriving (Eq, Ord, Show)
insertNode :: (Ord a) => a -> AVL a -> AVL a
insertNode x Empty = Node x Empty Empty 0
insertNode x (Node n left right balanceFactor)
| x < n = let leftNode = insertNode x left
in
balanceTree (Node n leftNode right ((treeHeight leftNode) - (treeHeight right)))
| otherwise = let rightNode = insertNode x right
in
balanceTree (Node n left rightNode ((treeHeight left) - (treeHeight rightNode)))
findNode :: AVL a -> a
findNode Empty = error "findNode from Empty"
findNode (Node a _ _ _) = a
findLeftNode :: AVL a -> AVL a
findLeftNode Empty = error "findLeftNode from Empty"
findLeftNode (Node _ left _ _) = left
findRightNode :: AVL a -> AVL a
findRightNode Empty = error "findRightNode from Empty"
findRightNode (Node _ _ right _) = right
findBalanceFactor :: AVL a -> Int
findBalanceFactor Empty = 0
findBalanceFactor (Node _ _ _ bf) = bf
treeHeight :: AVL a -> Int
treeHeight Empty = 0
treeHeight (Node _ left right _) = 1 + (max (treeHeight left) (treeHeight right))
balanceTree :: AVL a -> AVL a
balanceTree Empty = Empty
balanceTree (Node r Empty Empty bf) = Node r Empty Empty bf
balanceTree (Node r left right bf)
| bf == -2 && rbf == -1 = let rl = (findLeftNode right)
in
(Node (findNode right) -- This is for the
(Node r left rl ((treeHeight left) - (treeHeight rl))) -- "right right" case
(findRightNode right)
((1 + (max (treeHeight left) (treeHeight rl))) - (treeHeight (findRightNode right)))
)
| bf == -2 && rbf == 1 = let rl = findLeftNode right
rr = findRightNode right
in
(Node (findNode (rl)) -- This is for the
(Node r left (findLeftNode rl) ((treeHeight left) - (treeHeight (findLeftNode rl)))) -- "right left" case
(Node (findNode right) (findRightNode rl) rr ((treeHeight (findRightNode rl)) - (treeHeight rr)))
((max (treeHeight left) (treeHeight (findLeftNode rl))) - (max (treeHeight (findRightNode rl)) (treeHeight rr)))
)
| bf == 2 && lbf == 1 = let lr = findRightNode left
in
(Node (findNode left) -- This is for the
(findLeftNode left) -- "left left" case
(Node r lr right ((treeHeight lr) - (treeHeight right)))
((treeHeight (findLeftNode left)) - (1 + (max (treeHeight lr) (treeHeight right))))
)
| bf == 2 && lbf == -1 = let lr = findRightNode left
ll = findLeftNode left
in
(Node (findNode lr) -- This is for the
(Node (findNode left) ll (findLeftNode lr) ((treeHeight ll) - (treeHeight (findLeftNode lr)))) -- "left right" case
(Node r (findRightNode lr) right ((treeHeight (findRightNode lr)) - (treeHeight right)))
((max (treeHeight ll) (treeHeight (findLeftNode lr))) - (max (treeHeight(findRightNode lr)) (treeHeight right)))
)
| otherwise = (Node r left right bf)
where rbf = findBalanceFactor right
lbf = findBalanceFactor left
这是我实现AVL树的当前状态。正常输入通常是:
insertNode 4 (Node 2 (Node 1 Empty Empty 0) (Node 3 Empty Empty 0) 0)
导致:
Node 2 (Node 1 Empty Empty 0) (Node 3 Empty (Node 4 Empty Empty 0) (-1)) (-1)
我现在想要一个能够以整洁的方式显示输入树的功能,例如,正上方的树:
2
1
Empty
Empty
3
Empty
4
Empty
Empty
有没有人对如何实施这一点有任何建议?我希望仅显示节点,一旦到达分支的末尾,它就会打印“空”。我碰到了一堵砖墙,尝试了一些尝试但收效甚微。
编辑:大家好,感谢您的快速回复。您的建议确实有效,但是,我希望在不使用包或库的情况下显示树的实现。很抱歉没有澄清这个!答案 0 :(得分:4)
您正在寻找的是一台漂亮的打印机!我总是在Hackage上使用“pretty”包。
Text.PrettyPrint
你的树是一个非常简单的结构,所以我只是一次性定义它。 prettyTree :: Show t => AVL t -> Doc
prettyTree Empty = text "Empty"
prettyTree (Node t l r _) = text (show t)
$+$ nest 1 (prettyTree l)
$+$ nest 1 (prettyTree r)
中有许多有用的组合器,所以请查看它们!它们在GHCi中也很容易使用,所以当你不理解文档时,只需给它一个旋转。
Doc
Show
有一个λ let tree = Node 2 (Node 1 Empty Empty 0) (Node 3 Empty (Node 4 Empty Empty 0) (-1)) (-1)
λ prettyTree (tree :: AVL Int)
2
1
Empty
Empty
3
Empty
4
Empty
Empty
实例,你可能会很好,或者你可以使用更强大的样式函数。
type Doc = [String]
text :: String -> Doc
text = pure
indent :: Doc -> Doc
indent = map (' ':)
vertical :: Doc -> Doc -> Doc
vertical = (++)
prettyTree :: Show t => AVL t -> Doc
prettyTree Empty = text "Empty"
prettyTree (Node t l r _) = vertical (text (show t))
(indent (vertical (prettyTree l)
(prettyTree r)))
render :: Doc -> String
render = concat
如果您想在没有任何外部依赖关系的情况下执行此操作,只需将样式标记为自己的垫片,然后将其放入组合器中。
{{1}}
答案 1 :(得分:0)
您可以首先将AVL树转换为使用Data.Tree库 一个Data.Tree.Tree:
import qualified Data.Tree as T
data AVL t = Empty | Node t (AVL t) (AVL t) Int
deriving (Eq, Ord, Show)
toTree :: Show t => AVL t -> T.Tree String
toTree Empty = T.Node "Empty" []
toTree (Node t left right a)
= T.Node (show t ++ " " ++ show a) [toTree left, toTree right]
avl = Node 2 (Node 1 Empty Empty 0) (Node 3 Empty (Node 4 Empty Empty 0) (-1)) (-1)
test = putStrLn $ T.drawTree (toTree avl)
运行test
打印:
2 -1
|
+- 1 0
| |
| +- Empty
| |
| `- Empty
|
`- 3 -1
|
+- Empty
|
`- 4 0
|
+- Empty
|
`- Empty