Având în vedere un nod într-un BST, cum o găsi următoarea cheie mai mare?
În Succesor în binar de căutare Arbore
Verificați aici: Inorder Succesor într - un copac binar de căutare
În arbore binar, Inorder succesor al unui nod este următorul nod în Inorder parcurgeri de arbore binar. Inorder Succesor este nul pentru ultimul nod în Inoorder traversal. În binar de căutare Arbore, Inorder Succesor al unui nod de intrare poate fi, de asemenea, definit ca nodul cu cea mai mică cheie mai mare decât cheia nodului de intrare.
Modul în general, depinde de faptul dacă aveți o legătură părinte în nodurile sau nu.
Dacă păstrați legătura părinte
Apoi alegeți:
- Cea mai la stînga copil al copilului drept, în cazul în care nodul curent are un copil drept. În cazul în care copilul nu are dreptul nici un copil din stânga, copilul dreapta este succesorul dumneavoastră inordine.
- Navigați în sus nodurile strămoș părinte, și atunci când găsești un părinte al cărui copil stânga este nodul pe care ești în prezent la, părintele este succesorul inorder al nodului original.
Dacă aveți copil drept, face această abordare (caz 1 de mai sus):

Dacă nu aveți un copil drept, face această abordare (cazul 2 de mai sus):

