Bei einem gegebenen Knoten in einem BST, wie findet man den nächst höheren Schlüssel?
In Order Nachfolger in binärer Suchbaum
Schauen Sie sich hier: inOrder Nachfolger in einem binären Suchbaum
In Binary Tree, Inorder Nachfolger eines Knotens ist der nächste Knoten in Inorder Traversal des Binary Tree. Inorder Nachfolger ist für den letzten Knoten in Inoorder traversal NULL. In binärer Suchbaum, Inorder Nachfolger eines Eingangsknotens kann auch als Knoten mit dem kleinsten Schlüssel größer als der Schlüssel des Eingangsknotens definiert werden.
Die allgemeine Art und Weise hängt davon ab, ob Sie einen übergeordneten Link in Ihrem Knoten haben oder nicht.
Wenn Sie den Link Elternteil speichern
Dann wählen Sie:
- Das linke Kind des rechten Kindes, wenn Ihre aktuelle Knoten hat ein Recht Kind. Wenn das rechte Kind kein linkes Kind hat das Recht, Kind ist Ihr Inorder Nachfolger.
- Navigieren Sie durch die Eltern Vorfahren Knoten auf, und wenn Sie ein Elternteil, dessen linkes Kind finden, ist der Knoten, den Sie zur Zeit befinden sich auf der Eltern ist die Inorder Nachfolger des ursprünglichen Knotens.
Wenn Sie mit dem rechten Kind haben, tun, diesen Ansatz (Fall 1 oben):

Wenn Sie noch kein Recht Kind haben, tun diesen Ansatz (Fall 2 oben):

