Biorąc węzła w BST, w jaki sposób można znaleźć następną wyższą klucz?
W Następcy porządek w binarne drzewo poszukiwań
Sprawdź tutaj: Inorder następca w binarne drzewo poszukiwań
W drzewo binarne, Inorder następca węzła to kolejny węzeł w Inorder przejście przez drzewo binarne. Inorder następca jest NULL dla ostatniego węzła w Inoorder przechodzenia. W binarne drzewo poszukiwań, Inorder Następca węzła wejściowego może być również określona jako węzeł z najmniejszym kluczem większym niż klucz węzła wejściowego.
Ogólny sposób zależy od tego, czy masz link dominującej w węzłach lub nie.
Jeśli przechowujesz link nadrzędnego
Następnie należy wybrać:
- Skrajny lewy dziecko z prawego dziecka, jeśli bieżący węzeł ma prawo dziecka. Jeśli dziecko ma prawo lewy dziecka, prawa dziecka to Inorder następca.
- Poruszać się rodzic węzły przodka i kiedy można znaleźć rodzica, którego dziecko jest lewy węzeł jesteś obecnie, rodzic jest następcą Inorder z oryginalnego węzła.
Jeśli masz prawo dziecka, czy to podejście (przypadek 1 powyżej):

Jeżeli nie mają prawa dziecka, czy to podejście (przypadek 2 powyżej):

