W Następcy porządek w binarne drzewo poszukiwań

głosy
20

Biorąc węzła w BST, w jaki sposób można znaleźć następną wyższą klucz?

Utwórz 29/03/2011 o 12:25
źródło użytkownik
W innych językach...                            


16 odpowiedzi

głosy
2

Sprawdź tutaj: Inorder następca w binarne drzewo poszukiwań

W drzewo binarne, Inorder następca węzła to kolejny węzeł w Inorder przejście przez drzewo binarne. Inorder następca jest NULL dla ostatniego węzła w Inoorder przechodzenia. W binarne drzewo poszukiwań, Inorder Następca węzła wejściowego może być również określona jako węzeł z najmniejszym kluczem większym niż klucz węzła wejściowego.

Odpowiedział 29/03/2011 o 12:28
źródło użytkownik

głosy
64

Ogólny sposób zależy od tego, czy masz link dominującej w węzłach lub nie.

Jeśli przechowujesz link nadrzędnego

Następnie należy wybrać:

  1. Skrajny lewy dziecko z prawego dziecka, jeśli bieżący węzeł ma prawo dziecka. Jeśli dziecko ma prawo lewy dziecka, prawa dziecka to Inorder następca.
  2. Poruszać się rodzic węzły przodka i kiedy można znaleźć rodzica, którego dziecko jest lewy węzeł jesteś obecnie, rodzic jest następcą Inorder z oryginalnego węzła.

Jeśli masz prawo dziecka, czy to podejście (przypadek 1 powyżej):

Inorder-kiedy-right-dziecko

Jeżeli nie mają prawa dziecka, czy to podejście (przypadek 2 powyżej):

Inorder-kiedy-no-right-dziecko

Jeśli nie przechowywać link nadrzędnego

Następnie należy uruchomić pełne skanowanie drzewa, śledzenie węzłami, zwykle ze stosu, tak, że masz informacje niezbędne do w zasadzie tak samo jak w pierwszym sposobie, że oparła się na link macierzystej.

Odpowiedział 29/03/2011 o 12:47
źródło użytkownik

głosy
2

Oto implementacja bez konieczności powiązania dominujących lub struktur pośrednich (takich jak stos). Ta funkcja w następca zamówienie jest nieco różni się od tego, co najbardziej może być szukasz, ponieważ działa na klucz, w przeciwieństwie do węzła. Również będzie znaleźć następcę klucza, nawet jeśli nie jest obecny w drzewie. Nie jest zbyt trudne do zmiany, jeśli potrzebne do krytyki.

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));
    }
}
}
Odpowiedział 27/04/2012 o 15:47
źródło użytkownik

głosy
2

Z binarne drzewo poszukiwań, algorytm, aby znaleźć następny najwyższy węzeł danego węzła jest w zasadzie znalezienie najniższą węzeł prawego poddrzewa tego węzła.

Algorytm może być tylko po prostu:

  1. Start z prawej dziecka danego węzła (sprawiają, że tymczasowy węzeł bieżący)
  2. Jeśli bieżący węzeł ma lewy dziecko, to jest następny najwyższy węzeł.
  3. Jeśli bieżący węzeł posiada lewy dziecka, sprawiają, że bieżący węzeł.

Powtórz 2 i 3, aż znajdziemy obok najwyższy węzeł.

Odpowiedział 02/11/2012 o 20:13
źródło użytkownik

głosy
4

Kod Pythona do Lasse za odpowiedź :

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
Odpowiedział 12/01/2013 o 23:25
źródło użytkownik

głosy
1

C ++ rozwiązanie zakładając węzły w lewo, w prawo i wskazówki dla rodziców:

Ilustruje to funkcja Node* getNextNodeInOrder(Node), która zwraca następny klucz binarnym drzewie wyszukiwania w zamówienie.

#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;
}

Która drukuje:

1 2 3 4 5 6 7 8 9 10 11

unit tests: 
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Odpowiedział 16/07/2013 o 19:21
źródło użytkownik

głosy
0

Można odczytać dodatkowe informacje tutaj (Rus płuc)

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
Odpowiedział 07/10/2014 o 11:25
źródło użytkownik

głosy
0

Odpowiedzi te wszystkie wydają się zbyt skomplikowane dla mnie. Naprawdę nie trzeba rodzicielskich wskazówek ani żadnych pomocniczych struktur danych, takich jak stos. Wszystko, co musimy zrobić, to przechodzić drzewo z korzenia na zamówienie, należy ustawić flagę jak najszybciej znaleźć węzła docelowego, a następnego węzła w drzewie, które odwiedzimy będzie w kolejności następca węzła. Oto szybki i brudny rutyna pisałem w górę.

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);
}
Odpowiedział 09/12/2014 o 05:29
źródło użytkownik

głosy
1

Jeśli mamy wykonać w celu przechodzenia następnie odwiedzimy lewe poddrzewo, to węzeł główny i wreszcie odpowiedniego poddrzewa dla każdego węzła w drzewie. Wykonywanie w celu przechodzenia da nam klucze binarne drzewo wyszukiwania w porządku rosnącym, więc gdy mówimy do pobierania w kolejności następca węzła należącego do wyszukiwania binarnego drzewa rozumiemy co będzie następny węzeł w kolejności od dany węzeł.

Powiedzmy, że mamy węzła R i chcemy jej w kolejności następca mielibyśmy następujące przypadki.

[1] Korzeń R ma prawo węzeł, więc wszystko co musisz zrobić, to przechodzenie do lewej większości węźle R-> prawo.

