Как я могу реализовать дерево splay, которое выполняет операцию zig последним, а не первым?

для моего класса Algorithms & Data Structures мне было поручено реализовать дерево splay в Haskell. Мой алгоритм работы расширения следующий:

  1. если узел, который нужно разложить, является корнем, возвращается неизмененное дерево.
  2. если узел, который нужно развернуть, находится на одном уровне от корня, выполняется операция zig и возвращается результирующее дерево.
  3. если узел, который нужно разложить, находится на двух или более уровнях от корня, Зиг-Зиг или зиг-заг операция выполняется по результату разбиения поддерева, начиная с этого узла, и возвращается результирующее дерево.

это действительно согласно моему учителю. Однако,описание Википедии дерева splay говорит, что шаг zig "будет сделан только как последний шаг в операции splay", тогда как в моем алгоритме это первый шаг в операции splay.

Я хочу реализовать дерево splay, которое выполняет операцию zig last вместо во-первых, но я не знаю, как это лучше сделать. Мне кажется, что такой алгоритм стал бы более сложным, поскольку нужно найти узел, который нужно разложить, прежде чем можно будет определить, следует ли выполнять операцию Зига или нет.

Как я могу реализовать это в 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.

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)

вы можете найти этот код, а также выполняемые модульные тесты и быстрые проверки в my РЕПО.


вы уверены, что правильно читаете описание Википедии? Существует три вида шагов:" Зиг"," Зиг-Зиг "и"зиг-заг". Шаг "Зиг" -определена быть что-то, что происходит только тогда, когда x является дочерним элементом корня. Несмотря на названия, шаги "Зиг-Зиг" и "зиг-заг" не имеют шагов "Зиг" в качестве первого компонента.

Мне кажется, что ваша реализация соответствует описание Википедии в этом отношении.


вы можете ref курс, который имеет очень хорошую лекцию с кодом в OCaml для дерева Splay.