In Successore Ordine in Binary Search albero

voti
20

Dato un nodo in un BST, come si fa a trovare la chiave più alto dopo?

È pubblicato 29/03/2011 alle 12:25
fonte dall'utente
In altre lingue...                            


16 risposte

voti
2

Scopri qui: ordine simmetrico Successore in un binario di ricerca albero

In Albero binario, Inorder successore di un nodo è il nodo successivo in ordine simmetrico dell'albero binario. Simmetrico successivo è NULL per l'ultimo nodo Inoorder attraversamento. In Binary Search Albero, Inorder successore di un nodo di ingresso può anche essere definito come il nodo con la più piccola chiave maggiore della chiave del nodo d'ingresso.

Risposto il 29/03/2011 a 12:28
fonte dall'utente

voti
64

Il modo più generale, dipende dal fatto che si dispone di un collegamento genitore nei vostri nodi o meno.

Se si memorizza il collegamento principale

Poi si sceglie:

  1. Il bambino più a sinistra del figlio destro, se il nodo corrente ha un figlio destro. Se il bambino non ha diritto figlio sinistro, il figlio destro è il vostro ordine simmetrico successore.
  2. Navigare i nodi antenato genitore, e quando si trova un genitore il cui figlio sinistro è il nodo che sei attualmente, il genitore è il successore inorder del nodo originale.

Se avete figlio destro, fare questo approccio (sopra il caso 1):

simmetrico-quando-destra-bambino

Se non si dispone di un bambino a destra, fare questo approccio (sopra caso 2):

simmetrico-quando-no-destra-bambino

Se non si memorizza il link genitore

Allora avete bisogno di eseguire una scansione completa della struttura, tenendo traccia dei nodi, di solito con uno stack, in modo da avere le informazioni necessarie per fondamentalmente fare lo stesso come il primo metodo che si basava sul link genitore.

Risposto il 29/03/2011 a 12:47
fonte dall'utente

voti
2

Ecco un'implementazione senza la necessità di collegamenti controllanti o strutture intermedie (come una pila). Questa funzione successore in ordine è un po 'diverso da quello che la maggior parte potrebbe essere alla ricerca di quanto opera sulla chiave in contrapposizione al nodo. Inoltre, sarà trovare un successore di una chiave, anche se non è presente nella struttura. Non troppo difficile da cambiare se è necessario, però.

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));
    }
}
}
Risposto il 27/04/2012 a 15:47
fonte dall'utente

voti
2

Con Binary Search albero, l'algoritmo per trovare il più alto successivo nodo di un dato nodo è fondamentalmente trovando il nodo più basso del diritto sotto-albero di quel nodo.

L'algoritmo può essere solo semplicemente:

  1. Inizia con il figlio destro del nodo data (renderlo nodo corrente temporanea)
  2. Se il nodo corrente non ha figlio sinistro, è il nodo successivo più alto.
  3. Se il nodo corrente ha un figlio sinistro, ne fanno il nodo corrente.

Ripetere 2 e 3 fino a trovare immediatamente superiore nodo.

Risposto il 02/11/2012 a 20:13
fonte dall'utente

voti
4

Codice Python al di Lasse risposta :

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
Risposto il 12/01/2013 a 23:25
fonte dall'utente

voti
1

soluzione C ++ assumendo nodi hanno sinistra, a destra, e puntatori genitore:

Questo illustra la funzione Node* getNextNodeInOrder(Node)che restituisce la chiave successiva del albero binario di ricerca in ordine.

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

Quali stampe:

1 2 3 4 5 6 7 8 9 10 11

unit tests: 
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Risposto il 16/07/2013 a 19:21
fonte dall'utente

voti
0

Potete leggere ulteriori informazioni qui (Rus polmone)

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
Risposto il 07/10/2014 a 11:25
fonte dall'utente

voti
0

Queste risposte sembrano tutti troppo complicato per me. Abbiamo davvero non abbiamo bisogno di puntatori madre o una strutture di dati ausiliari come una pila. Tutto quello che dobbiamo fare è attraversare l'albero dalla radice in ordine, impostare un flag non appena troviamo il nodo di destinazione, e il prossimo nodo nell'albero che visitiamo sarà il nodo in ordine successore. Qui è una routine veloce e sporco che ho scritto su.

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);
}
Risposto il 09/12/2014 a 05:29
fonte dall'utente

voti
1

Se eseguiamo una in ordine di attraversamento poi visitiamo il sottoalbero sinistro, poi nodo radice ed infine il sottoalbero destro per ogni nodo nell'albero. Esecuzione di un in ordine di attraversamento ci darà le chiavi di un albero binario di ricerca in ordine crescente, così quando ci riferiamo a recuperare il in ordine successore di un nodo appartenente ad un albero binario di ricerca intendiamo quello che sarebbe il nodo successivo nella sequenza da il nodo dato.

Diciamo che abbiamo un nodo R e vogliamo la sua in modo successore avremmo il seguenti casi.

