Учитывая узел в BST, как можно найти следующий более высокий ключ?
В Преемник заказа в бинарном дереве поиска
Проверьте здесь: заказовМой Преемник в бинарном дереве поиска
В бинарном дереве, Симметричный преемник узла является следующим узлом в заказовМой обходе бинарного дерева. Симметричного Преемник является NULL для последнего узла в Inoorder обходе. В бинарном дереве поиска, Симметричного Преемник входного узла также может быть определен как узел с наименьшим ключом больше, чем ключ узла ввода.
Общий способ зависит от того, есть ли у вас родительская ссылка в ваших узлах или нет.
Если вы храните родительскую ссылку
Затем вы выбираете:
- Крайний левый ребенок правого ребенка, если текущий узел имеет правильный ребенок. Если право ребенка не имеет левого ребенка, право ребенка Ваш Симметричного преемник.
- Перемещаться предком узлов родителя, и когда вы нашли родитель, чьи левый ребенок узел вы в настоящее время, родитель является преемником Симметричного исходного узла.
Если у вас есть правильный ребенок, сделать этот подход (случай 1 выше):

Если вы не имеете права ребенка, делает этот подход (случай 2 выше):

Если вы не храните родительскую ссылку
Затем вам нужно запустить полное сканирование дерева, отслеживание узлов, как правило, со стеком, так что у вас есть информация, необходимые в основном то же самое, как первый метод, который опирался на родительской ссылке.
Вот реализация без необходимости родительских связей или промежуточных структур (например, стек). Эта функция правопреемником по заказу немного отличается от того, что большинство может искать, так как он работает на ключе, в отличие от узла. Кроме того, он будет найти преемника ключа, даже если его нет в дереве. Не слишком трудно изменить, если вам необходимо, однако.
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));
}
}
}
С бинарным деревом поиска, алгоритм, чтобы найти следующий самую высокий узел данного узла, в основном, найти наималейший узел правого поддерева этого узла.
Алгоритм может быть просто просто:
- Начните с правым ребенком данного узла (сделать это временный текущий узлом)
- Если текущий узел не имеет левого ребенка, это следующий самый высокий узел.
- Если текущий узел имеет левый ребенок, сделать его текущий узел.
Повторите 2 и 3, пока мы не найдем следующий самый высокий узел.
Python код в Лассе в ответ :
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 ++ при условии, узлы слева, справа, и родительские указатели:
Это иллюстрирует функцию , Node* getNextNodeInOrder(Node)которая возвращает следующий ключ двоичного дерева поиска в заказе.
#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;
}
Что печатает:
1 2 3 4 5 6 7 8 9 10 11
unit tests:
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09
Вы можете прочитать дополнительную информацию здесь (Рус легких)
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
Эти ответы все, кажется слишком сложным для меня. Мы действительно не нужны родительские указатели или любые вспомогательные структуры данных, как стек. Все, что нам нужно сделать, это пройти по дереву от корня упорядоченного, установите флаг, как только мы находим целевой узел, и следующий узел в дереве, который мы посещаем буду для того правопреемника узла. Вот быстрая и грязная рутина я написал.
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);
}
Если выполнить в порядке обхода, то мы посещаем левое поддерево, затем корневой узел и, наконец, правое поддерево для каждого узла в дереве. Выполнение в порядке обходе даст нам ключи двоичного дерева поиска в порядке возрастания, поэтому, когда мы ссылаемся на извлечение в порядке правопреемника узла, принадлежащий бинарное дерево поиска мы имеем в виду то, что будет следующий узел в последовательности от данный узел.
Допустим, у нас есть узел R, и мы хотим его в порядке правопреемника мы имели бы следующие случаи.
[1] Корень R имеет правый узел, поэтому все , что нам нужно сделать , это пройти к крайнему левому узлу R-> вправо.
[2] Корень R не имеет правильный узла, в этом случае мы пересекаем обратно вверх по дереву следующих родительских ссылок , пока узел R не является левым потомком своего родителя, когда это происходит , мы имеем родительский узел P в качестве в порядке преемнике ,
[3] Мы не в крайнем правом узле дерева, в данном случае не существует в порядке преемника.
Реализация основана на следующем определении узла
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 - Если данный узел имеет правильный узел, а затем возвращает наименьший узел в правом поддереве - Если нет, то есть 2 возможности: - Данный узел является левым потомком родительского узла. Если это так, возвращает родительский узел. В противном случае, данный узел является правым потомком родительского узла. Если это так, верните правую ребенка родительского узла
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
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);
}
}
Мы можем разделить это в 3-х случаях:
Если узел является родителем: В данном случае мы видим, если он имеет правильный узел и траверс левого ребенок правого узла. В случае, если право узел не имеет детей, то правый узел является его преемником Симметричного. Если нет правильного узла нам нужно двигаться вверх по дереву, чтобы найти заказовМои преемника.
Если узел является левым потомком: В этом случае родитель является преемником Симметричного.
Если узел (назовем его х) является правом ребенка (его непосредственного родителя): Мы траверс вверх по дереву, пока мы не найдем узел, чье левое поддерево имеет х.
Крайний случай: Если узел является крайним правым углом узла, нет симметричного преемника.
Каждый «учебник» , что я проверил на Google и все ответы в этой теме используется следующая логика: " Если узел не имеет правильный ребенка , то его в заказ преемник будет один из его предков Использования родительской ссылки держать путешествие вверх до тех пор. вы получаете узел , который является левым потомком своего родителя. Затем этот родительский узел будет преемником в заказе. "
Это то же самое , как думать « если мой родитель больше , чем у меня, то я левый ребенок » (свойство бинарного дерева поиска). Это означает , что вы можете просто идти вверх по родительской цепочке , пока выше свойство не верно. Что в моих результатах общественного мнения в более элегантный код.
Я думаю , причина , почему все проверки « я слева ребенок », глядя на ветвях вместо значений в пути кода , который использует родительские ссылки происходит от «заимствования» логики от алгоритма нет-канальном к родителю.
Кроме того, из включенного кода ниже мы можем видеть , что нет никакой необходимости в структуре данных стека , как предложено другие ответы.
Ниже приводится простая функция C ++, которая работает для обоих сценариев использования (с и без использования ссылки на родителя).
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 # реализация (не рекурсивный!), Чтобы найти «следующий» узел данного узла в бинарном дереве поиска, где каждый узел имеет связь с его родителем.
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);
}
Мы можем найти преемник в O (журнал N) без использования родительских указателей (для сбалансированного дерева).
Идея очень похожа, когда у вас есть родительские указатели.
Мы можем определить рекурсивную функцию, которая достигает этой цели следующим образом:
- Если текущий узел является объектом, возвращает самый левый / наименьший узел его правого поддерева, если он существует.
- Recurse влево, если цель меньше, чем текущий узел, и право, если оно больше.
- Если цель находится слева, и мы не нашли преемника еще, возвращает текущий узел.
Псевдо-код:
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
нам не нужно родительское ссылку или стек, чтобы найти в порядке правопреемника в O (журнал N) (при условии, сбалансированное дерево). Держите временную переменную с последним значением, встречающегося в заказовМои обходе, который больше, чем ключ. если Симметричный обход обнаруживает, что узел не имеет правильный ребенок, то это будет Симметричным преемник. еще, крайний левый потомок правого ребенка.