Jeśli nie przechowywać link nadrzędnego
Następnie należy uruchomić pełne skanowanie drzewa, śledzenie węzłami, zwykle ze stosu, tak, że masz informacje niezbędne do w zasadzie tak samo jak w pierwszym sposobie, że oparła się na link macierzystej.
Oto implementacja bez konieczności powiązania dominujących lub struktur pośrednich (takich jak stos). Ta funkcja w następca zamówienie jest nieco różni się od tego, co najbardziej może być szukasz, ponieważ działa na klucz, w przeciwieństwie do węzła. Również będzie znaleźć następcę klucza, nawet jeśli nie jest obecny w drzewie. Nie jest zbyt trudne do zmiany, jeśli potrzebne do krytyki.
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));
}
}
}
Z binarne drzewo poszukiwań, algorytm, aby znaleźć następny najwyższy węzeł danego węzła jest w zasadzie znalezienie najniższą węzeł prawego poddrzewa tego węzła.
Algorytm może być tylko po prostu:
- Start z prawej dziecka danego węzła (sprawiają, że tymczasowy węzeł bieżący)
- Jeśli bieżący węzeł ma lewy dziecko, to jest następny najwyższy węzeł.
- Jeśli bieżący węzeł posiada lewy dziecka, sprawiają, że bieżący węzeł.
Powtórz 2 i 3, aż znajdziemy obok najwyższy węzeł.
Kod Pythona do Lasse za odpowiedź :
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 ++ rozwiązanie zakładając węzły w lewo, w prawo i wskazówki dla rodziców:
Ilustruje to funkcja Node* getNextNodeInOrder(Node), która zwraca następny klucz binarnym drzewie wyszukiwania w zamówienie.
#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;
}
Która drukuje:
1 2 3 4 5 6 7 8 9 10 11
unit tests:
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Można odczytać dodatkowe informacje tutaj (Rus płuc)
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
Odpowiedzi te wszystkie wydają się zbyt skomplikowane dla mnie. Naprawdę nie trzeba rodzicielskich wskazówek ani żadnych pomocniczych struktur danych, takich jak stos. Wszystko, co musimy zrobić, to przechodzić drzewo z korzenia na zamówienie, należy ustawić flagę jak najszybciej znaleźć węzła docelowego, a następnego węzła w drzewie, które odwiedzimy będzie w kolejności następca węzła. Oto szybki i brudny rutyna pisałem w górę.
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);
}
Jeśli mamy wykonać w celu przechodzenia następnie odwiedzimy lewe poddrzewo, to węzeł główny i wreszcie odpowiedniego poddrzewa dla każdego węzła w drzewie. Wykonywanie w celu przechodzenia da nam klucze binarne drzewo wyszukiwania w porządku rosnącym, więc gdy mówimy do pobierania w kolejności następca węzła należącego do wyszukiwania binarnego drzewa rozumiemy co będzie następny węzeł w kolejności od dany węzeł.
Powiedzmy, że mamy węzła R i chcemy jej w kolejności następca mielibyśmy następujące przypadki.
[1] Korzeń R ma prawo węzeł, więc wszystko co musisz zrobić, to przechodzenie do lewej większości węźle R-> prawo.
[2] Korzeń R ma prawo węzeł, w tym przypadku możemy przechodzić z powrotem na drzewie na linki nadrzędnych aż węzeł R jest lewa dzieckiem swojego rodzica, kiedy to nastąpi mamy Rodzic P jak w kolejności następca ,
[3] Jesteśmy na skrajnym prawym węźle drzewa, w tym przypadku nie ma to na celu następcy.
Implementacja jest oparta na następującej definicji węzła
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);
}
Rozwiązanie JavaScript - Jeżeli dany węzeł ma prawo węzeł, a następnie powrócić najmniejszy węzeł w prawym poddrzewie - Jeśli nie, to są 2 możliwości: - Podany węzeł jest lewa dziecko węzła nadrzędnego. Jeśli tak, to powrót do węzła nadrzędnego. W przeciwnym razie dany węzeł jest prawo dziecka węzła nadrzędnego. Jeśli tak, to powrót właściwej dziecko węzła nadrzędnego
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;
}
}
Robi to w Javie
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);
}
}
Możemy podzielić to w 3 przypadkach:
Jeśli węzeł jest rodzicem: W tym przypadku możemy się dowiedzieć, czy ma on prawo węzeł i przechodzić do skrajnej lewej dziecka prawego węzła. W przypadku, gdy prawo węzeł nie ma dzieci, to jest jego prawo węzeł Inorder następca. Jeśli nie ma prawa węzeł musimy przenieść się na drzewo, by znaleźć następcę Inorder.
Jeśli węzeł jest lewa dziecko: W tym przypadku rodzic jest następcą Inorder.
Jeśli węzeł (nazwijmy go X) jest prawo dziecka (jego bezpośrednim rodzicem): My przechodzić w górę drzewa, aż znajdziemy węzeł, którego lewe poddrzewo ma x.
Skrajny przypadek: Jeśli węzeł jest skrajna węzeł narożny, nie ma Inorder następca.
Każdy „samouczek” że sprawdziłem na google i wszystkich odpowiedzi w tym wątku używa następującej logiki: " Jeśli węzeł nie ma prawa dziecka, to jego następca zamówienie będzie jednym z jego przodków Korzystanie Link rodzic zachować aż do podróżowania. masz węzeł, który jest lewym dzieckiem swojego rodzica. Wtedy ten węzeł nadrzędny będzie następca zamówienie. "
To jest taka sama jak myślenie „ czy mój rodzic jest większy ode mnie, to jestem lewa dziecko ” (właściwość wyszukiwania binarnego drzewa). Oznacza to, że można po prostu iść w górę łańcucha nadrzędnego aż powyżej właściwość ma wartość true. Który w moich wynikach opinii w bardziej elegancki kodu.
Chyba każdy powód jest sprawdzenie „ jestem w lewo dziecko ”, patrząc na oddziałach zamiast wartości w ścieżce kodu, który wykorzystuje łącza nadrzędne pochodzi od „kredytu” logiki od algorytmu no-link-to-rodzica.
Również z dołączonego kodu poniżej widzimy tam jest nie potrzeba struktury danych stosu sugerowane przez innych odpowiedzi.
Poniżej znajduje się prosta funkcja C ++, który pracuje dla obu przypadków użycia (bez iz wykorzystaniem łącza do rodzica).
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 # implementacja (Non rekurencyjne!), Aby znaleźć „Next” węzła danego węzła w drzewie binarnym wyszukiwania, gdzie każdy węzeł ma link do jego rodzica.
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);
}
Możemy znaleźć następcę O (log n) bez stosowania wskaźniki nadrzędne (dla zrównoważonego drzewa).
Pomysł jest bardzo podobny do tego, kiedy masz wskazówek rodzicielskich.
Możemy zdefiniować rekurencyjną funkcję, która osiąga to w następujący sposób:
- Jeśli bieżący węzeł jest celem, powrót lewy-większość / najmniejszy węzeł jej prawym poddrzewie, jeśli istnieje.
- Recurse lewo, jeśli cel jest mniejszy niż bieżącego węzła i prawo, czy to większa.
- Jeśli cel jest po lewej stronie, a my nie znaleźli jeszcze następcy, powrót bieżącego węzła.
Pseudo kod:
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
my nie potrzebują łącza nadrzędnego lub stos, aby znaleźć się w porządku następcy w czasie O (log n) (przy założeniu zrównoważonego drzewa). Zachować zmienną tymczasową z ostatniej wartości napotkane podczas przechodzenia Inorder, który jest większy niż klucza. jeśli Inorder przejścia stwierdza, że węzeł nie ma prawa dziecka, to będzie następca Inorder. indziej, skrajny lewy potomek prawej dziecka.