[1] La radice R ha un nodo destra, quindi tutto quello che dobbiamo fare è muovere nel nodo più a sinistra di R-> destra.

[2] La radice R ha alcun nodo di destra, in questo caso attraversiamo retrocedere nell'albero seguendo i link e sino alla nodo R è un figlio sinistro del suo genitore, quando questo si verifica abbiamo il nodo padre P come per successore .

[3] Siamo al nodo estrema destra della struttura, in questo caso non v'è in ordine successore.

L'implementazione si basa sulla seguente definizione nodo

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);
}
Risposto il 10/01/2015 a 20:11
fonte dall'utente

voti
0

Soluzione JavaScript - Se il nodo data ha un nodo a destra, per poi tornare il nodo più piccolo del sottoalbero destro - Se no, poi ci sono 2 possibilità: - Il dato nodo è un figlio sinistro del nodo padre. Se è così, restituire il nodo padre. In caso contrario, il nodo data è un figlio destro del nodo genitore. Se è così, restituire il giusto figlio del nodo padre

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;
  }
}
Risposto il 19/10/2015 a 03:44
fonte dall'utente

voti
0

Fare questo in 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);
    }
}
Risposto il 22/11/2016 a 04:58
fonte dall'utente

voti
0

Possiamo dividere questo in 3 casi:

  1. Se il nodo è un genitore: in questo caso troviamo se ha un nodo a destra e attraversare al bambino più a sinistra del nodo destra. Nel caso in cui il nodo destra non ha figli allora il nodo di destra è il suo successore ordine simmetrico. Se non v'è alcun nodo destra abbiamo bisogno di spostare l'albero per trovare il successore ordine simmetrico.

  2. Se il nodo è un figlio sinistro: in questo caso il genitore è il successore ordine simmetrico.

  3. Se il nodo (lo chiamano x) è un figlio destro (del suo genitore immediato): Noi attraversiamo l'albero fino a trovare un nodo il cui sottoalbero sinistro ha x.

Caso estremo: Se il nodo è il nodo più a destra angolo, non v'è alcun successore ordine simmetrico.

Risposto il 30/11/2016 a 10:12
fonte dall'utente

voti
0

Ogni "tutorial" che ho controllato su Google e tutte le risposte a questo thread utilizza la seguente logica: " Se il nodo non ha un bambino a destra e poi il suo successore in-ordine sarà uno dei suoi antenati Utilizzando legame genitore continuare a viaggiare fino. si ottiene il nodo che è il figlio sinistro del suo genitore. Allora questo nodo principale sarà il successore in ordine. "

Questo è lo stesso di pensare " se il mio genitore è più grande di me, allora io sono il figlio sinistro " (proprietà di un albero binario di ricerca). Questo significa che si può semplicemente camminare lungo la catena genitore fino a quando la proprietà di cui sopra è vero. Che a mio parere i risultati in un codice più elegante.

Credo che la ragione per la quale ognuno sta controllando " sono io il bambino lasciato ", cercando in rami al posto dei valori nel percorso di codice che utilizza collegamenti genitore viene dalla logica "prestito" dal algoritmo di no-link-to-genitore.

Anche dal codice riportato qui di seguito possiamo vedere non v'è alcuna necessità di struttura dati dello stack come suggerito da altre risposte.

Di seguito è una semplice funzione C ++ che funziona per entrambi i casi d'uso (con e senza utilizzare il link al genitore).

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;
    }
}
Risposto il 01/01/2017 a 13:11
fonte dall'utente

voti
0

C # implementazione (non ricorsiva!) Per trovare il nodo 'prossimo' di un dato nodo in un albero binario di ricerca in cui ogni nodo ha un link al suo genitore.

    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);
    }
Risposto il 16/03/2017 a 07:15
fonte dall'utente

voti
0

Possiamo trovare il successore in O (log n) senza l'utilizzo di puntatori genitore (per un albero bilanciato).

L'idea è molto simile a quando si hanno i puntatori genitore.

Possiamo definire una funzione ricorsiva che realizza questo come segue:

  • Se il nodo corrente è l'obiettivo, riportare il nodo più a sinistra / più piccolo del suo sottoalbero destro, se esiste.
  • Recurse sinistra se il bersaglio è più piccolo del nodo corrente, ea destra se è maggiore.
  • Se l'obiettivo è quello di sinistra e non abbiamo ancora trovato un successore, restituire il nodo corrente.

Pseudo-codice:

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

Vivere Java demo .

Risposto il 31/12/2017 a 16:10
fonte dall'utente

voti
1

Non abbiamo bisogno legame genitore o pila per trovare il successore al fine di O (log n) (supponendo albero bilanciato). Mantenere una variabile temporanea con il valore più recente incontrato nel attraversamento simmetrico che è più grande della chiave. se ordine simmetrico trova che il nodo non ha un figlio destro, allora questo sarebbe il successore ordine simmetrico. altrimenti, il discendente più a sinistra del figlio destro.

Risposto il 03/07/2018 a 20:07
fonte dall'utente

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