В Преемник заказа в бинарном дереве поиска

голоса
20

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

Задан 29/03/2011 в 12:25
источник пользователем
На других языках...                            


16 ответов

голоса
2

Проверьте здесь: заказовМой Преемник в бинарном дереве поиска

В бинарном дереве, Симметричный преемник узла является следующим узлом в заказовМой обходе бинарного дерева. Симметричного Преемник является NULL для последнего узла в Inoorder обходе. В бинарном дереве поиска, Симметричного Преемник входного узла также может быть определен как узел с наименьшим ключом больше, чем ключ узла ввода.

Ответил 29/03/2011 в 12:28
источник пользователем

голоса
64

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

Если вы храните родительскую ссылку

Затем вы выбираете:

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

Если у вас есть правильный ребенок, сделать этот подход (случай 1 выше):

Симметричный-When-правого ребенок

Если вы не имеете права ребенка, делает этот подход (случай 2 выше):

Симметричный-WHEN-не-правого ребенка

Если вы не храните родительскую ссылку

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

Ответил 29/03/2011 в 12:47
источник пользователем

голоса
2

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

public class Node<T extends Comparable<T>> {

private T data;
private Node<T> left;
private Node<T> right;

public Node(T data, Node<T> left, Node<T> right) {
    this.data = data;
    this.left = left;
    this.right = right;
}

/*
 * Returns the left-most node of the current node. If there is no left child, the current node is the left-most.
 */
private Node<T> getLeftMost() {
    Node<T> curr = this;
    while(curr.left != null) curr = curr.left;
    return curr;
}

/*
 * Returns the right-most node of the current node. If there is no right child, the current node is the right-most.
 */
private Node<T> getRightMost() {
    Node<T> curr = this;
    while(curr.right != null) curr = curr.right;
    return curr;
}

/**
 * Returns the in-order successor of the specified key.
 * @param key The key.
 * @return
 */
public T getSuccessor(T key) {
    Node<T> curr = this;
    T successor = null;
    while(curr != null) {
        // If this.data < key, search to the right.
        if(curr.data.compareTo(key) < 0 && curr.right != null) {
            curr = curr.right;
        }
        // If this.data > key, search to the left.
        else if(curr.data.compareTo(key) > 0) { 
            // If the right-most on the left side has bigger than the key, search left.
            if(curr.left != null && curr.left.getRightMost().data.compareTo(key) > 0) {
                curr = curr.left;
            }
            // If there's no left, or the right-most on the left branch is smaller than the key, we're at the successor.
            else {
                successor = curr.data;
                curr = null;
            }
        }
        // this.data == key...
        else {
            // so get the right-most data.
            if(curr.right != null) {
                successor = curr.right.getLeftMost().data;
            }
            // there is no successor.
            else {
                successor = null;
            }
            curr = null;
        }
    }
    return successor;
}

public static void main(String[] args) {
    Node<Integer> one, three, five, seven, two, six, four;
    one = new Node<Integer>(Integer.valueOf(1), null, null);
    three = new Node<Integer>(Integer.valueOf(3), null, null);
    five = new Node<Integer>(Integer.valueOf(5), null, null);
    seven = new Node<Integer>(Integer.valueOf(7), null, null);
    two = new Node<Integer>(Integer.valueOf(2), one, three);
    six = new Node<Integer>(Integer.valueOf(6), five, seven);
    four = new Node<Integer>(Integer.valueOf(4), two, six);
    Node<Integer> head = four;
    for(int i = 0; i <= 7; i++) {
        System.out.println(head.getSuccessor(i));
    }
}
}
Ответил 27/04/2012 в 15:47
источник пользователем

голоса
2

С бинарным деревом поиска, алгоритм, чтобы найти следующий самую высокий узел данного узла, в основном, найти наималейший узел правого поддерева этого узла.

Алгоритм может быть просто просто:

  1. Начните с правым ребенком данного узла (сделать это временный текущий узлом)
  2. Если текущий узел не имеет левого ребенка, это следующий самый высокий узел.
  3. Если текущий узел имеет левый ребенок, сделать его текущий узел.

Повторите 2 и 3, пока мы не найдем следующий самый высокий узел.

Ответил 02/11/2012 в 20:13
источник пользователем

голоса
4

Python код в Лассе в ответ :

def findNext(node):
  if node.rightChild != None:
    return findMostLeft(node.rightChild)
  else:
    parent = node.parent
    while parent != None:
      if parent.leftChild == node:
        break
      node = parent
      parent = node.parent
    return parent
Ответил 12/01/2013 в 23:25
источник пользователем

голоса
1

Решение C ++ при условии, узлы слева, справа, и родительские указатели:

Это иллюстрирует функцию , Node* getNextNodeInOrder(Node)которая возвращает следующий ключ двоичного дерева поиска в заказе.

