对于我的算法& Data Structures类,我的任务是在Haskell中实现一个splay树。我的splay操作算法如下:
根据我老师的说法,这是有效的。但是,the Wikipedia description of a splay tree表示zig步骤“将仅作为展开操作的最后一步”,而在我的算法中,它是展开操作的第一步。
我想实现一个splay树,它最后执行zig操作而不是第一个,但我不确定如何最好地完成它。在我看来,这样的算法会变得更加复杂,看看在确定是否应该执行zig操作之前,需要如何找到要展开的节点。
如何在Haskell(或其他一些函数式语言)中实现它?
在这个例子中,我们搜索值4,提示我们将它展开到树的顶部。
1 1 4 \ \ / 2 zig 2 zig-zig 2 \ --> \ ------> / \ 3 4 1 3 \ / 4 3
1 1 4 \ \ / 2 zig-zig 4 zig 1 \ ------> / --> \ 3 3 3 \ / / 4 2 2
两棵树都有效,但它们的结构不同。我想用函数式语言实现第二个,最好是Haskell。
答案 0 :(得分:3)
关键是要构建一个要显示的值的路径,然后从底部重建树,如果可能,一次重建两个级别(以便可以进行zig-zip与zig-zag的确定):
data Tree a = Empty | Node a (Tree a) (Tree a)
deriving (Eq, Show)
data Direction = LH | RH
deriving (Eq, Show)
splay :: (Ord a) => a -> Tree a -> Tree a
splay a t = rebuild $ path a t [(undefined,t)]
where path a Empty ps = ps
path a n@(Node b l r) ps =
case compare a b of
EQ -> ps
LT -> path a l $ (LH, l) : ps
GT -> path a r $ (RH, r) : ps
rebuild :: (Ord a) => [(Direction,Tree a)] -> Tree a
rebuild ((_,n):[]) = n
rebuild ((LH,x):(_,p):[]) = zigL x p
rebuild ((RH,x):(_,p):[]) = zigR x p
rebuild ((LH,x):(LH,p):(z,g):ps) = rebuild $ (z, zigzigL x p g):ps
rebuild ((RH,x):(RH,p):(z,g):ps) = rebuild $ (z, zigzigR x p g):ps
rebuild ((RH,x):(LH,p):(z,g):ps) = rebuild $ (z, zigzagL x p g):ps
rebuild ((LH,x):(RH,p):(z,g):ps) = rebuild $ (z, zigzagR x p g):ps
zigL (Node x a b) (Node p _ c) = Node x a (Node p b c)
zigR (Node x a b) (Node p c _) = Node x (Node p c a) b
zigzigL (Node x a b) (Node p _ c) (Node g _ d) =
Node x a (Node p b (Node g c d))
zigzigR (Node x a b) (Node p c _) (Node g d _) =
Node x (Node p (Node g d c) a) b
zigzagL (Node x b c) (Node p a _) (Node g _ d) =
Node x (Node p a b) (Node g c d)
zigzagR (Node x b c) (Node p _ a) (Node g d _) =
Node x (Node g d b) (Node p c a)
您可以在我的repo中找到此代码,以及可运行的单元测试和快速检查。
答案 1 :(得分:0)
您确定正确阅读维基百科说明吗?有三种步骤:“zig”,“zig-zig”和“zig-zag”。 “zig”步骤是定义的,只有当x
是根的子节点时才会发生。尽管名称不同,“zig-zig”和“Zig-zag”步骤没有“zig”步骤作为第一个组件。
在我看来,您的实施遵循维基百科在这方面的描述。
答案 2 :(得分:0)
您可以参考this course,其中包含一个非常好的演讲笔记,其中包含OCaml for Splay树中的代码。