Bir BST bir düğüm önüne alındığında, nasıl bir sonraki daha yüksek anahtarını bulur?
İkili Arama Ağacı sipariş Halef ise
Burada göz atın: Inorder Halef bir ikili arama Ağacında
İkili Ağacı olarak, bir düğümün Inorder halefi İkili Tree Inorder kastetmek sonraki düğümdür. Inorder Halef Inoorder kastetmek son düğüm için NULL olur. İkili Arama Ağacı olarak, bir giriş düğümü Inorder Halef de girdi düğümün anahtarından büyükse küçük anahtarla düğüm olarak tanımlanabilir.
Genel yolu, düğümler ya da değil bir üst bağlantısı var olup olmamasına bağlıdır.
Üst bağlantı saklıyorsanız
Sonra almak:
- Sağ çocuğun en soldaki çocuk, geçerli düğüm bir sağ çocuğu varsa. Sağ çocuk hiçbir sol çocuğu varsa, sağ çocuk senin inorder halefi olduğunu.
- ebeveyn atası düğümlerini yukarı gidin ve kimin sol çocuk şu anda bulunduğunuz düğüm olan bir ebeveyne bulduğunda, ebeveyn orijinal düğümün inorder halefi olduğunu.
Doğru çocuğunuz varsa, bu yaklaşımı (yukarıdaki durum 1) yapın:

Bir dik çocuğu yoksa, bu yaklaşımı (yukarıdaki durum 2) yapın:

