Δεδομένης ένας κόμβος σε ένα BST, πώς μπορεί κανείς να βρει την επόμενη υψηλότερη κλειδί;
Στην Παραγγελία Διάδοχος σε δυαδική αναζήτηση Δέντρο
Αναχώρηση εδώ: Inorder Διάδοχος σε μια δυαδική αναζήτηση Δέντρο
Σε Binary Tree, Inorder διάδοχος ενός κόμβου είναι ο επόμενος κόμβος Inorder διάσχιση του Binary Tree. Inorder Διάδοχος είναι NULL για το τελευταίο κόμβο στο Inoorder διάσχισης. Σε Binary Search Tree, Inorder Διάδοχος του κόμβου εισόδου μπορεί επίσης να οριστεί ως τον κόμβο με το μικρότερο κλειδί μεγαλύτερη από το κλειδί του κόμβου εισόδου.
Ο γενικός τρόπος εξαρτάται από το αν έχετε ένα γονέα σύνδεση σε κόμβους ή όχι.
Αν αποθηκεύετε το μητρικό σύνδεσμο
Στη συνέχεια, μπορείτε να επιλέξετε:
- Το αριστερό παιδί του δικαιώματος του παιδιού, εάν το τρέχον κόμβος σας έχει δικαίωμα των παιδιών. Εάν το δικαίωμα του παιδιού δεν έχει αριστερό παιδί, το δικαίωμα του παιδιού είναι inorder διάδοχό σας.
- Πλοηγηθείτε μέχρι τους κόμβους πρόγονο γονέα, και όταν βρείτε ένα γονέα με το αριστερό παιδί είναι ο κόμβος είστε σήμερα στο, η μητρική είναι η inorder διάδοχος του αρχικού κόμβου σας.
Εάν έχετε το δικαίωμα του παιδιού, κάνει αυτή την προσέγγιση (περίπτωση 1 παραπάνω):

Εάν δεν έχετε το δικαίωμα των παιδιών, κάνει αυτή την προσέγγιση (περίπτωση 2 πιο πάνω):

