C# 二进制搜索树IEnumerator.MoveNext()非递归顺序遍历实现。如何?
在构建了由C# 二进制搜索树IEnumerator.MoveNext()非递归顺序遍历实现。如何?,c#,algorithm,binary-search-tree,ienumerable,enumerator,C#,Algorithm,Binary Search Tree,Ienumerable,Enumerator,在构建了由BSTNode节点组成的二叉搜索树之后,我正在尝试为它实现IEnumerable接口 这就是我如何构造bstnodeenumerator: 我们可以将算法转换为以下c代码: public节点下一步() { 而(_stack.Count>0 | | | u current!=null) { 如果(_current!=null) { _堆栈推送(_当前); _当前=_current.left; } 其他的 { _当前=_stack.Pop(); BSTNode结果=_当前; _当前=_cu
BSTNode
节点组成的二叉搜索树之后,我正在尝试为它实现IEnumerable接口
这就是我如何构造bstnodeenumerator
:
我们可以将算法转换为以下c代码:
public节点下一步()
{
而(_stack.Count>0 | | | u current!=null)
{
如果(_current!=null)
{
_堆栈推送(_当前);
_当前=_current.left;
}
其他的
{
_当前=_stack.Pop();
BSTNode结果=_当前;
_当前=_current.Right;
}
}
返回结果;
}
但这不是必需的boolmovenext()
实现,因为我必须返回bool。如果我确实将\u current
设置为适当的节点,则为True;如果我在末尾,则为false
我应该如何实现公共bool MoveNext()?我无法理解的主要问题是,如果我想将
BSTNode Next()
转换为bool MoveNext()
我必须返回true
而不是简单地访问节点BSTNode result=\u current代码>并且仅在该设置之后\u current=\u current.Right代码>这显然是我做不到的。老实说,对于这样一个非繁琐的枚举器,最好只使用.NET内置的工具。只需返回IEnumerator
并使用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; }
}
class节点:IEnumerable
其中TKey:i可比较
{
公共IEnumerator GetEnumerator()
{
var stack=新堆栈();
无功电流=此;
while(stack.Count>0 | | current!=null)
{
如果(当前!=null)
{
堆栈推送(当前);
电流=电流。左;
}
其他的
{
当前=stack.Pop();
产生回流电流;
电流=电流。右;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
返回GetEnumerator();
}
公共节点左{get;set;}
公共节点权限{get;set;}
公钥{get;set;}
公共TValue值{get;set;}
}
如果您感到好奇,下面是编译器为它在幕后创建的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();
}
}
[编译生成]
私有密封类d__0:IEnumerator、IDisposable、IEnumerator
{
私立国际1____州;
专用节点2___当前;
公共BST节点4____;
专用堆栈5__1;
专用节点5_uu2;
BSTNode IEnumerator.Current
{
[调试隐藏]获取
{
返回此0.2__当前值;
}
}
对象IEnumerator.Current
{
[调试隐藏]获取
{
返回(对象)此0.2__当前值;
}
}
[调试程序隐藏]
公共数据0(内部1状态)
{
基本参数。\u002Ector();
此0.1__状态=参数0;
}
[调试程序隐藏]
void IDisposable.Dispose()无效
{
}
bool IEnumerator.MoveNext()
{
开关(此.1___状态)
{
案例0:
该状态为-1;
此0.5__1=新堆栈();
此0.5_uu2=(BSTNode)null;
转到标签_8;
案例1:
该状态为-1;
this.5_uuuu2=this.5_uuuu2.Right;
打破
违约:
返回false;
}
标签7:
标签8:
如果(this.5_uu1.Count调用方正在枚举上循环(可能在foreach循环中)。因此,您可以在每次希望返回结果时中止循环。出现了一个问题,因为\u current=\u current.Right;
必须在确定结果后执行。因此,我将引入一个新变量\u result
private BSTNode<TKey, TValue> _result;
bool IEnumerator.MoveNext()
{
while (_stack.Count > 0 || _current != null)
{
if (_current != null)
{
_stack.Push(_current);
_current = _current.left;
}
else
{
_current = _stack.Pop();
_result = _current;
_current = _current.Right;
return true;
}
}
return false;
}
BSTNode<TKey, TValue> IEnumerator<BSTNode<TKey, TValue>>.Current
{
get { return _result; }
}
private BSTNode\u结果;
bool IEnumerator.MoveNext()
{
而(_stack.Count>0 | | | u current!=null)
{
如果(_current!=null)
{
_堆栈推送(_当前);
_当前=_current.left;
}
其他的
{
_当前=_stack.Pop();
_结果=_电流;
_当前=_current.Right;
返回true;
}
}
返回false;
}
BSTNode IEnumerator.Current
{
获取{return\u result;}
}
请注意,枚举上的循环包括第一次调用MoveNext()
并测试布尔结果。如果返回了true
,则使用Current
返回的值。为什么不直接使用HashSet或Dictionary?您需要自己制作IEnumerator吗?为什么不让GetEnumerator函数直接返回您的实现,而是在上执行返回当前值;
BSTNode result=_current;
line。我将发布一个实现作为答案。@MatthewWhited-当然我可以简单地使用.Net中已经存在的东西,我只是在尝试学习。我现在也在与AVL二叉树和Skiplits作斗争,只是为了它。我确信这是可以理解的。我的意思是.Net不仅仅来自天空。真的吗d@ScottChamberlain注释。迭代器方法和yield
语句是专门为非平凡的枚举数设计的。我知道,yield-return
基本上保留了枚举的当前状态,使我的生活更轻松。@pijemcolu,如果你想了解更多的话。你还可以用yield
做其他很酷的技巧,如果您的代码中有一个try/finally
,如果调用方处理了IEnumerator
,finally
块中的代码将被执行,如果它在try
块中等待yield return
。啊,这就是执行的方法。我试图找出一条漫长的路,我没有想到addi
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; }
}
[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();
}
}
private BSTNode<TKey, TValue> _result;
bool IEnumerator.MoveNext()
{
while (_stack.Count > 0 || _current != null)
{
if (_current != null)
{
_stack.Push(_current);
_current = _current.left;
}
else
{
_current = _stack.Pop();
_result = _current;
_current = _current.Right;
return true;
}
}
return false;
}
BSTNode<TKey, TValue> IEnumerator<BSTNode<TKey, TValue>>.Current
{
get { return _result; }
}