2010-07-27 4 views
2

В красно-черном дереве, когда вы вращаетесь, вам нужно знать, кто является родителем определенного узла. Однако узел имеет ссылку только на правый или левый дочерний элемент.Красно-черное дерево - Как найти родителя узла?

Я думал дать переменную экземпляра узла «родительский», но по этой причине я не думаю, что это стоит того, и было бы слишком сложно изменить родительскую ссылку на поворот.

public class Node { 
    private left; 
    private right; 
    private isRed; 
    private parent; //I don't think this is good idea 
} 

Итак, мое решение заключается в том, чтобы написать метод findParent(), который использует поиск, чтобы найти родителя. Мне интересно, есть ли другой способ найти родителя узла?

Мое решение:

образец дерева:

50 
    /\ 
    25 75 

Если вы хотите, чтобы найти родительский узел 25, вы передаете что-то вроде:

Node parent = findParent(Node25.value); 

и возвращает node50.

protected Node findParent(int val) { 
     if(root == null) { 
      return null; 
     } 
     Node current = root; 
     Node parent = current; 
     while(true) { 
      if(current.val == val) { //found 
       return parent; 
      } 
      if(current == null) { //not found 
       return null; 
      } 
      parent = current; 
      if(current.val > val) { //go left 
       current = current.left; 
      } 
      else { //go right 
       current = current.right; 
      } 
     } 
    } 
+1

Возможно, я ошибаюсь, но я считаю, что обычный подход состоит в том, чтобы передать родительский элемент в качестве параметра в стеке вызовов функции вращения. – mikera

+0

Вы должны посмотреть на libavl. Правильный способ - держать предков в стеке при поиске. – user172818

ответ

3

Я думал, чтобы дать узла экземпляра переменной «родителя», но именно по этой причине я не думаю, что это стоит делать так

Имея ваши узлы имеют parent ссылку требует один дополнительный указатель/ссылка на узел. Сравните это с необходимостью пересекать дерево, когда вам нужно знать родителя для данного узла.

Это то компромисс между

  1. Стоимость поддержания дополнительных ссылок, и держать его в актуальном состоянии, когда вы изменить узел.
  2. Вычислительная стоимость и сложность того, чтобы пройти по дереву, чтобы найти родитель данного узла

Я думаю, что выбор между этими двумя вариантами весьма субъективный, но лично я выбрал бы просто следить ссылки parent.

В качестве точки отсчета для вас, java.util.TreeMap реализован в виде красно-черного дерева, которое Entry узлы, которые содержат left, right и parent ссылки.

+0

Я не думаю, что все это субъективно. Если вы собираетесь уйти от дерева R-B вообще, это, вероятно, потому, что вы готовы пожертвовать некоторыми вещами в погоне за более быстрыми операциями. Если вы так хрустели для памяти, почему бы просто не использовать массив? –

+0

Ну, я думаю, что есть некоторые алгоритмы, где вы можете сказать, что компромисс между необходимостью поддерживать структуру данных стоит того, чтобы немного увеличить вычислительную сложность. Лично я не думаю, что это один из них. Я просто хотел избежать широкого ответа. –

1

Определенно лучше хранить родителя, чем искать его. Обновление родительской ссылки не так сложно.

2

Как перемещаться по дереву, чтобы добраться до шарнирного узла можно кэшировать предыдущего родителя или, если вам нужно больше, чем один уровень «отменить» вы можете кэшировать каждый пройденный узел на стеке.

Этот кеш будет переменной, локальной для вашего алгоритма вращения, поэтому для этого не потребуется больше места в дереве или дорогих дополнительных обходах.

0

Использование родительского указателя является необязательным.Если вы откажетесь от родительского указателя, вам придется писать операции вставки/удаления с помощью рекурсии (вызовы рекурсивного метода сохраняют родительскую информацию в стеке) или писать итеративную версию, которая поддерживает собственный стек родителей при движении по дереву.

Очень хорошее описание красно-черных деревьев можно найти здесь

http://adtinfo.org/

Это включает в себя описания ряда реализаций rbtree в том числе и без родительских указателей.

Если вы хотите сэкономить на пространстве (и это вполне справедливо) действительно прекрасное описание реализации rbtree можно найти здесь

http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx

метод, который вы описали для поиска для узла родительский элемент был бы очень неэффективен, если он используется реализациями insert/delete. Используйте указатель или используйте рекурсию.

0

Другое решение, помимо родительских указателей и запроса родителя, состоит в том, чтобы поддерживать стек предков.

Пусть кто-то хочет, чтобы вставить 23 в следующее дерево:

Red Black Tree

Вообще алгоритм вставки является:

  1. Найти узел, где 23 будет, если он находится в дереве

  2. Если 23 уже существует, возврат отказа

  3. Если 23 еще нет, поместите его туда.

  4. Выполняйте процедуру повторной балансировки/раскраски по мере необходимости.

Теперь, чтобы использовать стек подход, вы выделяете стек достаточно большой, чтобы поддержать одного узла на уровень вашего дерева (я думаю, что 2 * Потолок (Log2 (счет)) + 2) должны вы охвачены. Вы даже можете сохранить стек, выделенный для вставки или удаления, и просто очистить его всякий раз, когда вы начинаете вставку.

Итак - Посмотрите на корень. Вставьте его в стек. 23 больше значения в корне, поэтому идите вправо. Теперь нажмите узел узла узла (значение 21) в стек. Если 23 находится в дереве, оно должно находиться справа от текущего узла. Но узел справа от текущего узла является нулевым сигналом. Таким образом, эта нуль-дозорная ссылка должна быть заменена узлом с вашим значением. Родитель - это элемент в верхней части стека (последний раз нажал), дедушка и бабушка в очереди ... и т. Д. Поскольку вы, кажется, учитесь ... Java предоставляет вам интерфейс стека, поэтому вам не понадобятся чтобы создать свой собственный стек, чтобы сделать это. Просто используйте их.

Что касается того, насколько это лучше, чем подход родительского указателя, который мне кажется спорным, я бы опирался на подход родительского указателя для простоты и устранения необходимости поддерживать вспомогательную структуру данных или широко использовать рекурсию. Тем не менее, любой подход лучше, чем запрос родителя текущего узла при применении вашей процедуры повторной балансировки/раскраски.

Смежные вопросы