Αν δεν αποθηκεύσετε το μητρικό σύνδεσμο
Στη συνέχεια, θα πρέπει να εκτελέσετε μια πλήρη σάρωση του δέντρου, την παρακολούθηση των κόμβων, συνήθως με μια στοίβα, έτσι ώστε να έχετε τις πληροφορίες που απαιτούνται για ουσιαστικά κάνει το ίδιο με την πρώτη μέθοδο που επικαλέστηκε η μητρική σύνδεσμο.
Εδώ είναι μια εφαρμογή χωρίς την ανάγκη για μητρική συνδέσεις ή ενδιάμεσων δομών (όπως μια στοίβα). Αυτή η λειτουργία διάδοχος τάξης είναι λίγο διαφορετικό από αυτό που οι περισσότεροι θα μπορούσε να ψάχνει για δεδομένου ότι λειτουργεί με κλειδί, σε αντίθεση με τον κόμβο. Επίσης, θα βρείτε ένα διάδοχο ενός κλειδιού, ακόμη και αν δεν υπάρχει στο δέντρο. Δεν είναι πολύ δύσκολο να αλλάξει αν χρειάζεται να, όμως.
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));
}
}
}
Με Binary Search Tree, ο αλγόριθμος για να βρει το επόμενο υψηλότερο κόμβος ενός συγκεκριμένου κόμβου είναι ουσιαστικά εύρεση της χαμηλότερης κόμβο του δικαιώματος υπο-δέντρο αυτού του κόμβου.
Ο αλγόριθμος μπορεί απλά να είναι απλά:
- Ξεκινήστε με το δεξί παιδί του συγκεκριμένου κόμβου (να είναι η προσωρινή τρέχοντος κόμβου)
- Εάν ο τρέχων κόμβος δεν έχει αριστερό παιδί, είναι το επόμενο υψηλότερο κόμβο.
- Εάν ο τρέχων κόμβος έχει ένα αριστερό παιδί, ο τρέχων κόμβος κάνει.
Επαναλάβετε 2 και 3 μέχρι να βρούμε το επόμενο υψηλότερο κόμβο.
Κώδικα Python για να του Lasse του απάντηση :
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 διάλυμα ++ υποθέτοντας κόμβοι έχουν αριστερά, δεξιά, και η μητρική δείκτες:
Αυτό δείχνει τη λειτουργία Node* getNextNodeInOrder(Node)που επιστρέφει το επόμενο πλήκτρο του δυαδικού δένδρου αναζήτησης τάξης.
#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;
}
Ποια εκτυπώσεις:
1 2 3 4 5 6 7 8 9 10 11
unit tests:
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Μπορείτε να διαβάσετε περισσότερες πληροφορίες εδώ (Rus πνεύμονα)
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
Αυτές οι απαντήσεις όλα φαίνονται υπερβολικά περίπλοκη για μένα. Εμείς πραγματικά δεν χρειάζεται γονέα δείκτες ή οποιεσδήποτε βοηθητικές δομές δεδομένων, όπως μια στοίβα. Το μόνο που χρειάζεται να κάνετε είναι να διασχίσει το δέντρο από τη ρίζα σε σειρά, που μια σημαία, το συντομότερο βρίσκουμε τον κόμβο-στόχο, και το επόμενο κόμβο στο δέντρο που επισκεπτόμαστε θα είναι ο κόμβος διάδοχο σειρά. Εδώ είναι μια γρήγορη και βρώμικη τακτική έγραψα επάνω.
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);
}
Εάν εκτελέσετε μια σε διάσχισης, προκειμένου, στη συνέχεια, θα επισκεφθούμε το αριστερό υποδένδρο, τότε ο κόμβος ρίζα και, τέλος, το δικαίωμα υποδένδρο για κάθε κόμβο στο δέντρο. Εκτέλεση ένα στο διάσχισης, προκειμένου να μας δώσει τα κλειδιά ενός δυαδικού δένδρου αναζήτησης με αύξουσα σειρά, έτσι ώστε όταν αναφερόμαστε στην ανάκτηση του για διάδοχο του κόμβου που ανήκει σε ένα δυαδικό δέντρο αναζήτησης που σημαίνει ό, τι θα ήταν ο επόμενος κόμβος στην ακολουθία από το δεδομένο κόμβο.
Ας πούμε ότι έχουμε έναν κόμβο R και θέλουμε τους στο διάδοχο σειρά που θα έχει τις ακόλουθες περιπτώσεις.
[1] Η ρίζα R έχει δικαίωμα κόμβο, οπότε το μόνο που χρειάζεται να κάνετε είναι να διασχίσει με το αριστερό πιο κόμβο της R-> δικαιώματος.
[2] Η ρίζα R δεν έχει δικαίωμα κόμβο, σε αυτή την περίπτωση θα διασχίζουν πίσω μέχρι το δέντρο μετά από τις μητρικές συνδέσεις μέχρι τον κόμβο R είναι ένα αριστερό παιδί του γονέα του, όταν αυτό συμβαίνει έχουμε το μητρικό κόμβο P όπως η εν διάδοχος σειρά .
[3] Βρισκόμαστε στην άκρα δεξιά κόμβο του δέντρου, στην περίπτωση αυτή δεν υπάρχει σε διάδοχος σειρά.
Η εφαρμογή βασίζεται στα εξής ορισμό κόμβο
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 - Αν το δεδομένο κόμβο έχει δικαίωμα κόμβο, στη συνέχεια επιστρέφουν το μικρότερο κόμβο στο δεξί υποδέντρο - Αν όχι, τότε υπάρχουν 2 δυνατότητες: - Το δεδομένο κόμβο είναι ένα αριστερό παιδί του γονέα κόμβο. Αν ναι, επιστρέψτε το γονικό κόμβο. Σε αντίθετη περίπτωση, το δεδομένο κόμβο είναι δικαίωμα του παιδιού της μητρικής κόμβο. Αν ναι, επιστρέψτε το δικαίωμα του παιδιού της μητρικής κόμβου
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;
}
}
Με αυτόν τον τρόπο σε 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);
}
}
Μπορούμε να χωρίσουμε αυτό σε 3 περιπτώσεις:
Αν ο κόμβος είναι ένας γονέας: Σε αυτή την περίπτωση θα βρούμε αν έχει το δικαίωμα κόμβο και διασχίζουν με το αριστερό παιδί του δικαιώματος κόμβου. Σε περίπτωση που το δικαίωμα κόμβος δεν έχει παιδιά, τότε η σωστή κόμβος είναι inorder διάδοχό του. Αν δεν υπάρχει σωστό κόμβο πρέπει να κινηθεί προς τα επάνω το δέντρο για να βρει το διάδοχο inorder.
Αν ο κόμβος είναι ένα αριστερό παιδί: Σε αυτή την περίπτωση ο γονέας είναι ο διάδοχος inorder.
Αν ο κόμβος (ονομάσουμε x) είναι δικαίωμα του παιδιού (άμεσης μητρικής της): Θα διασχίσει το δέντρο μέχρι να βρούμε έναν κόμβο του οποίου το αριστερό υποδέντρο έχει x.
Ακραία περίπτωση: Εάν ο κόμβος είναι το δεξιότερο κόμβο γωνία, δεν υπάρχει διάδοχος inorder.
Κάθε «φροντιστήριο» που ελέγχονται στο google και όλες τις απαντήσεις σε αυτό το νήμα χρησιμοποιεί την εξής λογική: " Αν ο κόμβος δεν έχει το δικαίωμα του παιδιού στη συνέχεια της στη σειρά διάδοχος θα είναι ένας από τους προγόνους του, χρησιμοποιώντας μητρική σύνδεσμο κρατήσει ταξιδεύουν μέχρι. μπορείτε να πάρετε τον κόμβο που είναι το αριστερό παιδί του γονέα του. στη συνέχεια, αυτή η μητρική κόμβος θα είναι ο διάδοχος στην παραγγελία. "
Αυτό είναι το ίδιο με τη σκέψη « αν η μητρική μου είναι μεγαλύτερο από μένα, τότε είμαι το αριστερό παιδί » (ιδιοκτησίας ενός δυαδικού δένδρου αναζήτησης). Αυτό σημαίνει ότι μπορείτε απλά να περπατήσετε μέχρι τη μητρική αλυσίδα μέχρι το παραπάνω ακίνητο είναι αλήθεια. Η οποία με αποτέλεσμα τη γνώμη μου σε ένα πιο κομψό κώδικα.
Υποθέτω ότι ο λόγος για τον οποίο ο καθένας έχει τον έλεγχο « είμαι το αριστερό παιδί » κοιτάζοντας τα υποκαταστήματα και όχι τιμές στον κώδικα μονοπάτι που χρησιμοποιεί η μητρική συνδέσεις προέρχεται από το «δανεισμό» λογική από τον αλγόριθμο μη-link-to-γονέα.
Επίσης από την συμπεριλαμβάνονται παρακάτω κώδικα είναι εκεί μπορούμε να δούμε καμία ανάγκη για τη δομή των δεδομένων στοίβα όπως προτείνεται από άλλες απαντήσεις.
Μετά είναι μια απλή C λειτουργία ++ που λειτουργεί και για τις δύο περιπτώσεις χρήσης (με και χωρίς τη χρησιμοποίηση του συνδέσμου προς τη μητρική).
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 # εφαρμογή (μη αναδρομικό!) Για να βρείτε την «επόμενη» κόμβος ενός συγκεκριμένου κόμβου σε ένα δυαδικό δένδρο αναζήτησης, όπου κάθε κόμβος έχει μια σύνδεση με τη μητρική της.
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);
}
Μπορούμε να βρούμε τον διάδοχο σε O (log n) χωρίς τη χρήση μητρικών δείκτες (για μια ισορροπημένη δέντρο).
Η ιδέα είναι πολύ παρόμοια με όταν έχεις γονέα δείκτες.
Μπορούμε να ορίσουμε μια αναδρομική συνάρτηση που επιτυγχάνει αυτό ως εξής:
- Εάν ο τρέχων κόμβος είναι ο στόχος, να επιστρέψει το πιο αριστερό / μικρότερη κόμβο του δικαιώματος υποδέντρο του, αν υπάρχει.
- Recurse αριστερά αν ο στόχος είναι μικρότερο από το τρέχον κόμβο, και δεξιά αν είναι μεγαλύτερη.
- Εάν ο στόχος είναι προς τα αριστερά και δεν έχουμε βρει έναν διάδοχο ακόμα, να επιστρέψει το τρέχον κόμβο.
Ψευδοκώδικας:
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
εμείς dont πρέπει γονέα σύνδεση ή στοίβα για να βρει το διάδοχο στην σειρά με O (log n) (υποθέτοντας ισορροπημένο δέντρο). Κρατήστε μια προσωρινή μεταβλητή με την πιο πρόσφατη τιμή που ανέκυψαν κατά τη διάσχιση inorder που είναι μεγαλύτερο από το κλειδί. αν inorder διάσχιση διαπιστώσει ότι ο κόμβος δεν έχει το δικαίωμα του παιδιού, τότε αυτό θα ήταν ο διάδοχος inorder. άλλο, το πιο αριστερό απόγονος του δικαιώματος του παιδιού.













