我正在尝试为我的循环单链表创建一个迭代器,但我不承诺如何实现next()和hasNext()方法。我怀疑我需要1)在链表类或迭代器类中有其他字段,或者2)引用其他字段而不是' head'并且'尾巴'? 我的代码如下:
public class CircularSinglyLinkedList2<E> implements Iterable<E> {
private Node head;
private Node tail;
public CircularSinglyLinkedList2() {
head = null;
tail = null;
}
class Node {
E data;
Node next;
private Node(E data) {
this.data = data;
}
}
private boolean isEmpty() {
return head == null;
}
private int size() {
int count = 0;
if(isEmpty()) {
return 0;
}
Node p = head;
count++;
p = p.next;
while(p != head) {
count++;
p = p.next;
}
return count;
}
public void insert(E data) {
Node node = new Node(data);
if(isEmpty()) {
node.next = node;
head = node;
tail = node;
} else {
node.next = head;
head = node;
tail.next = head;
}
}
public void delete(E data) {
if(isEmpty()) {
return;
}
if(head == tail) {
if(head.data == data) {
head = null;
tail = null;
}
return;
}
Node p = head.next, q = head;
while(p != head) {
if(p.data == data) {
q.next = p.next;
return;
}
q = p;
p = p.next;
}
}
public Node search(E data) {
if(isEmpty()) {
return null;
}
Node p = head;
if(p.data == data) {
return p;
}
p = p.next;
while(p != head) {
if(p.data == data) {
return p;
}
p = p.next;
}
return null;
}
public boolean contains(E data) {
return search(data) != null;
}
public Iterator<E> iterator() {
return new SLLIterator();
}
private class SLLIterator implements Iterator<E> {
private Node p;
private Node q;
public SLLIterator() {
if(!isEmpty()) {
p = head.next;
q = head;
}
}
@Override
public boolean hasNext() { doesnt't work
if(p == q || p == head) {
return false;
}
return true;
}
@Override
public E next() { //doesn't work
E data = q.data;
q = p;
p = p.next;
return data;
}
}
答案 0 :(得分:2)
您的hasNext()
不完全正确。由于您的p == head
条件,您将始终错过打印最后一个元素。因此,检查p
无助于决定hasNext()
。
理想情况下,您要检查的是q == head
,这是当您完成对所有元素的迭代并返回到起始元素并且hasNext()
应该返回false
时,但是如果你只需检查q == head
,它就不会起作用,因为你的起始元素本身就会失败。因此,请使用标记来确定您是回来还是第一次来访。
我建议你做这样的事情:
使用visitingAgain
标志。
boolean visitingAgain = false;
在hasNext()
中使用它,如下所示。
@Override
public boolean hasNext() {
if (p == q || (q == head && visitingAgain)){
return false;
}
visitingAgain = true; // once you start iterating change this flag.
return true;
}
注意我没有完全检查您的insert
和delete
逻辑,如果这不起作用,请确保您的其他功能正确无误。如果有任何问题,请告诉我。
答案 1 :(得分:1)
是的,您的迭代器中存在问题。它忽略了最后一项(头部)。例如,假设您的列表中只有一个元素。因此,head
和tail
都指向它,以及head.next
。
现在,如果我们在这样的列表上询问hasNext()
新的迭代器,我们应该得到true
一次,然后,在我们调用next()
之后,得到错误
但你的条件是:
if(p == q || p == head) {
return false;
}
这意味着对于单个元素列表,无论如何,您都将返回false
。
此外,即使我们假设我们有多个元素,也可以说:
2->1
然后使用p = head.next
和q = head
初始化迭代器。您的hasNext()
将返回true,但您的next()
会做什么?
public E next() { //doesn't work
E data = q.data;
q = p;
p = p.next;
return data;
}
因此,它会在开头返回2
,然后移动p
和q
。没关系,打印2
。但现在q
再次指向1
和p
点2
。同样,您的hasNext()
会看到p == head
并且说没有更多元素!
因此q
当前指向的元素(实际的下一个元素)将被忽略。
你应该做的是有一种标志,告诉你当你第二次第二次而不是第一次时。并且实际上不需要两个指针。这是我的迭代器版本:
private class SLLIterator implements Iterator<E> {
private Node p;
private boolean atStart;
public SLLIterator() {
if(!isEmpty()) {
p = head;
atStart = true;
}
}
@Override
public boolean hasNext() {
if(isEmpty() || p == head && ! atStart) {
return false;
}
return true;
}
@Override
public E next() {
E data = p.data;
atStart = false;
p = p.next;
return data;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
此迭代器有一个atStart
标志,开头为true
。因此,当在单项列表上调用hasNext()
时,它会看到p
指向头部,但它也会看到这是第一次,因此返回true
}。
在这种情况下,next()
方法将为您提供p
指向的数据,这是头部中的数据。此时,atStart
已更改为false,因此虽然p
已提前并圈回,但又是head
,但下次我们调用hasNext()
时,我们会赢'再次返回true
。
如果你有一个更长的列表,例如2->1
,你将第一次获得2
,p
会提前到1
和{{1是假的。
现在第二次,atStart
看到hasNext()
指向不是p
的{{1}},因此它返回1
。在head
我们返回true
,然后将next()
推进到头部。
再次拨打1
将会停止,因为p
已回到头部,但hasNext()
为假。