如何实现最后执行zig操作的splay树,而不是第一个?

Jak*_*kob 6 haskell functional-programming splay-tree

对于我的算法和数据结构类,我的任务是在Haskell中实现一个splay树.我的splay操作算法如下:

  1. 如果要显示的节点是根,则返回未更改的树.
  2. 如果要展开的节点是从根开始的一个级别,则执行zig操作并返回结果树.
  3. 如果要展开的节点是来自根的两个或更多级别,则对从该节点开始的子树展开的结果执行zig-zig或Zig-zag操作,并返回结果树.

根据我老师的说法,这是有效的.然而,维基百科对splay树的描述说zig步骤"将仅作为splay操作的最后一步",而在我的算法中,它是splay操作的第一步.

我想实现一个splay树,它最后执行zig操作而不是第一个,但我不确定如何最好地完成它.在我看来,这样的算法会变得更加复杂,看看在确定是否应该执行zig操作之前,需要如何找到要展开的节点.

我如何在Haskell(或其他一些函数式语言)中实现它?

在这个例子中,我们搜索值4,提示我们将它展开到树的顶部.

我的算法(zig作为第一步)

1             1                   4
 \             \                 /
  2      zig    2    zig-zig    2
   \     -->     \   ------>   / \
    3             4           1   3
     \           /
      4         3

维基百科算法(zig作为最后一步)

1                   1           4
 \                   \         /
  2      zig-zig      4  zig  1
   \     ------>     /   -->   \
    3               3           3
     \             /           /
      4           2           2

两棵树都有效,但它们有不同的结构.我想用函数式语言实现第二个,最好是Haskell.

Mtn*_*ark 4

关键是构建一条到要展开的值的路径,然后从底部重建树,如果可能的话一次两层(以便可以做出 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)
Run Code Online (Sandbox Code Playgroud)

您可以在我的存储库中找到此代码以及可运行的单元测试和快速检查。