Gegeven een knooppunt in een BST, hoe gaat men de volgende hogere sleutel te vinden?
In Opvolger bestellen in binaire zoekboom
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.
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:
- 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.
- 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):

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

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.
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));
}
}
}
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:
- Begin met de rechter kind van de opgegeven node (maken het de tijdelijke huidige knooppunt)
- Als de huidige node geen links kind, is de volgende hoogste node.
- Als het huidige knooppunt heeft een linker kind, maken het de huidige knooppunt.
Herhaal 2 en 3 totdat we volgende hoogste node.
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
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
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
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);
}
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);
}
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;
}
}
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);
}
}
We kunnen dit verdelen in 3 gevallen:
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.
Als het knooppunt is een linker kind: In dit geval is de ouder de inorder opvolger.
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.
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;
}
}
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);
}
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
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.













