提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
关于刷haskell题目对于tree的整理。
以下代码来自:WIKI99
1 基本数据结构
data Tree a = Empty | Branch a (Tree a) (Tree a)
deriving (Show, Eq)
leaf x = Branch x Empty Empty
1.1 例子
-- A binary tree consisting of a root node only
tree2 = Branch 'a' Empty Empty
-- An empty binary tree
tree3 = Empty
-- A tree of integers
tree4 = Branch 1 (Branch 2 Empty (Branch 4 Empty Empty))
(Branch 2 Empty Empty)
2 一些题目
2.1 Construct completely balanced binary trees
要求构成平衡二叉树 :
平衡:左边和右边的差距最大为1
二叉树:一个Branch只有两个sub tree
λ> cbalTree 4
[
-- permutation 1
-- x
-- / \
-- x x
-- \
-- x
Branch 'x' (Branch 'x' Empty Empty)
(Branch 'x' Empty
(Branch 'x' Empty Empty)),
-- permutation 2
-- x
-- / \
-- x x
-- /
-- x
Branch 'x' (Branch 'x' Empty Empty)
(Branch 'x' (Branch 'x' Empty Empty)
Empty),
-- permutation 3
-- x
-- / \
-- x x
-- \
-- x
Branch 'x' (Branch 'x' Empty
(Branch 'x' Empty Empty))
(Branch 'x' Empty Empty),
-- permutation 4
-- x
-- / \
-- x x
-- /
-- x
Branch 'x' (Branch 'x' (Branch 'x' Empty Empty)
Empty)
(Branch 'x' Empty Empty)
]
Answer 1:
cbalTree 0 = [Empty]
cbalTree 1 = [leaf 'x']
cbalTree n = if n `mod` 2 == 1 then
[ Branch 'x' l r | l <- cbalTree ((n - 1) `div` 2),
r <- cbalTree ((n - 1) `div` 2) ]
else
concat [ [Branch 'x' l r, Branch 'x' r l] | l <- cbalTree ((n - 1) `div` 2),
r <- cbalTree (n `div` 2) ]
- 要注意最后得到的是一个tree list
- list comprehension 去罗列所有可能的tree
- 只有两种情况 : 完全balence ; 不完全balence
- concat 使用注意去掉一层括号
Answer 2:
这个答案很具有参考性,更加具有普遍性
可以用于其他场景: 左树比右树高2;3;4…
main = putStrLn $ concatMap (\t -> show t ++ "\n") balTrees
where balTrees = filter isBalancedTree (makeTrees 'x' 4)
isBalancedTree :: Tree a -> Bool
isBalancedTree Empty = True
isBalancedTree (Branch _ l r) = abs (countBranches l - countBranches r) <= 1
&& isBalancedTree l && isBalancedTree r
isBalancedTree _ = False
countBranches :: Tree a -> Int
countBranches Empty = 0
countBranches (Branch _ l r) = 1 + countBranches l + countBranches r
-- makes all possible trees filled with the given number of nodes
-- and fill them with the given value
makeTrees :: a -> Int -> [Tree a]
makeTrees _ 0 = []
makeTrees c 1 = [leaf c]
makeTrees c n = lonly ++ ronly ++ landr
where lonly = [Branch c t Empty | t <- smallerTree]
ronly = [Branch c Empty t | t <- smallerTree]
landr = concat [[Branch c l r | l <- fst lrtrees, r <- snd lrtrees] | lrtrees <- treeMinusTwo]
smallerTree = makeTrees c (n-1)
treeMinusTwo = [(makeTrees c num, makeTrees c (n-1-num)) | num <- [0..n-2]]
concat 是在2 个for循环的情况下
弄清循环的分级很重要
总结
- Haskell里的循环要多考虑list comprehension。
- 循环要注意考虑条件的分级, 比如代码中要对同一棵树取fst snd
- 循环分级时需用concat
- 从最基本的树开始分析,一层一层往上照,总归会找出规律,Haskell递归的本质就是,发现规律并表示出来。