Üst bağlantıyı saklamak yoksa
Gerekli temelde üst bağlantıyı dayanıyordu ilk yöntem olarak aynı şeyi bilgilere sahip olmamız Sonra, genellikle bir yığın ile, düğümlerin takibi, ağacın tam tarama çalıştırmak gerekir.
İşte ana bağlantıları ya da (bir yığın gibi) ara yapılar için gerek kalmadan bir uygulama bu. Bu in-order halefi işlevi düğüm aksine tuş üzerinde çalışır beri arıyor olabilir en şeye biraz farklıdır. o ağaçta mevcut değilse bile Ayrıca, bir anahtarın bir halef bulacaksınız. Eğer gerekirse çok zor değil ancak değiştirmek için.
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));
}
}
}
İkili Arama Ağacı ile, algoritma belirli bir düğümün sonraki en yüksek düğüm temelde bu düğümün sağ alt ağacın en düşük düğümü bulmaktır bulmak için.
Algoritma sadece basit olabilir:
- Verilen düğümün sağ çocuğu ile başlayın (geçici akım düğüm olun)
- Geçerli düğüm hiçbir sol çocuğu varsa, bir sonraki en yüksek düğümdür.
- Geçerli düğüm bir sol çocuğu varsa, geçerli düğüm olun.
bir sonraki en yüksek düğümü buluncaya kadar 2 ve 3 tekrarlayın.
Lasse en Python kodu cevap :
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
Düğümleri varsayarak C ++ çözüm sağ, sol, ve ebeveyn işaretçileri adres:
Bu fonksiyon göstermektedir Node* getNextNodeInOrder(Node)içinde sipariş ikili arama ağacının yanındaki anahtarı döndürür.
#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;
}
Hangi baskılar:
1 2 3 4 5 6 7 8 9 10 11
unit tests:
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Ek bilgi okuyabilir burada (Rus akciğer)
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
Bu cevaplar hepsi bana aşırı karmaşık görünüyor. Biz gerçekten ebeveyn işaretçileri veya yığını gibi herhangi bir yardımcı veri yapılarını gerek yoktur. Yapmamız gereken tek şey biz hedef düğümü bulur bulmaz bir bayrak içinde sipariş kökünden gelen ağaç ve biz sipariş halefi düğümünde olacak ziyaret ağaçta sonraki düğümü çapraz olduğunu. Benım yazdım hızlı ve kirli rutindir.
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);
}
Biz sipariş kastetmek bir gerçekleştirirseniz o zaman ağaçtaki her düğüm için sol alt ağaç, daha sonra kök düğümü ve son olarak sağ alt ağacı ziyaret edin. Sipariş kastetmek bir gerçekleştirme bize artan sırada bir ikili arama ağacının anahtarlarını vermek, bu yüzden biz dan dizideki bir sonraki düğüm ne olacağını demek bir ikili arama ağacına ait bir düğüm sırası halefi alınırken bakın ne zaman olacak belirli bir düğümün.
Biz bir düğüm R var ve biz onun emri halefi biz şu durumlarda olurdu istiyorum Diyelim.
[1] kök R 'bu yüzden yapmak gerekir tamam> R- en sol düğümüne hareket için, doğru bir düğüm vardır.
[2] kök R biz sipariş halefi olduğu gibi üst düğüm P var oluştuğunda, biz düğüm R üst biriminin sol alt olana kadar üst bağlantıları takip ağacın geri çapraz bu durumda hiçbir hak düğüm vardır .
[3] Biz sipariş halefi hiçbir orada bu durumda, ağacın aşırı sağ düğüm altındadır.
uygulaması aşağıdaki düğüm tanımlanmasına dayanmaktadır
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 çözümü - Verilen düğümü sağ düğüm varsa, sağ ağaca en küçük düğüm dönmek - Değilse, sonra 2 olasılık vardır: - Belirtilen düğüm üst düğümün sol çocuğudur. Eğer öyleyse, ebeveyn düğüm döner. Aksi takdirde, verilen düğüm üst düğümün sağ çocuğu. Eğer öyleyse, ebeveyn düğümün sağ çocuğu dönmek
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 Bunu yapmak
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);
}
}
Biz 3 durumlarda bu bölebilirsiniz:
Düğüm bir ebeveyn ise: o doğru düğüm varsa bu durumda biz bulup doğru düğümün en soldaki çocuğa geçiş. durumda sağ düğüm doğru düğüm onun inorder halefi o zaman hiçbir çocuk babasıdır. hiçbir doğru düğüm varsa biz inorder halef bulmak için ağaç yukarı taşımak gerekir.
Düğüm sol alt ise: Bu durumda ebeveyn inorder halefi olduğunu.
Düğüm (o x call) (onun hemen ebeveynin) sağ alt ise: biz kimin sol alt ağaç x olan bir düğüm bulana kadar ağaca çapraz.
Aşırı durum: düğüm en sağdaki köşe düğüm ise, hiçbir inorder halefi yoktur.
Ben bu iplik google ve tüm cevapların kontrol Her "öğretici" aşağıdaki mantığı kullanır: " düğüm daha sonra sağ çocuğu yoksa onun içinde sipariş halefi ebeveyn bağlantı kadar seyahat tutmak kullanma atalarından biri olacak. Eğer üst biriminin sol çocuğudur düğüm. O zaman bu üst düğüm içinde sipariş halefi olacak olsun. "
Bu "düşünce aynıdır benim ebeveyn benden daha büyük ise, o zaman ben sol çocuğuyum " (ikili arama ağacının özelliği). Bu, yukarıda özellik doğrudur kadar sadece üst zincirinden yürümek anlamına gelir. Daha şık bir kod Bence sonuçlarında hangi.
Herkesin "kontrol ediyor nedenini tahmin Ben sol çocuğuyum yerine no-link-to-ebeveyn algoritmadan "borçlanma" mantık gerektirir ebeveyn bağlantıları kullanan kod yolundaki değerlerin dalları bakarak".
Ayrıca görebildiğimiz aşağıda yer koddan var yığın veri yapısı gerek diğer cevaplar önerdiği gibi.
Aşağıdaki (ve ebeveyne bağlantıyı kullanarak olmadan) hem kullanım senaryoları için çalışan basit bir C ++ işlevidir.
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 # uygulaması (Non özyinelemeli!) Her düğüm için üst bağlantı içeren bir ikili arama ağacında belirli bir düğümün 'next' düğümü bulmak için.
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);
}
Biz (dengeli bir ağaç için) ana işaretçileri kullanmadan O (log n) 'de halefi bulabilirsiniz.
Fikir ebeveyn işaretçileri varken çok benzer.
Biz şöyle başarır tekrarlamalı bir fonksiyon tanımlayabilirsiniz:
- Geçerli düğüm hedef ise varsa, onun sağ alt ağacının en soldaki / en küçük düğümünü döndürür.
- Hedef o büyük ise akım düğümün daha küçük ve doğru ise Recurse bıraktı.
- Hedef sola ve biz henüz bir ardıl bulamadıysanız, cari düğümü döndürür.
Sözde 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
Biz ebeveyn bağlantısına ihtiyacınız yoksa (dengelenmiş ağaç varsayarak) (n günlük) O sipariş halefi bulmak yığını yok. tuşunun büyükse inorder kastetmek karşılaşılan en son değere sahip geçici bir değişken tutun. inorder geçişi düğümü sağ çocuğu yok bulursa, o zaman bu inorder halefi olacaktır. Başka sağ çocuğun en soldaki soyundan.













