Vzhledem k tomu, uzel v BST, jak se dá najít nejbližší vyšší klíč?
Za účelem nástupce strom binárního vyhledávání
Podívejte se zde: nezbytného nástupce binární vyhledávací strom
V binární strom, Nezbytného nástupce uzlu je další uzel v nezbytného průchod binárního stromu. Nezbytného nástupce je NULL pro poslední uzel v Inoorder průchod. V binární vyhledávací strom, Nezbytného nástupce ze vstupního uzlu může být také definována jako uzel s nejmenším klíčem je větší než klíč vstupního uzlu.
Obecný způsob závisí na tom, zda máte nadřazený odkaz ve svých uzlech, či nikoli.
Pokud ukládáte nadřazený odkaz
Pak si vyberete:
- Nejvíce vlevo dítě správným dítěte, je-li aktuální uzel má pravý dítě. V případě, že právo dítěte nemá levou dítěte, právo dítěte je váš nezbytného nástupce.
- Navigate up předchůdce uzly mateřské, a když zjistíte, rodič, jehož dítě vlevo je uzel, že jste v současné době, která je mateřskou je nezbytného nástupcem původní uzlu.
Pokud máte správného dítě, proveďte tento postup (případ 1 výše):

Pokud nechcete mít právo dítě, proveďte tento postup (případ 2 výše):

