开发者

In Order Successor in Binary Search Tree

Given a node in a BST, how does one find the ne开发者_开发知识库xt higher key?


The general way depends on whether you have a parent link in your nodes or not.

If you store the parent link

Then you pick:

  1. The leftmost child of the right child, if your current node has a right child. If the right child has no left child, the right child is your inorder successor.
  2. Navigate up the parent ancestor nodes, and when you find a parent whose left child is the node you're currently at, the parent is the inorder successor of your original node.

If you have right child, do this approach (case 1 above):

In Order Successor in Binary Search Tree

If you don't have a right child, do this approach (case 2 above):

In Order Successor in Binary Search Tree

If you don't store the parent link

Then you need to run a complete scan of the tree, keeping track of the nodes, usually with a stack, so that you have the information necessary to basically do the same as the first method that relied on the parent link.


Python code to the Lasse's answer:

def findNext(node):
  # Case 1
  if node.right != None:
    node = node.right:
    while node.left:
      node = node.left
    return node

  # Case 2
  parent = node.parent
  while parent != None:
    if parent.left == node:
      break
    node = parent
    parent = node.parent
  return parent


Here's an implementation without the need for parent links or intermediate structures (like a stack). This in-order successor function is a bit different to what most might be looking for since it operates on the key as opposed to the node. Also, it will find a successor of a key even if it is not present in the tree. Not too hard to change if you needed to, however.

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));
    }
}
}


Check out here : InOrder Successor in a Binary Search Tree

In Binary Tree, Inorder successor of a node is the next node in Inorder traversal of the Binary Tree. Inorder Successor is NULL for the last node in Inoorder traversal. In Binary Search Tree, Inorder Successor of an input node can also be defined as the node with the smallest key greater than the key of input node.


With Binary Search Tree, the algorithm to find the next highest node of a given node is basically finding the lowest node of the right sub-tree of that node.

The algorithm can just be simply:

  1. Start with the right child of the given node (make it the temporary current node)
  2. If the current node has no left child, it is the next highest node.
  3. If the current node has a left child, make it the current node.

Repeat 2 and 3 until we find next highest node.


we dont need parent link or stack to find the in order successor in O(log n) (assuming balanced tree). Keep a temporary variable with the most recent value encountered in the inorder traversal that is larger than the key. if inorder traversal finds that the node does not have a right child, then this would be the inorder successor. else, the leftmost descendant of the right child.


C++ solution assuming Nodes have left, right, and parent pointers:

This illustrates the function Node* getNextNodeInOrder(Node) which returns the next key of the binary search tree in-order.

#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;
}

Which prints:

1 2 3 4 5 6 7 8 9 10 11

unit tests: 
passed01
passed02
passed03
passed04
passed05
passed06
passed07
passed08
passed09


You can read additional info here(Rus lung)

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


If we perform a in order traversal then we visit the left subtree, then root node and finally the right subtree for each node in the tree. Performing a in order traversal will give us the keys of a binary search tree in ascending order, so when we refer to retrieving the in order successor of a node belonging to a binary search tree we mean what would be the next node in the sequence from the given node.

Lets say we have a node R and we want its in order successor we would have the following cases.

[1] The root R has a right node, so all we need to do is to traverse to the left most node of R->right.

[2] The root R has no right node, in this case we traverse back up the tree following the parent links until the node R is a left child of its parent, when this occurs we have the parent node P as the in order successor.

[3] We are at the extreme right node of the tree, in this case there is no in order successor.

The implementation is based on the following node definition

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);
}


We can find the successor in O(log n) without using parent pointers (for a balanced tree).

The idea is very similar to when you have parent pointers.

We can define a recursive function that achieves this as follows:

  • If the current node is the target, return the left-most / smallest node of its right subtree, if it exists.
  • Recurse left if the target is smaller than the current node, and right if it's greater.
  • If the target is to the left and we haven't found a successor yet, return the current node.

Pseudo-code:

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

Live Java demo.


These answers all seem overly complicated to me. We really don't need parent pointers or any auxiliary data structures like a stack. All we need to do is traverse the tree from the root in-order, set a flag as soon as we find the target node, and the next node in the tree that we visit will be the in order successor node. Here is a quick and dirty routine I wrote up.

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);
}


JavaScript solution - If the given node has a right node, then return the smallest node in the right subtree - If not, then there are 2 possibilities: - The given node is a left child of the parent node. If so, return the parent node. Otherwise, the given node is a right child of the parent node. If so, return the right child of the parent node

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;
  }
}


Doing this in 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);
    }
}


We can divide this in 3 cases:

  1. If the node is a parent: In this case we find if it has a right node and traverse to the leftmost child of the right node. In case the right node has no children then the right node is its inorder successor. If there is no right node we need to move up the tree to find the inorder successor.

  2. If the node is a left child: In this case the parent is the inorder successor.

  3. If the node (call it x) is a right child (of its immediate parent): We traverse up the tree until we find a node whose left subtree has x.

