【问题标题】:In Order Successor in Binary Search Tree二叉搜索树中的顺序后继
【发布时间】:2011-07-25 05:03:56
【问题描述】:

给定 BST 中的一个节点,如何找到下一个更高的键?

【问题讨论】:

  • if (node->right) return min_tree(node->right);如果节点没有右子树怎么办?

标签: algorithm data-structures tree binary-search-tree


【解决方案1】:

一般来说,使用order statistic tree 可以在 O(log n) 时间内完成对树中第 n 个最小(顺序统计)元素的查询。一种实现是在GNU's C++ extensions: Policy-Based Data Structures 中。用法见this CodeForces blog

实现这一点的方法是简单地在自平衡树的每个节点上存储一个附加值,即以该节点为根的子树的大小。然后操作Select(i)找到第i个最小元素和Rank(x)找到索引使得x是第i个最小元素可以以对数时间复杂度实现;请参阅 CLRS 或 Wikipedia 页面。那么查询就是Select(Rank(x)+1)

【讨论】:

    【解决方案2】:

    好吧,我会试一试,因为每个人都在发布他们的实现。该技术来自《算法简介》一书。基本上,您需要一种从子节点回溯到父节点的方法。

    首先,你需要一个类来表示节点:

    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) + "]";
        }
    }
    

    你可以有另一个类来运行操作:

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

    寻找访问器的思路是:

    • 如果右子树不为空,则求右子树中的最小值。
    • 否则,请继续沿树向上,直到到达其父节点的左子节点。

    而寻找前任,反之亦然。

    您可以在我的 GitHub in this package 上找到完整的工作示例。

    【讨论】:

      【解决方案3】:

      Python 代码到 Lasse 的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
      

      【讨论】:

        【解决方案4】:
        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;
        }
        

        【讨论】:

          【解决方案5】:

          我们不需要父链接或堆栈来找到 O(log n) 中的顺序后继(假设平衡树)。 保留一个临时变量,其中包含在中序遍历中遇到的大于键的最新值。如果中序遍历发现该节点没有右孩子,那么这将是中序后继。否则,右孩子的最左边的后代。

          【讨论】:

            【解决方案6】:

            我们可以在 O(log n) 中找到后继者,而无需使用父指针(对于平衡树)。

            这个想法与你有父指针时非常相似。

            我们可以定义一个递归函数来实现这一点,如下所示:

            • 如果当前节点是目标,则返回其右子树的最左/最小节点(如果存在)。
            • 如果目标小于当前节点,则向左递归,如果大于当前节点,则向右递归。
            • 如果目标在左侧并且我们还没有找到后继节点,则返回当前节点。

            伪代码:

            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.

            【讨论】:

              【解决方案7】:

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

              【讨论】:

                【解决方案8】:

                我在谷歌上查看的每个“教程”以及该线程中的所有答案都使用以下逻辑:“如果节点没有正确的孩子,那么它的有序后继者将是它的祖先之一。使用父链接一直向上移动,直到你得到它的父节点的左子节点。然后这个父节点将是有序的后继。"

                这与思考“如果我的父母比我大,那么我就是左孩子”(二叉搜索树的属性)是一样的。这意味着您可以简单地沿着父链向上走,直到上述属性为真。在我看来,这会产生更优雅的代码。

                我猜为什么每个人都通过查看分支而不是使用父链接的代码路径中的值来检查“我是左孩子吗”的原因来自于“借用”逻辑从 no-链接到父算法。

                此外,从下面包含的代码中,我们可以看到 不需要堆栈数据结构,正如其他答案所建议的那样。

                以下是一个简单的 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;
                    }
                }
                

                【讨论】:

                  【解决方案9】:

                  我们可以分为三种情况:

                  1. 如果节点是父节点:在这种情况下,我们查找它是否有右节点并遍历右节点的最左边的子节点。如果右节点没有子节点,则右节点是它的中序继任者。如果没有正确的节点,我们需要向上移动树以找到中序继任者。

                  2. 如果节点是左子节点:在这种情况下,父节点是中序继任者。

                  3. 如果节点(称为 x)是(其直接父节点的)右子节点:我们向上遍历树,直到找到其左子树具有 x 的节点。

                  极端情况:如果节点是最右角节点,则没有中序后继。

                  【讨论】:

                    【解决方案10】:

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

                    【讨论】:

                      【解决方案11】:

                      JavaScript 解决方案 - 如果给定节点有右节点,则返回右子树中最小的节点 - 如果不是,那么有两种可能性: - 给定节点是父节点的左子节点。如果是,则返回父节点。否则,给定节点是父节点的右子节点。如果是,则返回父节点的右孩子

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

                      【讨论】:

                        【解决方案12】:

                        如果我们执行顺序遍历,那么我们访问左子树,然后是根节点,最后是树中每个节点的右子树。 执行按顺序遍历将按升序为我们提供二叉搜索树的键,因此当我们提到检索属于二叉搜索树的节点的顺序后继时,我们的意思是序列中的下一个节点是什么给定的节点。

                        假设我们有一个节点 R,我们想要它的后继节点,我们会遇到以下情况。

                        [1]根R有一个右节点,所以我们需要做的就是遍历到R->right最左边的节点。

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

                        【讨论】:

                          【解决方案13】:

                          这些答案对我来说似乎都过于复杂。我们真的不需要父指针或任何辅助数据结构,如堆栈。我们需要做的就是从根开始按顺序遍历树,一旦找到目标节点就设置一个标志,我们访问的树中的下一个节点将是有序的后继节点。这是我写的一个快速而肮脏的例程。

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

                          【讨论】:

                          • 大 O 是 O(n),让我们做得更好。请参阅@Lasse V. Karlsen 的回答。
                          【解决方案14】:

                          您可以阅读更多信息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
                          

                          【讨论】:

                            【解决方案15】:

                            假设节点具有左、右和父指针的 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
                            

                            【讨论】:

                              【解决方案16】:

                              使用二叉搜索树,找到给定节点的下一个最高节点的算法基本上是找到该节点右子树的最低节点。

                              算法可以很简单:

                              1. 从给定节点的右子节点开始(使其成为临时当前节点)
                              2. 如果当前节点没有左子节点,则为下一个最高节点。
                              3. 如果当前节点有左孩子,则将其设为当前节点。

                              重复 2 和 3 直到找到下一个最高节点。

                              【讨论】:

                              • 在具有三个节点、一个父节点和两个子节点的树中,该算法在左子节点上会失败。它忽略了走回树上。
                              【解决方案17】:

                              这是一个不需要父链接或中间结构(如堆栈)的实现。这个有序的后继函数与大多数人可能正在寻找的有点不同,因为它对键而不是节点进行操作。此外,即使它不存在于树中,它也会找到密钥的后继者。不过,如果您需要,也不太难更改。

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

                              【讨论】:

                                【解决方案18】:

                                一般方式取决于您的节点中是否有父链接。

                                如果存储父链接

                                然后你选择:

                                1. 如果当前节点有右孩子,则为右孩子的最左孩子。如果右孩子没有左孩子,则右孩子是您的顺序继承人。
                                2. 向上导航父祖先节点,当您找到一个父节点的左子节点是您当前所在的节点时,该父节点就是您原始节点的顺序后继节点。

                                如果您有正确的孩子,请执行此方法(上面的案例 1):

                                如果您没有正确的孩子,请执行此方法(上面的案例 2):

                                如果不存储父链接

                                然后您需要运行树的完整扫描,跟踪节点,通常使用堆栈,以便您拥有基本执行与依赖父链接的第一个方法相同的必要信息。

                                【讨论】:

                                • 很好的答案!你能再解释一下第一种方法吗……再详细一点会很好。非常感谢。
                                • 只是想添加... 1. 基本上,右边向上直到父母的左边是孩子。但是,如果有权利。它会一直走到最右边的最左边!
                                • @Lasse V. Karlsen 如果您没有父指针,您仍然可以在 O(h) 时间内找到有序后继,其中 h 是树的高度。当您找到该节点时,请跟踪您从哪个节点步入左子节点的最后一个节点。当一个节点没有右孩子时,这个节点是有序的后继。如果一个节点有一个右孩子,则顺序后继是右子树中的最小节点。
                                • 同意@JohnKurlak 这是在没有父指针的情况下实现 Java 的要点。 gist.github.com/rcaloras/36f9e5f94f4334e0827c5b52ec0d8115
                                • @RCCola 这个解决方案与 JohnKurlak 的不太一样,因为它在右子树为空时从根开始搜索。这是一个 jsfiddle 示例,它跟踪最后一步离开的节点:jsfiddle.net/e3d8Lvu5/4
                                【解决方案19】:

                                在这里查看:InOrder Successor in a Binary Search Tree

                                在二叉树中,a 的中序后继 node 是 Inorder 中的下一个节点 二叉树的遍历。为了 中的最后一个节点的后继为 NULL 无序遍历。在二分搜索中 树,输入的顺序后继 节点也可以定义为节点 最小的键大于 输入节点的key。

                                【讨论】:

                                • 这个算法依赖于父链接,如果你没有,实现是完全不同的。
                                猜你喜欢
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2023-03-08
                                相关资源
                                最近更新 更多