В красно-черных деревьях удаление сверху вниз происходит быстрее и эффективнее пространства, чем удаление снизу вверх?

За эту страницу http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx "Удаление сверху вниз" представляет собой реализацию удаления красного дерева node, которое активно балансирует дерево, нажимая красный node вниз по дереву, чтобы лист node, который удаляется, гарантирован быть красным. Поскольку лист node гарантированно будет красным, вам не нужно беспокоиться о повторной балансировке дерева, потому что удаление красного листа node не нарушает никаких правил, и вам не нужно выполнять никаких дополнительных операции по балансировке и восстановлению красно-черного цвета.

"Удаление снизу вверх" включает в себя выполнение нормального двоичного поиска по дереву, чтобы найти node для удаления, заменяя его на лист node (если найденный node не является листом node), а затем восстановление свойств красно-черного дерева путем восхождения на дерево при фиксации красно-черных нарушений правил.

Делает ли удаление сверху вниз минимизацию количества операций повторной балансировки? Возможно ли, что удаление сверху вниз проактивно делает слишком много повторных раскрасок и повторных балансировок на пути вниз?

Как насчет этого сценария: (x) обозначает красный node

               8
         _____/ \____
        /            \
       4              12
     /   \          /    \
   2       6      10      14
  / \     / \    /  \    /  \
 1   3   5   7   9  11  13  15
                             \
                            (16)

Если я хочу удалить 16, удаление снизу вверх не будет выполнять никаких перебалансировок, но удаление сверху вниз переориентирует узлы на все пути вниз, прежде чем обнаруживать, что операции повторного воспроизведения не нужны:

Итерация 1:

              (8)
         _____/ \____
        /            \
       4              12
     /   \          /    \
   2       6      10      14
  / \     / \    /  \    /  \
 1   3   5   7   9  11  13  15
                             \
                            (16)

итерация 2:

               8
         _____/ \____
        /            \
      (4)            (12)
     /   \          /    \
   2       6      10      14
  / \     / \    /  \    /  \
 1   3   5   7   9  11  13  15
                             \
                            (16)

итерация 3:

               8
         _____/ \____
        /            \
      (4)             12
     /   \          /    \
   2       6     (10)    (14)
  / \     / \    /  \    /  \
 1   3   5   7   9  11  13  15
                             \
                            (16)

Затем на итерации 4 вы обнаружите, что вам не нужно толкать, потому что 16 уже краснеет. То есть удаление сверху вниз больше времени и пространства?

Ответы

Ответ 1

Из того, что я собираю: "удаление сверху вниз" позволяет избежать прохождения одного и того же node по пути более одного раза во время операции. Итак, учитывая простой путь от корня до заданного node, если вы все равно сделаете что-то в node, что в этом пути, почему бы просто не сделать это по пути вниз? Это позволяет избежать прохождения по частям пути более одного раза. Поэтому это экономит время.

Аналогичный принцип используется для нескольких операций (включая вставку) на 2-3-4 деревьях (специальный подсезон a, b-деревьев)

Делает ли удаление сверху вниз минимизацию количества операций повторной балансировки?

Думайте, что в среднем случае это так. Поскольку вы делаете это потенциально легче вставлять что-то потом с небольшим количеством операций балансировки.

Возможно ли, что удаление сверху вниз pro-active делает слишком много повторных раскрасок и повторных балансировок по пути вниз?

Возможно, но это зависит от набора данных. Однако, как упоминалось выше. Это может уменьшить количество повторных раскрасок и повторных балансировок.

Ответ 2

Является ли сверху вниз более эффективным пространство, чем снизу вверх?

Одним словом, да. Алгоритм сверху вниз, представленный в вечно confuzzled, не нуждается в указателях родителей на узлах. Алгоритмы Bottom-up представлены с компромиссом между временем и пространством: родительские указатели допускают некоторое короткое замыкание при повторной балансировке после вставки и удаления.

Например, реализация OpenJdk-7 в красно-черных деревьях имеет родительские указатели, что позволяет ему выбирать, будет ли перебалансировка необходимо после удаления (например, в вашем сценарии).

Является ли сверху вниз более эффективным по времени, чем снизу вверх?

В общем, да: подход сверху вниз должен проходить только одно дерево за операцию, тогда как нижний подход должен пересекать дерево дважды за операцию. Как я упоминал ранее, подходы снизу могут сбрить некоторое время, используя указатели-родители. Но определенно не весь обход дерева каждый раз.

Обе реализации также могут использовать threading, чтобы улучшить время или пространство, необходимые для итерации по всему дереву. Для этого требуется накладные расходы на флаг или два на node. Это также может быть достигнуто с помощью указателей родителей, но не так эффективно. NB: ссылка на потоки говорит, что потоковая передача не так эффективна, как родительские указатели, но это относится только к деревьям снизу вверх (которые покрывает книга).

Анекдотические доказательства

Вернувшись в колледж, мы внедрили вечно confuzzled сверху вниз красно-черное дерево на С++ и сделали сравнение с нашей STL (снизу вверх ) реализация std:: map. Наш подход "сверху вниз" был определенно более быстрым: я хочу сказать, что он был легко 2x быстрее на всех мутирующих операциях. Поиск был быстрее, но я не могу сказать, было ли это из-за более сбалансированного дерева или менее сложного кода.

К сожалению, у меня больше нет кода или записи.