Extreme case: If the node is the rightmost corner node, there is no inorder successor.


Every "tutorial" that I checked on google and all answers in this thread uses the following logic: "If node doesn't have a right child then its in-order suc­ces­sor will be one of its ances­tors. Using par­ent link keep traveling up until you get the node which is the left child of its par­ent. Then this par­ent node will be the in-order successor."

This is the same as thinking "if my parent is bigger than me, then I am the left child" (property of a binary search tree). This means that you can simply walk up the parent chain until the above property is true. Which in my opinion results in a more elegant code.

I guess the reason why everyone is checking "am I the left child" by looking at branches instead of values in the code path that utilizes parent links comes from "borrowing" logic from the no-link-to-parent algorithm.

Also from the included code below we can see there is no need for stack data structure as suggested by other answers.

Following is a simple C++ function that works for both use-cases (with and without utilizing the link to parent).

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# implementation (Non recursive!) to find the ‘next’ node of a given node in a binary search tree where each node has a link to its parent.

    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);
    }


Node successor(int data) {
  return successor(root, data);
}

// look for the successor to data in the tree rooted at curr
private Node successor(Node curr, int data) {
  if (curr == null) {
    return null;
  } else if (data < curr.data) {
    Node suc = successor(curr.left, data);
    // if a successor is found use it otherwise we know this node
    // is the successor since the target node was in this nodes left subtree
    return suc == null ? curr : suc;
  } else if (data > curr.data) {
    return successor(curr.right, data);
  } else {
    // we found the node so the successor might be the min of the right subtree
    return findMin(curr.right);
  }
}

private Node findMin(Node curr) {
  if (curr == null) {
    return null;
  }

  while (curr.left != null) {
    curr = curr.left;
  }

  return curr;
}


All right I will take a shot since everyone is posting their implementations. This technique is from Introduction To Algorithms book. Basically, you need a way to backtrack to parent nodes from child nodes.

First up, you need a class to represent nodes:

public class TreeNode<V extends Comparable<V>> {
    TreeNode<V> parent;
    TreeNode<V> left;
    TreeNode<V> right;
    V data;

    public TreeNode(TreeNode<V> parent, V data) {
        this.parent = parent;
        this.data = data;
    }

    public void insert(TreeNode<V> parent, V data) {
        if (data.compareTo(this.data) < 0) {
            if (left == null) {
                left = new TreeNode<>(parent, data);
            } else {
                left.insert(left, data);
            }
        } else if (data.compareTo(this.data) > 0) {
            if (right == null) {
                right = new TreeNode<>(parent, data);
            } else {
                right.insert(right, data);
            }
        }
        // ignore duplicates
    }

    @Override
    public String toString() {
        return data + " -> [parent: " + (parent != null ? parent.data : null) + "]";
    }
}

You can have another class to run the operations:

public class BinarySearchTree<E extends Comparable<E>> {

    private TreeNode<E> root;

    public void insert(E data) {
        if (root == null) {
            root = new TreeNode<>(null, data);
        } else {
            root.insert(root, data);
        }
    }

    public TreeNode<E> successor(TreeNode<E> x) {
        if (x != null && x.right != null) {
            return min(x.right);
        }
        TreeNode<E> y = x.parent;
        while (y != null && x == y.right) {
            x = y;
            y = y.parent;
        }
        return y;
    }

    public TreeNode<E> min() {
        return min(root);
    }

    private TreeNode<E> min(TreeNode<E> node) {
        if (node.left != null) {
            return min(node.left);
        }
        return node;
    }

    public TreeNode<E> predecessor(TreeNode<E> x) {
        if(x != null && x.left != null) {
            return max(x.left);
        }

        TreeNode<E> y = x.parent;
        while(y != null && x == y.left) {
            x = y;
            y = y.parent;
        }
        return y;
    }

    public TreeNode<E> max() {
        return max(root);
    }

    private TreeNode<E> max(TreeNode<E> node) {
        if (node.right != null) {
            return max(node.right);
        }
        return node;
    }

}

The idea of finding an accessor is:

  • if right-subtree is not null, find the minimum value in right-subtree.
  • else, keep going up the tree till you get to a node that's a left child of its parent.

And for finding a predecessor, it's vice versa.

You can find a complete working example on my GitHub in this package.


In general, queries about n-th smallest (order statistic) element in a tree can be achieved in O(log n) time using an order statistic tree. One implementation is in GNU's C++ extensions: Policy-Based Data Structures. See this CodeForces blog for usage.

The way this is achieved is simply by storing an additional value at each node of a self-balancing tree that is the size of the subtree rooted at that node. Then operations Select(i) which finds the i-th smallest element and Rank(x) which finds the index such that x is the i-th smallest element can be implemented in logarithmic time complexity; see CLRS or the Wikipedia page. Then the query is simply Select(Rank(x)+1).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