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;我显然不能做的设置之后.
老实说,对于像这样的非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)