[2] Korzeń R ma prawo węzeł, w tym przypadku możemy przechodzić z powrotem na drzewie na linki nadrzędnych aż węzeł R jest lewa dzieckiem swojego rodzica, kiedy to nastąpi mamy Rodzic P jak w kolejności następca ,

[3] Jesteśmy na skrajnym prawym węźle drzewa, w tym przypadku nie ma to na celu następcy.

Implementacja jest oparta na następującej definicji węzła

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);
}
Odpowiedział 10/01/2015 o 20:11
źródło użytkownik

głosy
0

Rozwiązanie JavaScript - Jeżeli dany węzeł ma prawo węzeł, a następnie powrócić najmniejszy węzeł w prawym poddrzewie - Jeśli nie, to są 2 możliwości: - Podany węzeł jest lewa dziecko węzła nadrzędnego. Jeśli tak, to powrót do węzła nadrzędnego. W przeciwnym razie dany węzeł jest prawo dziecka węzła nadrzędnego. Jeśli tak, to powrót właściwej dziecko węzła nadrzędnego

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;
  }
}
Odpowiedział 19/10/2015 o 03:44
źródło użytkownik

głosy
0

Robi to w Javie

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);
    }
}
Odpowiedział 22/11/2016 o 04:58
źródło użytkownik

głosy
0

Możemy podzielić to w 3 przypadkach:

  1. Jeśli węzeł jest rodzicem: W tym przypadku możemy się dowiedzieć, czy ma on prawo węzeł i przechodzić do skrajnej lewej dziecka prawego węzła. W przypadku, gdy prawo węzeł nie ma dzieci, to jest jego prawo węzeł Inorder następca. Jeśli nie ma prawa węzeł musimy przenieść się na drzewo, by znaleźć następcę Inorder.

  2. Jeśli węzeł jest lewa dziecko: W tym przypadku rodzic jest następcą Inorder.

  3. Jeśli węzeł (nazwijmy go X) jest prawo dziecka (jego bezpośrednim rodzicem): My przechodzić w górę drzewa, aż znajdziemy węzeł, którego lewe poddrzewo ma x.

Skrajny przypadek: Jeśli węzeł jest skrajna węzeł narożny, nie ma Inorder następca.

Odpowiedział 30/11/2016 o 10:12
źródło użytkownik

głosy
0

Każdy „samouczek” że sprawdziłem na google i wszystkich odpowiedzi w tym wątku używa następującej logiki: " Jeśli węzeł nie ma prawa dziecka, to jego następca zamówienie będzie jednym z jego przodków Korzystanie Link rodzic zachować aż do podróżowania. masz węzeł, który jest lewym dzieckiem swojego rodzica. Wtedy ten węzeł nadrzędny będzie następca zamówienie. "

To jest taka sama jak myślenie „ czy mój rodzic jest większy ode mnie, to jestem lewa dziecko ” (właściwość wyszukiwania binarnego drzewa). Oznacza to, że można po prostu iść w górę łańcucha nadrzędnego aż powyżej właściwość ma wartość true. Który w moich wynikach opinii w bardziej elegancki kodu.

Chyba każdy powód jest sprawdzenie „ jestem w lewo dziecko ”, patrząc na oddziałach zamiast wartości w ścieżce kodu, który wykorzystuje łącza nadrzędne pochodzi od „kredytu” logiki od algorytmu no-link-to-rodzica.

Również z dołączonego kodu poniżej widzimy tam jest nie potrzeba struktury danych stosu sugerowane przez innych odpowiedzi.

Poniżej znajduje się prosta funkcja C ++, który pracuje dla obu przypadków użycia (bez iz wykorzystaniem łącza do rodzica).

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;
    }
}
Odpowiedział 01/01/2017 o 13:11
źródło użytkownik

głosy
0

C # implementacja (Non rekurencyjne!), Aby znaleźć „Next” węzła danego węzła w drzewie binarnym wyszukiwania, gdzie każdy węzeł ma link do jego rodzica.

    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);
    }
Odpowiedział 16/03/2017 o 07:15
źródło użytkownik

głosy
0

Możemy znaleźć następcę O (log n) bez stosowania wskaźniki nadrzędne (dla zrównoważonego drzewa).

Pomysł jest bardzo podobny do tego, kiedy masz wskazówek rodzicielskich.

Możemy zdefiniować rekurencyjną funkcję, która osiąga to w następujący sposób:

  • Jeśli bieżący węzeł jest celem, powrót lewy-większość / najmniejszy węzeł jej prawym poddrzewie, jeśli istnieje.
  • Recurse lewo, jeśli cel jest mniejszy niż bieżącego węzła i prawo, czy to większa.
  • Jeśli cel jest po lewej stronie, a my nie znaleźli jeszcze następcy, powrót bieżącego węzła.

Pseudo kod:

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

Żyć demo Java .

Odpowiedział 31/12/2017 o 16:10
źródło użytkownik

głosy
1

my nie potrzebują łącza nadrzędnego lub stos, aby znaleźć się w porządku następcy w czasie O (log n) (przy założeniu zrównoważonego drzewa). Zachować zmienną tymczasową z ostatniej wartości napotkane podczas przechodzenia Inorder, który jest większy niż klucza. jeśli Inorder przejścia stwierdza, że ​​węzeł nie ma prawa dziecka, to będzie następca Inorder. indziej, skrajny lewy potomek prawej dziecka.

Odpowiedział 03/07/2018 o 20:07
źródło użytkownik

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