我正在尝试使用我制作的自定义链表列表,并在我的一个C#程序中使用枚举器。我不想显示太多的代码,所以希望这已经足够了。
我不确定,但这是枚举器看起来应该是什么样的?
class SinglyLinkedListEnumerator<T> : IEnumerator<T>
{
private Node<E> node;
private Node<E> start;
public SinglyLinkedListEnumerator(Node<T> node)
{
this.node = node;
start = node;
}
public T Current
{
get { return node.getData(); }
}
public Boolean MoveNext()
{
if (node.getNext() != null)
{
node = node.getNext();
return true;
}
return false;
}
public void Reset()
{
node = start;
}
public void IDisposable.Dispose()
{
}
}
迭代器块使创建实现IEnumerable<T>
的对象变得更加容易:
public static IEnumerable<T> Iterate<T>(Node<T> root)
{
var current = root;
while (current != null)
{
yield return current.getData();
current = current.getNext();
}
}
它删除了大多数样板代码,只是让你定义所有逻辑来确定序列中的节点是什么,同时仍然提供所有功能,就像你所做的那样写出所有代码。
在C#世界中,这个概念称为枚举而不是迭代。不要与enum
混淆。
无论如何,您正在寻找的各个接口是IEnumerable<T>
命名空间中的IEnumerator<T>
和System.Collections.Generic
。查看他们的文档,你应该很高兴。这个概念本身与你在Java中所做的完全相同。
我不知道你的Node<T>
代码是什么样的,但这看起来很奇怪:
public Boolean MoveNext()
{
if (node.getNext() != null)
{
node = node.getNext();
return true;
}
return false;
}
理想情况下,看起来MoveNext看起来像这样:
public Boolean MoveNext()
{
// make sure current node is not null
if (node != null)
{
node = node.getNext();
}
// simply return whether current node is null or not
return node != null;
}
在您的初始方法中,您将获得两次下一个节点,这可能会给您错误的结果。我假设getNext
只返回对当前节点的下一个兄弟的引用。否则,我没有看到您的枚举器(或迭代器)类的任何初始问题。
为清楚起见,我会使用currentNode
而不是node
并将start
更改为startNode
。
此外,如果node.getNext()
没有返回Node对象,则应重命名该方法以指示它正在做什么。
我假设node.getNext()
正在移动内部参考,但@Servy纠正了我。谢谢!
我可能仍会建议更改一些名称来澄清操作。 :)
链表的枚举器应如下所示:
public class MyLinkedList : IEnumerable {
Node head = null;
Node current = null;
public IEnumerator GetEnumerator()
{
current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
而节点本身
public class Node
{
public int Data;
public Node Next;
public Node(int value) { Data = value; }
}
对于二叉树,您应该实现所有三个:Current,MoveNext和Reset +不要忘记Constructor。