我有一个大学作业,要求我实现一个实现Iterator接口的内部类。迭代器适用于单链表超类。
当前我的内部类如下所示:
private class ListIterator implements Iterator<V>{
Node temp;
boolean nextCalled = false;
ListIterator(Node fo){
this.temp = fo;
}
@Override
public boolean hasNext() {
if(temp != null){
return true;
}
return false;
}
@Override
public V next() {
nextCalled = true;
return temp.getReprValue();
}
@Override
public void remove() {
if(nextCalled && hasNext()){
nextCalled = false;
removeElement(temp.getReprKey());
temp = temp.getNext();
}
}
}
现在我的问题是,即使列表实际上为空,hasNext()方法也会返回true。其他一切似乎都起作用了。我可能忽略了某个地方的逻辑缺陷,但我自己找不到。
如果当前节点(temp
)不是null
,则hasNext
返回true。
如果您的链表实现使用头节点,那么构造函数总是收到fo=null和hasNext将返回true,即使列表为空。您应该在实现中考虑这一事实。
根据你的代码,似乎
ListIterator(Node fo){
this.temp = fo.getNext();
}
可能会成功(如果header.getNext()==null
为空列表)。
您需要跟踪您在列表中的位置,实现光标,或者如果链接列表中的节点知道它们的下一个元素,只需询问它们是否有下一个元素。当光标大于长度/节点没有下一步时,在hasNext()中返回false。
在您的hasNext()
方法中执行所有这些操作。请记住,如果hasNext()为false,则让next()引发异常是可以的,因此您需要确保这是它引发异常的唯一时间。
由于我不知道列表的底层数据结构,我无法告诉您哪一个更好。
更改了您的实现以反映Iterator合约需要的内容。您需要记住,您需要能够遍历集合的所有元素,即Next()
应该从第一个元素开始,并且在每次调用之后,它必须将当前的下一个元素更改为列表中的下一个元素,或者如果没有,则抛出异常。
阅读Iterator接口文档以理解您需要实现它并从那里开始的方式是很好的。
private class ListIterator implements Iterator<V> {
private Node next;
private boolean alreadyDeleted = false;
ListIterator(Node node){
this.next = node;
}
@Override
public boolean hasNext() {
// because next is the current element. We need to iterate over all the elements
// from the collection.
return next != null;
}
@Override
public V next() {
if (next == null) {
throw new NoSuchElementException();
}
Node current = next;
this.next = current.getNext();
this.alreadyDeleted = false; // it's better to try to elimate this state variable. You can try to do in another way, if yours removeElement returns something
return current;
}
@Override
public void remove() {
if (alreadyDeleted || next == null) {
throw new IllegalStateException();
}
removeElement(next.getReprKey());
this.alreadyRemoved = true;
}
}
迭代器 乍看来,迭代器似乎很直观。但凑近了看,你会发现标准STL容器提供了四种不同的迭代器:iterator、const_iterator、reverse_iterator和const_reverse_iterator。很快你会注意到在这四种类型中,容器的insert和erase的某些形式只接受其中一种。那是问题的开始。为什么有四种迭代器?它们之间的关系是什么?它们可以互相转化吗?在调用算法和ST
For freedom Christ has set us free. Stand firm, therefore, and do not submit again to a yoke of slavery. 基督释放了我们,叫我们得以自由,所以要站立得稳,不要再被奴仆的轭挟制。(GALATIANS 5:1) 迭代器 迭代,对于读者已经不陌生了,曾有专门一节来讲述,如果印象不深,请复习《迭代》。
在Rust中,迭代器共分为三个部分:迭代器、适配器、消费者。 其中,迭代器本身提供了一个惰性的序列,适配器对这个序列进行诸如筛选、拼接、转换查找等操作,消费者则在前两者的基础上生成最后的数值集合。 但是,孤立的看这三者其实是没有意义的,因此,本章将在一个大节里联系写出三者。 迭代器、适配器、消费者
正如我们之前学到的,在Python中我们可以使用“for”循环来迭代出对象中的内容: >>> for value in [0, 1, 2, 3, 4, 5]: ... print(value) ... 0 1 4 9 16 25 可以使用“for”循环(迭代)的对象称为迭代器。因此,一个迭代器也就是一个遵循了迭代协议的对象。 内置函数“iter”可以用来创建一个迭代对象,这时使用“next”函数
我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list、tuple、dict、set、str等; 一类是generator,包括生成器和带yield的generator function。 这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。 可以使用isinstance()判断一个对象是否是Iterable对象: >>> from coll
从for循环讲起 我们在控制语句里学习了Rust的for循环表达式,我们知道,Rust的for循环实际上和C语言的循环语句是不同的。这是为什么呢?因为,for循环不过是Rust编译器提供的语法糖! 首先,我们知道Rust有一个for循环能够依次对迭代器的任意元素进行访问,即: for i in 1..10 { println!("{}", i); } 这里我们知道, (1..10) 其本身