В порядке наследника в бинарном дереве поиска - PullRequest
24 голосов
/ 29 марта 2011

Учитывая узел в BST, как найти следующий более высокий ключ?

Ответы [ 16 ]

0 голосов
/ 01 января 2017

Каждый "учебник", который я проверял в Google и все ответы в этой теме, использует следующую логику: " Если у узла нет правильного потомка, то его преемник по порядку будет одним из его предков. Использованиеродительская ссылка продолжает перемещаться вверх, пока вы не получите узел, который является левым дочерним элементом своего родителя. Тогда этот родительский узел будет преемником по порядку."

Это то же самое, что и думать" если мой родитель больше меня, то я левый ребенок"(свойство бинарного дерева поиска).Это означает, что вы можете просто пройти по родительской цепочке, пока указанное выше свойство не станет истинным.Что, на мой взгляд, приводит к более элегантному коду.

Я думаю, причина, по которой все проверяют " я ли левый ребенок ", просматривая ветви вместо значений в пути кода, которыеиспользует родительские ссылки, полученные из логики «заимствования» из алгоритма no-link-to-parent.

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

Ниже приводится простая функция C ++, которая работает для обоих вариантов использования (с использованием ссылки на родителя и без нее).

Node* nextInOrder(const Node *node, bool useParentLink) const
{
    if (!node)
        return nullptr;

    // when has a right sub-tree
    if (node->right) {
        // get left-most node from the right sub-tree
        node = node->right;
        while (node->left)
            node = node->left;
        return node;
    }

    // when does not have a right sub-tree
    if (useParentLink) {
        Node *parent = node->parent;
        while (parent) {
            if (parent->value > node->value)
                return parent;
            parent = parent->parent;
        }
        return nullptr;
    } else {
        Node *nextInOrder = nullptr;
        // 'root' is a class member pointing to the root of the tree
        Node *current = root;
        while (current != node) {
            if (node->value < current->value) {
                nextInOrder = current;
                current = current->left;
            } else {
                current = current->right;
            }
        }
        return nextInOrder;
    }
}

Node* previousInOrder(const Node *node, bool useParentLink) const
{
    if (!node)
        return nullptr;

    // when has a left sub-tree
    if (node->left) {
        // get right-most node from the left sub-tree
        node = node->left;
        while (node->right)
            node = node->right;
        return node;
    }

    // when does not have a left sub-tree
    if (useParentLink) {
        Node *parent = node->parent;
        while (parent) {
            if (parent->value < node->value)
                return parent;
            parent = parent->parent;
        }
        return nullptr;
    } else {
        Node *prevInOrder = nullptr;
        // 'root' is a class member pointing to the root of the tree
        Node *current = root;
        while (current != node) {
            if (node->value < current->value) {
                current = current->left;
            } else {
                prevInOrder = current;
                current = current->right;
            }
        }
        return prevInOrder;
    }
}
0 голосов
/ 30 ноября 2016

Мы можем разделить это на 3 случая:

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

  2. Если узел является левым дочерним элементом: в этом случае родитель является преемником наследства.

  3. Если узел (назовите его x) является правым потомком (его непосредственного родителя): мы проходим вверх по дереву, пока не найдем узел, у левого поддерева которого есть x.

Крайний случай: если узел является крайним правым угловым узлом, преемника не будет.

0 голосов
/ 22 ноября 2016

Делаем это на Java

TreeNode getSuccessor(TreeNode treeNode) {
    if (treeNode.right != null) {
         return getLeftMostChild(treeNode.right);
    } else {
        TreeNode p = treeNode.parent;
        while (p != null && treeNode == p.right) { // traverse upwards until there is no parent (at the last node of BST and when current treeNode is still the parent's right child
            treeNode = p;
            p = p.parent; // traverse upwards
        }
        return p; // returns the parent node
    }
}

TreeNode getLeftMostChild(TreeNode treeNode) {
    if (treeNode.left == null) {
        return treeNode;
    } else {
        return getLeftMostChild(treeNode.left);
    }
}
0 голосов
/ 19 октября 2015

Решение JavaScript - Если у данного узла есть правый узел, тогда вернуть наименьший узел в правом поддереве. Если нет, то есть 2 возможности: - Данный узел является левым потомком родительского узла.Если это так, верните родительский узел.В противном случае данный узел является правым дочерним узлом родительского узла.Если это так, верните правого потомка родительского узла

function nextNode(node) {
  var nextLargest = null;
  if (node.right != null) {
    // Return the smallest item in the right subtree

    nextLargest = node.right;
    while (nextLargest.left !== null) {
      nextLargest = nextLargest.left;
    }

    return nextLargest;
  } else {
    // Node is the left child of the parent
    if (node === node.parent.left) return node.parent;

    // Node is the right child of the parent
    nextLargest = node.parent;
    while (nextLargest.parent !== null && nextLargest !== nextLargest.parent.left) {
      nextLargest = nextLargest.parent
    }
    return nextLargest.parent;
  }
}
0 голосов
/ 09 декабря 2014

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

Node* FindNextInorderSuccessor(Node* root, int target, bool& done)
{
    if (!root)
        return NULL;

    // go left
    Node* result = FindNextInorderSuccessor(root->left, target, done);
    if (result)
        return result;

    // visit
    if (done)
    {
        // flag is set, this must be our in-order successor node
        return root;
    }
    else
    {
        if (root->value == target)
        {
            // found target node, set flag so that we stop at next node
            done = true;
        }
    }

    // go right
    return FindNextInorderSuccessor(root->right, target, done);
}
0 голосов
/ 07 октября 2014

Вы можете прочитать дополнительную информацию здесь (рус лунг)

Node next(Node x)
   if x.right != null
      return minimum(x.right)
   y = x.parent
   while y != null and x == y.right
      x = y
      y = y.parent
   return y


Node prev(Node x)
   if x.left != null
      return maximum(x.left)
   y = x.parent
   while y != null and x == y.left
      x = y
      y = y.parent
   return y
...