【问题标题】:Help needed with InOrder iterator implementation for a tree树的 InOrder 迭代器实现需要帮助
【发布时间】:2011-08-17 04:13:31
【问题描述】:

我正在为家庭作业实现一个 InOrder 迭代器,这意味着迭代器会这样前进:

  • 拜访左孩子
  • 访问节点
  • 拜访右孩子

还有这些复杂性限制: 遍历整棵树的运行时间复杂度应该是 o(n),其中 n 是树中的节点数,内存复杂度应该是 o(h),其中 h 是树的高度。

我已经尝试使用这种方法来实现 Advance(++) 运算符:

Tree<DataT>::_InOrderIterator::operator++()
{
    TreeNode* node = this->Node->GetRightChild();
    while(node != NULL)
    {
        advanceStack.Push(node);
        node = node->GetLeftChild();
    }
    node = advanceStack.Pop();
    if (node == NULL)
    {
        node = end; //reserved end node
    }
    this->Node = node;
    return *this;
}

我还没有测试它,但我认为它应该可以正常工作。当我尝试实现后退 (--) 运算符时,我的问题就开始了。我最初的方法是拥有第二个堆栈:recedeStack,并以与 ++ 运算符相同的方式使用它。 但是我不知道如何使后退堆栈在 ++ 运算符中保持同步,反之亦然(--运算符中的 AdvanceStack)。无论如何,并非没有超出内存复杂性的限制。

关于如何解决这个问题的任何想法(使用我当前的实现或不使用)?

【问题讨论】:

  • 内存约束应该给你一个非常重要的线索:让它递归。画一棵树和图片子树。然后你会看到递归应该基于什么
  • @sehe:我实际上就是这样做的,这就是我得到第一个解决方案的方式。堆栈的使用是为了避免递归,因为在调用 ++ 运算符之间保持状态是一个主要问题。我想我只是没有看到如何在前进时更新后退数据

标签: c++ tree iterator inorder


【解决方案1】:
    //......    
       class Iterator{
              friend class BST<T>;
              stack<Node<T>*> stack;
              bool goLeft;
              Iterator(Node<T> *root):goLeft(true)
              {
                  stack.push(NULL);
                  stack.push(root);
              }
        public:

          const T &next()
            {
                Node<T> *curr = stack.top();
                if(curr == NULL) throw exception("The tree is empty");
                if(goLeft){
                    while(curr->left){
                        stack.push(curr->left);
                        curr = curr->left;
                    }
                    goLeft =false;
                }
                stack.pop();
                if(curr->right)
                {
                    stack.push(curr->right);
                    goLeft = true;
                }
                return curr->value;
            }


        };
//...

【讨论】:

    【解决方案2】:

    我在面试中遇到了类似的问题,并且可以找到解决方案。使用递归进行遍历很简单。为广度优先遍历编写迭代器很简单。但是为中序遍历编写一个迭代器对我来说是一个脑筋急转弯。因此,在对网络进行一些研究之后,我发现了一个很好的解决方案,其中包括过于冗长和相对复杂的解决方案。我的语言是 C#,但我希望将它翻译成其他语言并不难。 BinaryTreeNode 类具有 Data、Left、Right 属性,此处省略。

        public class BinaryTreeInorderIterator
        {
            #region Constructors
    
            public BinaryTreeInorderIterator(BinaryTreeNode aRoot)
            {
                Current = aRoot;
    
                if (Current == null)
                {
                    // The tree is empty.
                    return;
                }
    
                // Push the terminator.
                mNodeStack.Push(null);
    
                // To initialize inorder iterator go deep to the leftmost node of the left subtree 
                // of the root node along the way pushing nodes traversed so far.
                while (Current.Left != null)
                {
                    mNodeStack.Push(Current);
                    Current = Current.Left;
                }
            }
    
            #endregion
    
            #region Public properties
    
            public BinaryTreeNode Current { get; private set; }
    
            #endregion
    
            #region Public methods
    
            public bool Next()
            {
                if (Current == null)
                {
                    // Iterating finished already.
                    return false;
                }
    
                if (Current.Right != null)
                {
                    // There is right subtree.
                    // Go deep to the leftmost node of the left subtree 
                    // of the current node along the way pushing nodes traversed so far.
                    Current = Current.Right;
                    while (Current.Left != null)
                    {
                        mNodeStack.Push(Current);
                        Current = Current.Left;
                    }
                }
                else
                {
                    // There is no right subtree.
                    // Go a level up.
                    Current = mNodeStack.Pop();
                }
    
                return HasNext();
            }
    
            public bool HasNext()
            {
                return Current != null;
            }
    
            #endregion
    
            #region Private data
    
            private readonly Stack<BinaryTreeNode> mNodeStack = new Stack<BinaryTreeNode>();
    
            #endregion
        }
    

    【讨论】:

    • 这不起作用。如果没有右子树,你就不会上升,因为你已经在那里了。这会让你陷入无限循环。
    【解决方案3】:

    与其尝试手动实现递归算法(使用堆栈),不如将其编写为递归。更容易理解。就像访问左,节点,右一样简单。 (因为是作业,我就不多说了)。

    【讨论】:

    • 我想你错过了我的实际问题。如上所述,我需要实现一个迭代器,不仅要遍历整个树,因此我求助于堆栈使用。但我的实际困难是同时实现 -- 和 ++ 运算符。
    • @eladidan,插入时尝试保存每个节点的后继节点,就像保存其父节点一样保存其指针。那么实现++应该会更容易。
    猜你喜欢
    • 1970-01-01
    • 2013-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多