【问题标题】:Binary Search Tree In-order traversal without recursion or additional data structures二叉搜索树无递归或额外数据结构的按序遍历
【发布时间】:2023-11-08 00:08:02
【问题描述】:

如果二叉搜索树中的节点有指向其父节点的指针,是否可以在不需要递归或其他数据结构的情况下进行中序遍历?

【问题讨论】:

  • 这个问题不适合 Stack Overflow,所以让我在他们关闭它之前回答它。答案是:是的,有可能。
  • 你能给我看看吗?
  • 实际上是否有指向父节点的指针并不重要。这里应该有几个例子不是如何做到这一点的。
  • 如果没有父指针,您可能必须构建一些额外的结构。如果你称它为堆栈或其他东西都没关系。使用父指针,您只需要根据您来自哪里的信息来决定下一步该做什么和去哪里。如果您来自父母,请向左走。如果您来自左孩子打印父母并向右走。如果您来自正确的孩子,请去找父母。如果 parent 为 null,我们就完成了。
  • 感谢辩证法。我也是这么想的,但我正在努力建立一个有效的算法。如果您知道实现并且可以分享它,那就太好了。谢谢

标签: algorithm traversal


【解决方案1】:

在遍历过程中跟踪前一个节点,这将有助于决定下一步走哪条路。

在 C# 中:

class Node {
    /* ... */
    public void inorder() {
        Node curr = this;
        Node prev = null;
        Node next = null;
        while (curr != null) {
            if (curr.right != null && prev == curr.right) {
                next = curr.parent;
            } else if (curr.left == null || prev == curr.left) {
                Console.WriteLine(curr.data);  // <-- visit the node.
                next = curr.right != null ? curr.right : curr.parent;
            } else {
                next = curr.left;
            }
            prev = curr;
            curr = next;
        }
    }
};

在 C++ 中它可能如下所示:

void inorder(Node* root) {
    Node * curr = root;
    Node * prev = NULL;
    Node * next = NULL;
    while (curr != NULL) {
        if (curr->right != NULL && prev == curr->right) {
            next = curr->parent;
        } else if (curr->left == NULL || prev == curr->left) {
            cout << curr->data << " ";  // <-- visit the node.
            next = curr->right != NULL ? curr->right : curr->parent;
        } else {
            next = curr->left;
        }
        prev = curr;
        curr = next;
    }
    cout << "\n";
}

【讨论】:

    【解决方案2】:

    要获得第一个节点,您只需从根开始并尽可能向左走。

    从任意节点到下一个节点:

    • 如果节点有右孩子,则向右走,然后尽可能向左走。
    • 否则,请按照父指针向上直到到达右侧的祖先(即,您从左孩子到达那里)

    当你从根部向上时,你就完成了。

    【讨论】:

    • 感谢马特。你有一个编码示例给我看吗?
    【解决方案3】:

    这是一个小例子。

    Map<TreeNode,TreeNode> parent; // available 
    
    Set<TreeNode> set = new HashSet<>(); // maintain visited nodes
    
    TreeNode curr = root;
    
    while(curr!=null){
    
      if(!set.contains(curr.left) && curr.left!=null){
         curr = curr.left;
      }else if(!set.contains(curr.right) && curr.right!=null){
         System.out.print(curr.value+" ");
         curr = curr.right;
      }else{
         if(curr.right==null){
            System.out.print(curr.value+" ");
         }
         set.add(curr); // mark it as completely visited
         curr = parent.get(curr);
      }
    }
    

    【讨论】:

    • 好的开始,现在请消除对Map&lt;&gt;Set&lt;&gt; 的需要:)