Wenn Sie nicht speichern den übergeordneten Link
Dann müssen Sie einen kompletten Scan des Baumes laufen, den Knoten zu verfolgen, in der Regel mit einem Stapel, so dass Sie die Informationen, die notwendig, um im Grunde das gleiches tun wie die erste Methode, die auf dem übergeordneten Link verlassen.
quelle vom benutzer Lasse Vågsæther Karlsen
Hier ist eine Implementierung ohne die Notwendigkeit für Eltern Links oder Zwischenstrukturen (wie ein Stapel). Diese in Ordnung ist Nachfolgerfunktion ein bisschen anders zu dem, was die meisten könnte gesucht werden, da sie arbeitet nach dem Schlüssel zu dem Knoten gegenüber. Auch wird es einen Nachfolger eines Schlüssels finden, auch wenn es nicht in dem Baum ist. Nicht zu schwer zu ändern, wenn Sie benötigen jedoch.
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));
}
}
}
Mit binärer Suchbaum zu finden, der Algorithmus die nächsthöhere Knoten eines bestimmten Knotens im Grunde ist die niedrigste Knoten des rechten Unterbaum dieses Knotens zu finden.
Der Algorithmus kann nur einfach sein:
- Beginnen Sie mit dem rechten Kind des gegebenen Knotens (macht es den temporäre Stromknoten)
- Wenn der aktuelle Knoten kein linkes Kind hat, ist es die nächsthöhere Knoten.
- Wenn der aktuelle Knoten ein linkes Kind hat, machen es der aktuelle Knoten.
2 und 3 wiederholen, bis wir nächst höheren Knoten finden.
Python - Code zu der wichtigsten Lasse Antwort :
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 ++ Lösung Knoten hat links, rechts, und Abstammungszeiger unter der Annahme:
Dies verdeutlicht die Funktion , Node* getNextNodeInOrder(Node)die die nächste Taste des binären Suchbaum in Ordnung zurückkehrt.
#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;
}
Welche Drucke:
1 2 3 4 5 6 7 8 9 10 11
unit tests:
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Sie können weitere Informationen lesen Sie hier (Rus Lunge)
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
Diese Antworten scheinen alle zu kompliziert für mich. Wir brauchen wirklich keine Abstammungszeiger oder jegliche Hilfsdatenstrukturen wie ein Stapel. Alles, was wir tun müssen, ist, den Baum von der Wurzel in Ordnung, eine Fahne so schnell eingestellt durchquert, wie wir den Zielknoten und den nächsten Knoten im Baum, die wir besuchen werden die um Nachfolgeknoten zu finden. Hier ist eine schnelle und schmutzige Routine, die ich schrieb auf.
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);
}
Wenn wir ein, um Traversal führen Sie dann besuchen wir den linken Unterbaum, dann Wurzelknoten und schließlich den rechten Teilbaum für jeden Knoten im Baum. Durchführen eines um Traversal gibt uns die Schlüssel eines binären Suchbaumes in aufsteigender Reihenfolge, so dass, wenn wir verweisen die um Nachfolger eines Knotens der Zugehörigkeit zu einem binären Suchbaum Abrufen wir meinen, was der nächste Knoten in der Folge wäre aus der gegebene Knoten.
Lets sagen, dass wir einen Knoten R haben, und wir wollen seine um Nachfolger würden wir die folgenden Fälle haben.
[1] Die Wurzel R hat einen richtigen Knoten, so alles , was wir tun müssen , ist auf der linken Seite die meisten Knoten der R-> rechts zu überqueren.
[2] Die Wurzel R hat keinen rechten Knoten, in diesem Fall haben wir die übergeordneten Verknüpfungen folgenden auf den Baum durchlaufen zurück , bis der Knoten R ein linkes Kind seiner Eltern ist, wenn dies der Fall wir den übergeordneten Knoten P als um Nachfolger haben , .
[3] Wir sind am äußersten rechten Knoten des Baumes, in diesem Fall gibt es keine , um Nachfolger ist.
Die Umsetzung wird auf die folgenden Knotendefinition basiert
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-Lösung - Wenn der gegebene Knoten einen rechten Knoten hat, dann wieder den kleinsten Knoten im rechten Teilbaum - Wenn nicht, dann gibt es zwei Möglichkeiten: - Der angegebene Knoten ein linkes Kind des Elternknotens ist. Wenn dem so ist, zurückkehren den übergeordneten Knoten. Ansonsten ist der gegebene Knoten ein rechtes Kind des Elternknotens. Wenn ja, schicken Sie das rechte Kind des Elternknotens
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;
}
}
Dadurch 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);
}
}
Wir können diese teilen in drei Fällen:
Wenn der Knoten ein Elternteil ist: In diesem Fall finden wir, wenn es einen richtigen Knoten hat und auf das äußerste linke Kind des rechten Knoten durchqueren. Falls der richtige Knoten keine Kinder dann der rechte Knoten sein Inorder Nachfolger ist. Wenn es keine richtigen Knoten ist, müssen wir den Baum nach oben zu dem Inorder Nachfolger zu finden.
Wenn der Knoten ein linkes Kind ist: In diesem Fall ist die Mutter der Inorder Nachfolger.
Wenn der Knoten (nennen wir es x) ein rechtes Kind ist (der unmittelbar übergeordneten): Wir durchqueren den Baum, bis wir einen Knoten, dessen linken Unterbaum hat x finden.
Extremfall: Wenn der Knoten der äußerste rechte Ecke Knoten ist, gibt es keinen Inorder Nachfolger.
Jedes „Tutorial“ , die ich auf Google und alle Antworten in diesem Thread überprüft verwendet die folgende Logik: " Wenn der Knoten ein rechtes Kind nicht , dann haben seine in Ordnung Nachfolger eines seiner Vorfahren sein Mit Link Eltern halten unterwegs bis. Sie erhalten den Knoten, der das linke Kind seiner Eltern ist. Dann ist dieser übergeordnete Knoten der in Ordnung Nachfolger sein wird. "
Dies ist das gleiche wie „denken , wenn meine Eltern größer als ich ist, dann bin ich das linke Kind “ (Eigenschaft eines binären Suchbaum). Das bedeutet , dass Sie einfach die Elternkette gehen , bis die obige Eigenschaft wahr ist. Was meiner Meinung nach ergibt sich ein eleganter Code.
Ich denke , den Grund , warum jede Überprüfung „ Ich ist das linke Kind “ von anstelle von Werten im Codepfad in den Filialen suchen , die von „Borgen“ Logik von dem no-link-to-Eltern - Algorithmus kommt Mutter Links verwendet.
Auch aus dem Code unten enthalten wir es sehen keine Notwendigkeit für die Strukturstapeldaten wie von anderen Antworten.
Folgende ist eine einfache C ++ Funktion, die für beide Anwendungsfälle (mit und ohne Verwendung der Link zum parent) funktioniert.
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 # -Implementierung (Non rekursiv!), Um die ‚next‘ Knoten eines bestimmtes Knotens in einem binären Suchbaum zu finden, wo jeder Knoten einen Link zu seinen Eltern hat.
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);
}
Wir können die Nachfolger in O (log n) ohne Abstammungszeiger mit (für einen ausgeglichenen Baum).
Die Idee ist sehr ähnlich, wenn Sie Abstammungszeiger haben.
Wir können eine rekursive Funktion definieren, die dies erreicht, wie folgt:
- Wenn der aktuelle Knoten das Ziel ist, kehren die am weitesten links / kleinste Knoten seiner rechten Teilbaum, wenn es vorhanden ist.
- Recurse links, wenn das Ziel kleiner ist als der aktuelle Knoten ist, und richtig, wenn es größer ist.
- Wenn das Ziel auf der linken Seite, und wir haben keinen Nachfolger noch, geben Sie den aktuellen Knoten gefunden.
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
wir nicht Mutter Link benötigen oder stapeln die um Nachfolger in O (log n) (unter der Annahme, ausgewogenen Baum) zu finden. Halten Sie eine temporäre Variable mit dem letzten Wert in der Inorder Traversal angetroffen, der größer ist als der Schlüssel ist. wenn Inorder Traversal feststellt, dass der Knoten nicht ein rechtes Kind hat, dann wäre dies der Inorder Nachfolger sein. der linke Abkömmling des rechten Kindes sonst.