Dacă nu păstrați legătura părinte
Apoi, aveți nevoie pentru a rula o scanare completă a arborelui, păstrând evidența nodurilor, de obicei cu o stivă, astfel încât să aveți informațiile necesare pentru a face practic la fel ca și prima metodă care sa bazat pe link-ul părinte.
sursa de către utilizator Lasse Vågsæther Karlsen
Iată o punere în aplicare, fără a fi nevoie de legături părinte sau structuri intermediare (cum ar fi o stivă). Această funcție succesor în ordine este un pic diferit de ceea ce s-ar putea să fie mai căutați, deoarece funcționează pe tasta, spre deosebire de nodul. De asemenea, se va găsi un succesor al unei taste, chiar dacă nu este prezentă în copac. Nu este prea greu pentru a schimba dacă este necesar să, cu toate acestea.
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));
}
}
}
Cu binar de căutare copac, algoritmul pentru a găsi următorul cel mai mare nod al unui nod dat este de a găsi practic cel mai mic nodul de sub-arborele drept al acelui nod.
Algoritmul poate fi doar simplu:
- Începeți cu copilul dreapta al nodului dat (acesta nodul curent temporar face)
- Dacă nodul curent nu are nici un copil din stânga, este următorul cel mai mare nod.
- Dacă nodul curent are un copil stânga, este nodul curent face.
Se repetă 2 și 3 până când vom găsi următorul cel mai mare nod.
Python la Lasse a răspuns :
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
Soluție C ++ presupunând Nodurile au stânga, dreapta, și indicii mamă:
Aceasta ilustrează funcția Node* getNextNodeInOrder(Node)care returnează următoarea cheie a arborelui binar de căutare în ordine.
#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;
}
Care printuri:
1 2 3 4 5 6 7 8 9 10 11
unit tests:
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Puteți citi informații suplimentare aici (Rus pulmonar)
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
Aceste răspunsuri toate par mult prea complicate pentru mine. Noi chiar nu au nevoie de indicii mamă sau structuri de date auxiliare, cum ar fi o stivă. Tot ce trebuie să facem este traversa copacul de la rădăcină în ordine, a stabilit un pavilion de îndată ce vom găsi nodul țintă, iar următorul nod din arborele pe care vom vizita va fi în nodul ordine succesor. Aici este o rutină rapid și murdar am scris în sus.
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);
}
Dacă vom efectua o în ordine traversal, atunci vom vizita subarborele stânga, apoi nodul rădăcină și în cele din urmă subarborelui drept pentru fiecare nod din arbore. Efectuarea unei pentru parcurgeri ne va da cheile unui arbore binar de căutare, în ordine crescătoare, astfel încât atunci când ne referim la preluarea în succesoare ordinea unui nod care aparține unui arbore binar de căutare ne referim la ceea ce ar fi următorul nod în secvența de la dat nodul.
Să presupunem că avem un nod R si dorim sa în ordine succesoare vom avea următoarele cazuri.
[1] Rădăcina R are un nod drept, asa ca tot ce trebuie să facem este să traverseze la cel mai nodul stânga al R-> dreapta.
[2] Rădăcina R nu are nici un nod drept, în acest caz , vom traversa din nou în sus copac urmând link - urile părinte până când nodul R este un copil stâng al părintelui său, atunci când se întâmplă acest lucru avem nodul părinte P ca și în succesoare ordine .
[3] Suntem la nodul de extremă dreapta de copac, în acest caz , nu există nici un succesor se află în ordine.
Implementarea se bazează pe următoarea definiție nod
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);
}
Soluție JavaScript - În cazul în care nodul dat are un nod dreapta, apoi se întoarce cel mai mic nodul din subarborelui drept - Dacă nu, atunci există 2 posibilități: - nodul dat este un copil stânga al nodului părinte. Dacă da, întoarceți nodul părinte. În caz contrar, nodul dat este un copil drept al nodului părinte. Dacă da, întoarce copilul dreapta al nodului părinte
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;
}
}
Făcând acest lucru în 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);
}
}
Putem împărți acest lucru în 3 cazuri:
În cazul în care nodul este un părinte: În acest caz, vom afla dacă are un nod drept și traversează spre stânga copil al nodului drept. În cazul în care nodul din dreapta nu are copii, atunci nodul dreapta este succesorul său inordine. Dacă nu există nici un nod drept trebuie să se deplaseze în sus copac pentru a găsi succesorul inordine.
În cazul în care nodul este un copil stânga: În acest caz, părintele este succesorul inordine.
Dacă nodul (numesc x) este un copil drept (a societății-mamă imediate): Am traversa copacul până când vom găsi un nod al cărui subarbore stâng are de x.
caz extrem: Dacă nodul este nodul de colț din dreapta, nu există nici un succesor inordine.
Fiecare „tutorial“ pe care am verificat pe Google și toate răspunsurile în acest thread folosește următoarea logică: " Dacă nodul nu are un copil chiar atunci succesorul său în ordine va fi unul dintre strămoșii săi folosind link - ul părinte păstrează călătoresc până. veți obține nodul care este copilul stâng al părintelui său. Apoi , acest nod părinte va fi în ordine succesor. "
Acest lucru este la fel ca și de gândire „în cazul în care mama mea este mai mare decât mine, atunci eu sunt copilul din stânga “ (proprietate a unui arbore binar de căutare). Acest lucru înseamnă că puteți merge pur și simplu lanțul părinte până proprietatea de mai sus este adevărată. Care din rezultatele mele de opinie într - un cod mai elegant.
Cred că motivul pentru care toată lumea este de verificare „ sunt eu copilul lăsat “ de privirea de la sucursale în loc de valori din calea de cod care utilizeaza link - uri părinte provine de la „împrumut“ logica de algoritmul nu-link-părinte.
De asemenea , din codul inclus mai jos putem vedea nu este nevoie de structuri de date stiva după cum a sugerat alte răspunsuri.
In urma este o funcție simplă de C ++, care funcționează pentru ambele cazuri de utilizare a-(cu și fără a utiliza link-ul de la mamă).
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 # implementare (non recursiv!) Pentru a găsi nodul „următor“ dintr-un anumit nod într-un arbore binar de căutare în cazul în care fiecare nod are o legătură către societatea mamă.
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);
}
Putem găsi succesorul în O (log n) fără a utiliza indicii părinte (pentru un arbore echilibrat).
Ideea este foarte similar cu atunci când ai indicii părinte.
Putem defini o funcție recursivă care realizează acest lucru, după cum urmează:
- Dacă nodul curent este ținta, întoarce nodul cel mai din stânga / cea mai mică din subarborele sau dreapta, dacă există.
- Recurse stânga dacă ținta este mai mică decât nodul curent, și la dreapta dacă este mai mare.
- În cazul în care obiectivul este de la stânga și nu am găsit un succesor încă, a reveni nodul curent.
Pseudo cod:
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
nu avem nevoie de link-ul părinte sau stivă pentru a găsi o în ordine succesoare în O (log n) (presupunând arbore echilibrat). Păstrați o variabilă temporară cu valoarea cea mai recentă întâlnită în traversal inordine, care este mai mare decât cheia. în cazul în care constată că inordine traversal nodul nu are un copil drept, atunci acest lucru ar fi succesorul inordine. altfel, cel mai din stânga descendent al copilului drept.













