Gitt en node i et BST, hvordan finner man det neste høyere nøkkelen?
I Bestill etterfølger i binært søketre
Sjekk ut her: inorder etterfølger i et binært søketre
I Binary forfedre Inorder etterfølger av en node er neste node i Inorder traversering av Binary treet. Inorder etterfølger er NULL for siste node i Inoorder traversering. I binært søketre, kan Inorder etterfølger en inngangsnode også defineres som noden med den minste nøkkelen større enn nøkkelen til inngangsnode.
Den generelle måten avhenger av om du har en forelder link i dine noder eller ikke.
Hvis du lagrer den overordnede koblingen
Deretter velger du:
- Lengst til venstre barn av retten barnet, hvis din nåværende node har rett barn. Hvis retten barnet har ingen venstre barn, er det rette barnet inorder etterfølger.
- Naviger opp foreldre stamfar noder, og når du finner en forelder som venstre barn er noden du er for tiden på, er den overordnede inorder etterfølger til den opprinnelige noden.
Hvis du har riktig barn, gjør denne tilnærmingen (case 1 ovenfor):

Hvis du ikke har rett til barn, gjør denne tilnærmingen (tilfelle 2 ovenfor):

Hvis du ikke lagrer den overordnede koblingen
Deretter må du kjøre en fullstendig skanning av treet, holde styr på nodene, vanligvis med en stabel, slik at du har nødvendig informasjon for å i utgangspunktet gjøre det samme som den første metoden som støttet seg på den overordnede link.
Her er en implementering uten behov for overordnede linker eller mellomliggende strukturer (for eksempel en stabel). Dette i-order etterfølger funksjonen er litt annerledes enn hva de fleste kan være ute etter, siden den opererer på nøkkelen i motsetning til noden. Dessuten vil det finne en etterfølger av en nøkkel, selv om det ikke er til stede i treet. Ikke så vanskelig å endre hvis du trengte å, imidlertid.
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));
}
}
}
Med binært søketre, til algoritmen finne den nest høyeste node til en gitt node er i utgangspunktet å finne den laveste noden i høyre sub-tre av den noden.
Algoritmen kan bare være enkelt:
- Begynn med høyre barn av gitt node (gjøre den midlertidige gjeldende node)
- Hvis gjeldende node har ingen venstre barn, er det nest høyeste node.
- Hvis gjeldende node har en venstre barn, gjør det gjeldende node.
Gjenta 2 og 3 til vi finner nest høyeste node.
Python koden til Lasses svaret :
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øsning forutsatt noder har venstre, høyre, og foreldre tips:
Dette illustrerer funksjonen Node* getNextNodeInOrder(Node)som returnerer neste nøkkelen til binært søketre i bestilling.
#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;
}
Som utskrifter:
1 2 3 4 5 6 7 8 9 10 11
unit tests:
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Du kan lese mer info her (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
Disse svarene alle synes altfor komplisert for meg. Vi trenger ikke foreldrepekere eller andre hjelpedatastrukturer som en stabel. Alt vi trenger å gjøre er å traversere treet fra roten i bestilling, sette et flagg så snart vi finne målet node, og neste node i treet som vi besøker vil være i orden etterfølger node. Her er en rask og skitne rutine jeg skrev opp.
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);
}
Hvis vi utfører en for traversering da vi besøker venstre treet, så root node og til slutt høyre subtre for hver node i treet. Utføre en for traversering vil gi oss nøklene til et binært søketre i stigende rekkefølge, så når vi refererer til å hente den for etterfølgeren av en node som tilhører et binært søketre vi mener det vil være det neste node i sekvensen fra den gitte node.
La oss si vi har en node R og vi ønsker det for etterfølgeren ville vi ha følgende tilfeller.
[1] Roten R har en rett node, slik at alt vi trenger å gjøre er å traversere å lengst til venstre noden i R-> høyre.
[2] Den grunnlegg R har ingen rett node, i dette tilfelle vi traversere tilbake opp treet følgende mor- koblingene til noden R er et venstre barn av foreldre, når dette skjer vi har foreldrenoden P som i rekkefølge etterfølger .
[3] Vi er på det ekstreme høyre node i treet, i dette tilfellet er det ingen i orden etterfølger.
Gjennomføringen er basert på følgende noden definisjonen
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øsning - Hvis gitt node har rett node, deretter returnere den minste node i riktig treet - Hvis ikke, så er det 2 muligheter: - Den oppgitte noden er en venstre barn av foreldrenoden. I så fall tilbake foreldrenoden. Ellers er gitt node rett barn av foreldrenoden. Hvis ja, gå tilbake til høyre barn av foreldrenoden
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;
}
}
Å gjøre dette i 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);
}
}
Vi kan dele dette i 3 tilfeller:
Hvis noden er en forelder: I dette tilfellet finner vi hvis det har en riktig node og krysse til den nest siste barnet av retten node. Ved riktig node har ingen barn så høyre node er dens inorder etterfølger. Hvis det ikke er riktig node må vi flytte opp treet for å finne den inorder etterfølger.
Hvis noden er en venstre barn: I dette tilfellet foreldrene er inorder etterfølger.
Hvis noden (kaller det x) er en rettighet barn (av dens umiddelbare overordnede): Vi krysser opp treet til vi finner en node som venstre subtre har x.
Ekstremt tilfelle: Dersom noden er lengst til høyre hjørne node, er det ingen inorder etterfølger.
Hver "tutorial" som jeg sjekket på google og alle svarene i denne tråden bruker følgende logikk: " Hvis noden ikke har rett til barnet deretter sin i-order etterfølger vil være en av sine forfedre ved hjelp av foreldrene linken holde reiser frem til. du får node som er venstre barn av sin overordnede. Da er dette overordnede noden vil være i for etterfølger. "
Dette er det samme som å tenke " hvis foreldrene mine er større enn meg, så jeg er venstre barn " (eies av et binært søketre). Dette betyr at du kan bare gå opp den overordnede kjeden til ovennevnte eiendom er sant. Som etter min mening gir en mer elegant kode.
Jeg tror grunnen til at alle ser " er jeg forlot barnet " ved å se på grener i stedet for verdier i kodebanen som utnytter foreldre linker kommer fra "låne" logikk fra nei-link-to-foreldre-algoritmen.
Også fra den medfølgende koden under vi kan se er det ikke behov for stack datastruktur som foreslått av andre svar.
Følgende er en enkel C ++ funksjon som fungerer for begge bruks-trekk (med og uten anvendelse av kobling til moder).
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 # implementering (Non rekursiv!) For å finne den 'neste' node til en gitt node i et binært søketre der hver node har en link til sin overordnede.
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);
}
Vi kan finne følgeren i O (log n) uten bruk av foreldre pekere (for en balansert tre).
Ideen er veldig lik når du har foreldrepekere.
Vi kan definere en rekursiv funksjon som oppnår dette på følgende måte:
- Hvis den aktuelle noden er målet, returnere lengst til venstre / minste node av sin rett treet, hvis den finnes.
- Recurse venstre hvis målet er mindre enn den nåværende node, og høyre om det er større.
- Hvis målet er til venstre, og vi har ikke funnet en etterfølger ennå, returnerer gjeldende node.
Pseudo-kode:
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
vi trenger moder kobling eller stabel for å finne den for etterfølger in O (log n) (forutsatt balansert tre). Hold en midlertidig variabel med den nyeste verdien oppstått i inorder traversering som er større enn nøkkelen. hvis inorder traversering finner at noden ikke har rett barn, da dette ville være den inorder etterfølger. annet, lengst til venstre kommer av høyre barn.













