堆是一种树型数据结构,一般组织成二叉树的形式。堆具有这样的属性,对于每一个节点,父节点上的元素大于子孙节点。具体实现可以用链表,也可以用数组。优先队列(Priority Queue)可以用堆来实现。下面介绍一种左倾树(Leftist Tree)的实现方式,参考Algorithms:a functional programming approach.
左倾树首先是堆,具有堆的属性。左倾树的每一个节点除空节点外,具有这些域:数据,距离,左子树,右子树。此处的距离不是指树的深度,而是指节点到达空节点经历的最少节点个数。规定空节点的距离是0。左倾树具有这样的特点,左子树上的距离大于等于右子树上的距离,左倾树的每一个子树都是左倾树。
左倾树一般提供这些操作:取最大值,插入一个元素,删除最大元素,归并(Merge)左倾树。插入一个元素操作,可以通过归并原左倾树和待插入元素构成的独苗来完成。删除最大元素,可以通过移除左倾树的根节点,然后归并左右子树来完成。
左倾树不是平衡树,之所以采用这种不平衡的结构是因为它归并操作比较省时,只需lgn的时间复杂度,比较容易保持堆的属性(对于每一个节点,父节点上的元素大于子孙节点)。左倾树体现了一种不平衡的美。AVL树体现平衡的美。各有各的美。
下面是实现代码:
module LeftistTree where
data (Ord a) => LeftistTree a = EmptyTree
| LeftistTree a Int (LeftistTree a) (LeftistTree a)
treeEmpty EmptyTree = True
treeEmpty _ = False
makeEmptyTree = EmptyTree
distance :: (Ord a)=> LeftistTree a -> Int
distance EmptyTree = 0
distance (LeftistTree elem dist left right) = dist
makeLeftistTree:: (Ord a)=> a -> LeftistTree a -> LeftistTree a -> LeftistTree a
makeLeftistTree elem left right | distance left >= distance right = LeftistTree elem (distance right +1) left right
| otherwise = LeftistTree elem (distance left +1) right left
mergeLeftistTree:: (Ord a)=>LeftistTree a -> LeftistTree a -> LeftistTree a
mergeLeftistTree EmptyTree right = right
mergeLeftistTree left EmptyTree = left
mergeLeftistTree left@(LeftistTree e1 d1 l1 r1) right@(LeftistTree e2 d2 l2 r2)
| e1 >= e2 = makeLeftistTree e1 l1 (mergeLeftistTree r1 right)
| otherwise = makeLeftistTree e2 l2 (mergeLeftistTree left r2)
getMax :: (Ord a ) => LeftistTree a -> a
getMax EmptyTree = error "getMax on empty tree"
getMax (LeftistTree e _ _ _) = e
insertLeftistTree::(Ord a)=>LeftistTree a -> a -> LeftistTree a
insertLeftistTree tree1 a = mergeLeftistTree tree1 (makeLeftistTree a EmptyTree EmptyTree )
removeLeftistTree::(Ord a)=>LeftistTree a -> LeftistTree a
removeLeftistTree EmptyTree = error "remove on empty tree"
removeLeftistTree (LeftistTree _ _ left right) = mergeLeftistTree left right
instance (Show a, Ord a)=> Show (LeftistTree a) where
show tree = showLevel tree 0
where
showLevel EmptyTree level= ""
showLevel (LeftistTree e d l r) level = levelSpaces level ++ show(e)++ ":" ++show(d) ++ "/r/n"
++ showLevel l (level+1)
++ showLevel r (level+1)
levelSpaces level | level==0 = ""
| otherwise = ' ':' ':' ': (levelSpaces ( level -1 ) )
main=test
test = do
let elems = [1,3,5,7,9,2,4,6,8,0]
let tree = makeEmptyTree
let tree1 = foldl insertLeftistTree tree elems
putStrLn "tree1"
print tree1
putStrLn "max1"
print $ getMax tree1
let tree2 = removeLeftistTree tree1
putStrLn "tree2"
print tree2
putStrLn "max2"
print $ getMax tree2
下面是试验结果:
tree1
9:2
8:2
6:1
4:1
2:1
0:1
7:1
5:1
3:1
1:1
max1
9
tree2
8:2
7:2
5:1
3:1
1:1
0:1
6:1
4:1
2:1
max2
8