#include <cstdlib>
#include <iostream>
using namespace std;

struct Node{
    int data;
    Node *parent;
    Node *left, *right;
};

Node *createNode(int data){
    Node *node =  new Node();
    node->data = data;
    node->left = node->right = NULL;
    return node;
}

Node* getFirstRightParent(Node *node){
    if (node->parent == NULL)
        return NULL;

    while (node->parent != NULL && node->parent->left != node){
        node = node->parent;
    }
    return node->parent;
}
Node* getLeftMostRightChild(Node *node){
    node = node->right;
    while (node->left != NULL){
        node = node->left;
    }
    return node;
}
Node *getNextNodeInOrder(Node *node){
    //if you pass in the last Node this will return NULL
    if (node->right != NULL)
        return getLeftMostRightChild(node);
    else
        return getFirstRightParent(node);
}
void inOrderPrint(Node *root)
{
    if (root->left != NULL) inOrderPrint(root->left);
    cout << root->data << " ";
    if (root->right != NULL) inOrderPrint(root->right);
}

int main(int argc, char** argv) {
    //Purpose of this program is to demonstrate the function getNextNodeInOrder
    //of a binary tree in-order.  Below the tree is listed with the order
    //of the items in-order.  1 is the beginning, 11 is the end.  If you 
    //pass in the node 4, getNextNode returns the node for 5, the next in the 
    //sequence.

    //test tree:
    //
    //        4
    //      /    \
    //     2      11
    //    / \     /
    //   1  3    10
    //          /
    //         5
    //          \
    //           6 
    //            \
    //             8
    //            / \
    //           7  9


    Node *root = createNode(4);
    root->parent = NULL;

    root->left = createNode(2);
    root->left->parent = root;

    root->right = createNode(11);
    root->right->parent = root;

    root->left->left = createNode(1);
    root->left->left->parent = root->left;

    root->right->left = createNode(10);
    root->right->left->parent = root->right;

    root->left->right = createNode(3);
    root->left->right->parent = root->left;

    root->right->left->left = createNode(5);
    root->right->left->left->parent = root->right->left;

    root->right->left->left->right = createNode(6);
    root->right->left->left->right->parent = root->right->left->left;

    root->right->left->left->right->right = createNode(8);
    root->right->left->left->right->right->parent = 
            root->right->left->left->right;

    root->right->left->left->right->right->left = createNode(7);
    root->right->left->left->right->right->left->parent = 
            root->right->left->left->right->right;

    root->right->left->left->right->right->right = createNode(9);
    root->right->left->left->right->right->right->parent = 
            root->right->left->left->right->right;

    inOrderPrint(root);

    //UNIT TESTING FOLLOWS

    cout << endl << "unit tests: " << endl;

    if (getNextNodeInOrder(root)->data != 5)
        cout << "failed01" << endl;
    else
        cout << "passed01" << endl;

    if (getNextNodeInOrder(root->right) != NULL)
        cout << "failed02" << endl;
    else
        cout << "passed02" << endl;

    if (getNextNodeInOrder(root->right->left)->data != 11)
        cout << "failed03" << endl;
    else
        cout << "passed03" << endl;

    if (getNextNodeInOrder(root->left)->data != 3)
        cout << "failed04" << endl;
    else
        cout << "passed04" << endl;

    if (getNextNodeInOrder(root->left->left)->data != 2)
        cout << "failed05" << endl;
    else
        cout << "passed05" << endl;

    if (getNextNodeInOrder(root->left->right)->data != 4)
        cout << "failed06" << endl;
    else
        cout << "passed06" << endl;

    if (getNextNodeInOrder(root->right->left->left)->data != 6)
        cout << "failed07" << endl;
    else
        cout << "passed07" << endl;

    if (getNextNodeInOrder(root->right->left->left->right)->data != 7)
        cout << "failed08 it came up with: " << 
          getNextNodeInOrder(root->right->left->left->right)->data << endl;
    else
        cout << "passed08" << endl;

    if (getNextNodeInOrder(root->right->left->left->right->right)->data != 9)
        cout << "failed09 it came up with: " 
          << getNextNodeInOrder(root->right->left->left->right->right)->data 
          << endl;
    else
        cout << "passed09" << endl;

    return 0;
}

Что печатает:

1 2 3 4 5 6 7 8 9 10 11

unit tests: 
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Ответил 16/07/2013 в 19:21
источник пользователем

голоса
0

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

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
Ответил 07/10/2014 в 11:25
источник пользователем

голоса
0

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

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);
}
Ответил 09/12/2014 в 05:29
источник пользователем

голоса
1

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

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

[1] Корень R имеет правый узел, поэтому все , что нам нужно сделать , это пройти к крайнему левому узлу R-> вправо.

