In Opvolger bestellen in binaire zoekboom

stemmen
20

Gegeven een knooppunt in een BST, hoe gaat men de volgende hogere sleutel te vinden?

De vraag is gesteld op 29/03/2011 om 12:25
bron van user
In andere talen...                            


16 antwoorden

stemmen
2

Check hier: Inorder Opvolger in een binaire zoekboom

In Binary Tree, Inorder opvolger van een knooppunt is de volgende knooppunt in Inorder traversal van de Binary Tree. Inorder opvolger is NULL voor het laatste knooppunt in Inoorder doorlopen. In Binary Search Tree, kan Inorder opvolger van een ingang knooppunt ook worden gedefinieerd als het knooppunt met de kleinste sleutel groter is dan de sleutel van de input node.

antwoordde op 29/03/2011 om 12:28
bron van user

stemmen
64

De algemene manier hangt af van de vraag of je een ouder link in uw nodes of niet.

Als u op te slaan de bovenliggende koppeling

Dan kies je:

  1. De meest linkse kind van het recht kind, als uw huidige knooppunt een recht kind. Als het juiste kind heeft geen links kind, rechts kind is uw inorder opvolger.
  2. Navigeer naar boven de ouder voorouder knooppunten, en als je een ouder waarvan de linker- kind is het knooppunt dat u momenteel in bent vinden, de ouder is de inorder opvolger van uw originele node.

Als u recht kind te hebben, doen deze aanpak (geval 1 hierboven):

inorder-when-rechts-kind

Als u niet beschikt over een recht kind te hebben, doen deze aanpak (geval 2 hierboven):

inorder-when-no-rechts-kind

Als u niet bewaren de bovenliggende koppeling

Dan moet je een complete scan van de boom lopen, het bijhouden van de knooppunten, meestal met een stack, zodat u de informatie die nodig is om in principe hetzelfde als de eerste methode die zich op de bovenliggende koppeling te doen.

antwoordde op 29/03/2011 om 12:47
bron van user

stemmen
2

Hier is een implementatie zonder de noodzaak voor ouders koppelingen of intermediaire structuren (zoals een stack). Deze in-order opvolger functie is een beetje anders dan wat de meeste misschien op zoek naar, omdat het werkt op de sleutel, in tegenstelling tot het knooppunt. Ook zal het een opvolger van een sleutel te vinden, zelfs als het niet aanwezig is in de boom. Niet te moeilijk te veranderen als je die nodig zijn om, echter.

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));
    }
}
}
antwoordde op 27/04/2012 om 15:47
bron van user

stemmen
2

Met Binary Search Boom, het algoritme op zoek naar de volgende hoogste knooppunt van een bepaald knooppunt is in feite het vinden van de laagste knooppunt van de juiste sub-boom van dat knooppunt.

Het algoritme kan gewoon zijn:

  1. Begin met de rechter kind van de opgegeven node (maken het de tijdelijke huidige knooppunt)
  2. Als de huidige node geen links kind, is de volgende hoogste node.
  3. Als het huidige knooppunt heeft een linker kind, maken het de huidige knooppunt.

Herhaal 2 en 3 totdat we volgende hoogste node.

antwoordde op 02/11/2012 om 20:13
bron van user

stemmen
4

Python code om de Lasse's antwoord :

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
antwoordde op 12/01/2013 om 23:25
bron van user

stemmen
1

C ++ oplossing uitgaande knooppunten links, rechts en ouder wijzers:

Dit illustreert de functie Node* getNextNodeInOrder(Node)die de volgende toets van de binaire zoekboom in-order terug.

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

Welke prints:

1 2 3 4 5 6 7 8 9 10 11

unit tests: 
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
antwoordde op 16/07/2013 om 19:21
bron van user

stemmen
0

U kunt extra info lees hier (Rus long)

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
antwoordde op 07/10/2014 om 11:25
bron van user

stemmen
0

Deze antwoorden lijken allemaal te ingewikkeld voor mij. We hebben echt niet ouder pointers of extra data structuren zoals een stapel nodig. Alles wat we moeten doen is de boom van de wortel in orde, zet een vlag zodra we vinden het doel knooppunt, en het volgende knooppunt in de boom die we bezoeken zullen het in orde opvolgerknooppunt doorkruisen. Hier is een quick and dirty routine ik schreef.

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);
}
antwoordde op 09/12/2014 om 05:29
bron van user

stemmen
1

Als we het uitvoeren van een in orde traversal dan bezoeken we de linker deelboom, dan rootnode en ten slotte de rechter deelboom voor elk knooppunt in de boom. Het uitvoeren van een in orde traversal zal ons de sleutels van een binaire zoekboom in oplopende volgorde te geven, dus als we verwijzen naar het ophalen van de ter opvolger van een knoop die behoren tot een binaire zoekboom we menen wat het volgende knooppunt in de sequentie uit zou zijn de bepaalde knoop.

Laten we zeggen dat we een knooppunt R en we willen zijn om opvolger dan zouden we de volgende gevallen.

[1] De wortel R recht knooppunt, zodat alles wat we moeten doen is doorlopen naar de meest linkse knooppunt van R-> rechts.

