二进制搜索树IEnumerator.MoveNext()在递遍实现时非递归.如何?

pij*_*olu 3 c# algorithm ienumerable enumerator binary-search-tree

在构建了一个BST<Tkey,TValue>BSTNode<Tkey,TValue>节点组成的二叉搜索树之后,我试图为它实现IEnumerable接口.

这就是我构建的方式BSTNodeEnumrator<Tkey,TValue>:

public class BSTNodeEnumerator<TKey, TValue> : IEnumerator<BSTNode<TKey, TValue>> where TKey : IComparable<TKey>
{
    private Stack<BSTNode<TKey, TValue>> _stack;

    public BSTNodeEnumerator(BSTNode<TKey, TValue> root)
    {
        _stack = new Stack<BSTNode<TKey, TValue>>();
        _current = null;
        _root = root;
    }

    // ... rest of the implementation
}
Run Code Online (Sandbox Code Playgroud)

我传入root节点并且_current是枚举的结果.我也试图使用堆栈,因为我不像AVL BST那样跟踪父节点.

现在我希望枚举器以非递归的方式按顺序遍历树.这应该导致排序的枚举,因为bst的属性,这是伟大的,因为这正是我想要实现的.

用于在伪代码中遍历的非递归算法,如本维基百科文章中所述

    iterativeInorder(node)
  s ? empty stack
  while (not s.isEmpty() or node ? null)
    if (node ? null)
      s.push(node)
      node ? node.left
    else
      node ? s.pop()
      visit(node)
      node ? node.right
Run Code Online (Sandbox Code Playgroud)

我们可以将算法转换为这个c#代码:

public BSTNode<Tkey,TValue> Next() 
{
   while (_stack.Count > 0 || _current != null) 
    {
         if (_current != null)
         {
          _stack.Push(_current);
          _current = _current.left;
         }
         else
         {
          _current = _stack.Pop();
          BSTNode<Tkey,TValue> result = _current;
          _current = _current.Right;
         }
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

但这不是必需的bool MoveNext()实现,因为我必须返回一个bool.如果我确实设置_current了适当的节点,则为True ,如果我在最后,则为false.

我该如何实施public bool MoveNext()?我无法解决的主要问题是,如果我想转换BSTNode<Tkey,TValue> Next()bool MoveNext()我必须return true而不是简单地访问节点,BSTNode<Tkey,TValue> result = _current;并且只有在那个_current = _current.Right;我显然不能做的设置之后.

Sco*_*ain 5

老实说,对于像这样的非trival枚举器,最好只使用.NET内置的工具.只需返回IEnumerator<BSTNode<Tkey,TValue>>并使用yield return关键字,它就可以自动将您编写的代码转换为枚举器,只需进行非常小的调整.

class BSTNode<TKey, TValue> : IEnumerable<BSTNode<TKey, TValue>>
     where TKey : IComparable<TKey>
{
    public IEnumerator<BSTNode<TKey, TValue>> GetEnumerator()
    {
        var stack = new Stack<BSTNode<TKey, TValue>>();
        var current = this;
        while (stack.Count > 0 || current != null)
        {
            if (current != null)
            {
                stack.Push(current);
                current = current.Left;
            }
            else
            {
                current = stack.Pop();
                yield return current;
                current = current.Right;
            }
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public BSTNode<TKey, TValue> Left { get; set; }

    public BSTNode<TKey, TValue> Right { get; set; }

    public TKey Key { get; set; }

    public TValue Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

如果你很好奇,这里是它在幕后制作的IEnumerator类的编译器生成代码

[CompilerGenerated]
  private sealed class <GetEnumerator>d__0 : IEnumerator<BSTNode<TKey, TValue>>, IDisposable, IEnumerator
  {
    private int <>1__state;
    private BSTNode<TKey, TValue> <>2__current;
    public BSTNode<TKey, TValue> <>4__this;
    private Stack<BSTNode<TKey, TValue>> <stack>5__1;
    private BSTNode<TKey, TValue> <current>5__2;

    BSTNode<TKey, TValue> IEnumerator<BSTNode<TKey, TValue>>.Current
    {
      [DebuggerHidden] get
      {
        return this.<>2__current;
      }
    }

    object IEnumerator.Current
    {
      [DebuggerHidden] get
      {
        return (object) this.<>2__current;
      }
    }

    [DebuggerHidden]
    public <GetEnumerator>d__0(int <>1__state)
    {
      base.\u002Ector();
      this.<>1__state = param0;
    }

    [DebuggerHidden]
    void IDisposable.Dispose()
    {
    }

    bool IEnumerator.MoveNext()
    {
      switch (this.<>1__state)
      {
        case 0:
          this.<>1__state = -1;
          this.<stack>5__1 = new Stack<BSTNode<TKey, TValue>>();
          this.<current>5__2 = (BSTNode<TKey, TValue>) null;
          goto label_8;
        case 1:
          this.<>1__state = -1;
          this.<current>5__2 = this.<current>5__2.Right;
          break;
        default:
          return false;
      }
label_7:
label_8:
      if (this.<stack>5__1.Count <= 0 && this.<current>5__2 == null)
        return false;
      if (this.<current>5__2 != null)
      {
        this.<stack>5__1.Push(this.<current>5__2);
        this.<current>5__2 = this.<current>5__2.Left;
        goto label_7;
      }
      else
      {
        this.<current>5__2 = this.<stack>5__1.Pop();
        this.<>2__current = this.<current>5__2;
        this.<>1__state = 1;
        return true;
      }
    }

    [DebuggerHidden]
    void IEnumerator.Reset()
    {
      throw new NotSupportedException();
    }
  }
Run Code Online (Sandbox Code Playgroud)