Pokud nechcete ukládat nadřazený odkaz
Pak budete muset spustit úplnou kontrolu stromu, sledování uzlů, obvykle s komínem, takže máte informace nezbytné pro v podstatě to samé jako první metoda, která vycházela z mateřské odkaz.
Zde je implementace bez nutnosti mateřských vazeb či zprostředkovatelských struktur (jako stoh). Tato funkce nástupce in-cílem je trochu odlišný od toho, co nejvíce by mohlo být hledáme, protože pracuje na tlačítku na rozdíl od uzlu. Také bude hledat nástupce klíče, i když není přítomen ve stromu. Není příliš těžké změnit, pokud jste potřebovali, nicméně.
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));
}
}
}
S binární vyhledávací strom, algoritmus najít další nejvyšší uzel daného uzlu je v podstatě najít nodu pravého podstromu daného uzlu.
Algoritmus může být jednoduše:
- Začněte s pravým dítětem daného uzlu (umožňují dočasné aktuální uzel)
- Pokud je aktuální uzel nemá levé dítě, to je další nejvyšší uzel.
- Pokud je aktuální uzel má levé dítě, aby bylo aktuální uzel.
Opakujte 2 a 3, dokud nenajdeme další nejvyšší uzel.
Python kód Lasse je odpověď :
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 ++ řešení za předpokladu, že uzly mají vlevo, vpravo, a mateřské ukazatele:
To ukazuje funkci Node* getNextNodeInOrder(Node), která vrací další klíč od binárního vyhledávacího stromu na zakázku.
#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;
}
Která tiskne:
1 2 3 4 5 6 7 8 9 10 11
unit tests:
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Si můžete přečíst další informace zde (Rus plic)
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
Tyto odpovědi jsou všechny se zdají příliš složité pro mě. Opravdu nepotřebujeme rodičovských rad nebo jakékoliv pomocné datové struktury, jako zásobníku. Vše, co musíme udělat, je procházet strom z kořene in-pořadí, nastavit příznak, jakmile najdeme cílový uzel a další uzel ve stromu, které navštívíme bude v pořadí následníků uzlu. Zde je rychlý a špinavý rutinní jsem sepsal.
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);
}
Budeme-li provést v pořadí průchod pak navštívíme levý podstrom, pak kořen a nakonec pravého podstromu pro každý uzel ve stromu. Provedení na objednávku průchod nám dá klíče od binárního vyhledávacího stromu ve vzestupném pořadí, takže když jsme se vztahují k načítání v pořadí nástupce uzlu, který patří do binárního vyhledávacího stromu máme na mysli to, co bude příští uzel v pořadí z daný uzel.
Řekněme máme uzlu R a chceme jeho v pořadí nástupce bychom měli tyto případy.
[1] Kořen R má pravý uzel, takže vše, co je třeba udělat, je přejít na nejvíce vlevo uzlu R-> doprava.
[2] Kořen R nemá právo uzlu, v tomto případě se přetínat zpět stromu po nadřazené odkazy dokud uzel R je levý dítě svého rodiče, když k tomu dojde, máme na rodičovský uzel P jako v pořadí nástupce ,
[3] Jsme na zcela vpravo uzlu stromu, v tomto případě není v pořádku nástupce.
Implementace je založeno na následující definici uzlu
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);
}
Řešení JavaScript - V případě, že daný uzel má pravý uzel, pak se vrátí nejmenší uzel v pravém podstromu - Pokud tomu tak není, pak jsou 2 možnosti: - Daný uzel je vlevo dítě nadřazeného uzlu. Pokud ano, vrátí nadřazený uzel. V opačném případě je daný uzel je právo dítě nadřazeného uzlu. Pokud ano, vrátí správné dítě nadřazeného uzlu
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;
}
}
Přitom v Javě
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);
}
}
To můžeme rozdělit do 3 případy:
V případě, že uzel je rodič: V tomto případě jsme se zjistit, zda má správnou uzel a přejít na zcela vlevo dítě pravého uzlu. V případě, že pravý uzel nemá děti, pak vpravo uzel je jeho nezbytného nástupce. Pokud není k dispozici správná uzel musíme přesunout do stromu najít nezbytného nástupce.
V případě, že uzel je vlevo dítě: V tomto případě je rodič je nezbytného nástupce.
V případě, že uzel (nazvat x) je právo dítě (jeho bezprostředním mateřským podnikem): jsme procházet na strom, dokud nenajdeme uzel, jehož levý podstrom má x.
Extrémním případem: Pokud uzel je nejvíce vpravo rohový uzel není nezbytného nástupce.
Každý „tutorial“, že jsem se díval na google a všechny odpovědi v tomto vlákně používá následující logiku: " Pokud uzel nemá správné dítě pak jeho in-pořadí nástupcem se stane jedním z jeho předků Použití rodič odkaz držet na cestách až do. dostanete uzlu, který je na levé dítě jeho rodiče. Pak se tento rodič uzel bude nástupcem in-pořadí. "
To je stejné jako myšlení „pokud má rodič je větší než já, pak já jsem tou levou dítě “ (vlastnost binárního vyhledávacího stromu). To znamená, že můžete jednoduše jít do nadřazené řetěz až do výše vlastnost je pravda. Který ve svých výsledcích mínění v elegantnější kódu.
Myslím, že důvod, proč je každý běžný „ já jsem opustil dítě “ při pohledu na pobočkách namísto hodnot v cestě kódu, který využívá odkazy rodiče pochází z „výpůjčky“ logiky z algoritmu no-link-to-rodič.
Také z přiloženého kódu níže můžeme vidět není žádná potřeba pro datové struktury zásobníku , jak navrhuje další odpovědi.
Následující jednoduchý C funkce ++, která funguje pro užitných případech (s a bez použití odkaz na rodiče).
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 implementace # (Non rekurzivní!) Najít ‚NEXT‘ uzel daného uzlu v binárním vyhledávacím stromu, kde každý uzel má odkaz na své mateřské společnosti.
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);
}
Můžeme najít nástupce v O (log n) bez použití nadřazených ukazatele (pro vyvážený strom).
Myšlenka je velmi podobný tomu, když máte nadřazené ukazatele.
Můžeme definovat rekurzivní funkci, která dosahuje to následujícím způsobem:
- Pokud je aktuální uzel je cíl, vrátit nejvíce vlevo / nejmenší uzel pravém podstromu, pokud existuje.
- Recurse opustil v případě, že cíl je menší než aktuální node, a v pořádku, pokud je to větší.
- V případě, že cíl je na levé straně a my jsme nenašli nástupce přesto, vrátí aktuální uzel.
Pseudo kód:
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 dont potřeba mateřský odkaz nebo stoh najít v pořadí nástupce v O (log n) (za předpokladu, že vyvážený strom). Zachovat dočasné proměnné s poslední hodnotou vyskytly při nezbytného průchod, který je větší, než je klíč. v případě nezbytného traversal zjistí, že uzel nemá správné dítě, pak by to bylo nezbytného nástupce. jinde, nejvíce vlevo potomek pravého dítěte.