[2] Корень R не имеет правильный узла, в этом случае мы пересекаем обратно вверх по дереву следующих родительских ссылок , пока узел R не является левым потомком своего родителя, когда это происходит , мы имеем родительский узел P в качестве в порядке преемнике ,

[3] Мы не в крайнем правом узле дерева, в данном случае не существует в порядке преемника.

Реализация основана на следующем определении узла

class node
{
private:
node* left;
node* right;
node* parent
int data;

public:
//public interface not shown, these are just setters and getters
.......
};

//go up the tree until we have our root node a left child of its parent
node* getParent(node* root)
{
    if(root->parent == NULL)
        return NULL;

    if(root->parent->left == root)
        return root->parent;
    else
        return getParent(root->parent);
}

node* getLeftMostNode(node* root)
{
    if(root == NULL)
        return NULL;

    node* left = getLeftMostNode(root->left);
    if(left)
        return left;
    return root;
}

//return the in order successor if there is one.
//parameters - root, the node whose in order successor we are 'searching' for
node* getInOrderSucc(node* root)
{
    //no tree, therefore no successor
    if(root == NULL)
        return NULL;

    //if we have a right tree, get its left most node
    if(root->right)
        return getLeftMostNode(root->right);
    else
        //bubble up so the root node becomes the left child of its
        //parent, the parent will be the inorder successor.
        return getParent(root);
}
Ответил 10/01/2015 в 20:11
источник пользователем

голоса
0

Решение 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;
  }
}
Ответил 19/10/2015 в 03:44
источник пользователем

голоса
0

Делая это в 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);
    }
}
Ответил 22/11/2016 в 04:58
источник пользователем

голоса
0

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

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

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

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

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

Ответил 30/11/2016 в 10:12
источник пользователем

голоса
0

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

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

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

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

Ниже приводится простая функция 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;
    }
}
Ответил 01/01/2017 в 13:11
источник пользователем

голоса
0

C # реализация (не рекурсивный!), Чтобы найти «следующий» узел данного узла в бинарном дереве поиска, где каждый узел имеет связь с его родителем.

    public static Node WhoIsNextInOrder(Node root, Node node)
    {
        if (node.Right != null)
        {
            return GetLeftMost(node.Right);
        }
        else
        {
            Node p = new Node(null,null,-1);
            Node Next = new Node(null, null, -1);
            bool found = false;
            p = FindParent(root, node);
            while (found == false)
                {
                    if (p.Left == node) { Next = p; return Next; }
                    node = p;
                    p = FindParent(root, node);
                }
            return Next;
        }
    }

    public static Node FindParent(Node root, Node node)
    {
        if (root == null || node == null)
        {
            return null;
        }
        else if ( (root.Right != null && root.Right.Value == node.Value) || (root.Left != null && root.Left.Value == node.Value))
        {
            return root;
        }
        else
        {
            Node found = FindParent(root.Right, node);

            if (found == null)
            {
                found = FindParent(root.Left, node);
            }

            return found;
        }
    }

    public static Node GetLeftMost (Node node)
    {
        if (node.Left == null)
        {
            return node;
        }
        return GetLeftMost(node.Left);
    }
Ответил 16/03/2017 в 07:15
источник пользователем

голоса
0

Мы можем найти преемник в O (журнал N) без использования родительских указателей (для сбалансированного дерева).

Идея очень похожа, когда у вас есть родительские указатели.

Мы можем определить рекурсивную функцию, которая достигает этой цели следующим образом:

  • Если текущий узел является объектом, возвращает самый левый / наименьший узел его правого поддерева, если он существует.
  • Recurse влево, если цель меньше, чем текущий узел, и право, если оно больше.
  • Если цель находится слева, и мы не нашли преемника еще, возвращает текущий узел.

Псевдо-код:

Key successor(Node current, Key target):
   if current == null
      return null
   if target == current.key
      if current.right != null
         return leftMost(current.right).key
      else
         return specialKey
   else
      if target < current.key
         s = successor(current.left, target)
         if s == specialKey
            return current.key
         else
            return s
      else
         return successor(current.right, target)

Node leftMost(Node current):
    while current.left != null
       current = current.left
    return current

Живите Java демо .

Ответил 31/12/2017 в 16:10
источник пользователем

голоса
1

нам не нужно родительское ссылку или стек, чтобы найти в порядке правопреемника в O (журнал N) (при условии, сбалансированное дерево). Держите временную переменную с последним значением, встречающегося в заказовМои обходе, который больше, чем ключ. если Симметричный обход обнаруживает, что узел не имеет правильный ребенок, то это будет Симметричным преемник. еще, крайний левый потомок правого ребенка.

Ответил 03/07/2018 в 20:07
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more