[2] De wortel R geen recht knooppunt in dit geval hebben we doorkruisen back de structuur na de oorspronkelijke verbindingen tot het knooppunt R een linkerkind van de bovenliggende alsdan we de bovenliggende knooppunt P als de ter opvolger .

[3] Wij zijn uiterst rechts knooppunt van de boom, in dit geval is er geen in orde opvolger.

De implementatie is gebaseerd op het volgende knooppunt definitie

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);
}
antwoordde op 10/01/2015 om 20:11
bron van user

stemmen
0

JavaScript oplossing - Als het gegeven knooppunt een recht knooppunt, dan terug de kleinste knooppunt in de rechter deelboom - Zo niet, dan zijn er 2 mogelijkheden: - De opgegeven knooppunt is een linker kind van de bovenliggende node. Zo ja, de terugkeer van de bovenliggende node. Anders is het gegeven knooppunt is een recht kind van de bovenliggende node. Als dat zo is, terug te keren het recht kind van de bovenliggende knooppunt

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;
  }
}
antwoordde op 19/10/2015 om 03:44
bron van user

stemmen
0

Door dit te doen 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);
    }
}
antwoordde op 22/11/2016 om 04:58
bron van user

stemmen
0

We kunnen dit verdelen in 3 gevallen:

  1. Als het knooppunt is een ouder: In dit geval vinden we als het een juiste knooppunt en doorkruisen om de meest linkse kind van de rechter node. In het geval dat de juiste node geen kinderen dan is de juiste knooppunt is zijn inorder opvolger. Als er geen recht knooppunt moeten we overgaan tot de boom naar de inorder opvolger te vinden.

  2. Als het knooppunt is een linker kind: In dit geval is de ouder de inorder opvolger.

  3. Als het knooppunt (noem het x) is een recht kind (van de onmiddellijke ouder): We doorkruisen de boom totdat we een knooppunt waarvan de linker deelboom heeft x vinden.

Extreem geval: Als het knooppunt is de meest rechtse hoek knooppunt, is er geen inorder opvolger.

antwoordde op 30/11/2016 om 10:12
bron van user

stemmen
0

Elke "les" dat ik gecontroleerd op google en alle antwoorden in deze thread gebruikt de volgende logica: " Als het knooppunt een recht kind dan niet heeft haar in-order opvolger zal een van zijn voorouders met behulp van moederbedrijf koppeling blijven reizen tot aan. je krijgt het knooppunt dat is de linker kind van haar ouders. dan is deze ouderknoop zal de in-order opvolger. "

Dit is hetzelfde als denken " als mijn ouders is groter dan ik, dan ben ik de linker kind " (eigendom van een binaire zoekboom). Dit betekent dat je gewoon kunt lopen naar de bovenliggende, totdat de bovenstaande eigenschap true. Die naar mijn mening resulteert in een meer elegante code.

Ik denk dat de reden waarom iedereen is het controleren van " ben ik de linker kind " door te kijken naar vestigingen in plaats van waarden in de code pad dat ouder banden gebruikt komt van "lenen" de logica van de no-link-naar-parent algoritme.

Ook vanuit de meegeleverde onderstaande code we kunnen zien is er geen noodzaak voor stack datastructuur zoals voorgesteld door andere antwoorden.

Hieronder volgt een eenvoudig C ++ functie die werkt voor zowel use-cases (met en zonder gebruik van de link ouder).

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;
    }
}
antwoordde op 01/01/2017 om 13:11
bron van user

stemmen
0

C # implementatie (Non recursieve!) Naar de 'next' knooppunt van een bepaald knooppunt te vinden in een binaire zoekboom waarbij elk knooppunt heeft een link naar de bovenliggende.

    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);
    }
antwoordde op 16/03/2017 om 07:15
bron van user

stemmen
0

We kunnen de opvolger in O (log n) zonder gebruik te maken ouder pointers (voor een evenwichtige boom) te vinden.

Het idee is zeer vergelijkbaar met als je ouder pointers.

We kunnen een recursieve functie die dit realiseert als volgt te definiëren:

  • Als het huidige knooppunt is het doel, de terugkeer van de meest linkse / kleinste knoop van zijn rechter deelboom, als het bestaat.
  • Recurse linker als het doel kleiner is dan het huidige knooppunt en rechter als het groter.
  • Als het doel is om de links en we hebben nog niet gevonden een opvolger, de terugkeer van de huidige knooppunt.

Pseudo-code:

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

Leef Java demo .

antwoordde op 31/12/2017 om 16:10
bron van user

stemmen
1

we dont behoefte ouder link of stack naar het vinden om opvolger in O (log n) (uitgaande van gebalanceerde boom). Houd een tijdelijke variabele met de meest recente waarde aangetroffen in de inorder traversal dat groter is dan de sleutel. Als inorder traversal vaststelt dat het knooppunt een recht kind heeft, dan zou dit de inorder opvolger. anders, de meest linkse afstammeling van de juiste kind.

antwoordde op 03/07/2018 om 20:07
bron van user

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