简体   繁体   English

循环单链表迭代器的问题

[英]Problems with circular singly linked list iterator

I am trying to make an iterator for my circular singly linked list, but I don't undertand how to implement the next() and hasNext() methods. 我试图为我的循环单链表创建一个迭代器,但我不承诺如何实现next()和hasNext()方法。 I suspect that I need to either 1) have additional fields in the linked list class or the iterator class, or 2) have references to something else instead of 'head' and 'tail'? 我怀疑我需要1)在链表类或迭代器类中有其他字段,或2)引用其他东西而不是'head'和'tail'? My code is below: 我的代码如下:

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;
    }

} 

Your hasNext() is not completely correct. 你的hasNext()不完全正确。 Because of your p == head condition, you will always miss out printing the last element. 由于您的p == head条件,您将始终错过打印最后一个元素。 So checking p will not help in deciding hasNext() . 所以检查p将无助于决定hasNext()

Ideally what you want to check is q == head , this is when you finish iterating the all the elements and came back to the starting element and your hasNext() should return false , but if you simply check q == head , it's not going to work because for your starting element itself it will fail. 理想情况下你要检查的是q == head ,这是当你完成所有元素的迭代并返回到起始元素并且你的hasNext()应该返回false ,但如果你只是检查q == head ,那么它不是开始工作,因为你的起始元素本身就会失败。 So use a flag to find out whether you came back or you are visiting for the first time. 因此,请使用标记来确定您是回来还是第一次来访。

I would suggest you to do something like this: 我建议你这样做:

use visitingAgain flag. 使用visitingAgain flag。

boolean visitingAgain = false;

Use it in your hasNext() like the following. 在你的hasNext()使用它,如下所示。

@Override
public boolean hasNext() { 
   if (p == q || (q == head && visitingAgain)){
      return false;
   }
   visitingAgain = true; // once you start iterating change this flag.
   return true;
}

NOTE I did not check your insert and delete logic completely, if this does not work just make sure that your other functions are correct. 注意我没有完全检查你的insertdelete逻辑,如果这不起作用只是确保你的其他功能是正确的。 Let me know if there is any problem. 如果有任何问题,请告诉我。

Yes, there is a problem in your iterator. 是的,您的迭代器中存在问题。 It ignores the last item (the head). 它忽略了最后一项(头部)。 For example, imagine that you have just one element in your list. 例如,假设您的列表中只有一个元素。 So both head and tail point to it, as well as head.next . 所以headtail指向它,以及head.next

Now, if we ask hasNext() on a fresh iterator on such a list, we are supposed to get true one time, and then, after we call next() , to get false. 现在,如果我们在这样的列表上的新迭代器上请求hasNext() ,我们应该得到一次true ,然后,在我们调用next() ,得到false。

But your condition is: 但你的条件是:

   if(p == q || p == head) {
        return false;
    }

Which means that for a single-element list, you're going to return false , no matter what. 这意味着对于单元素列表,无论如何,您都将返回false

Also, even when we assume we have more than one element, say: 此外,即使我们假设我们有多个元素,也说:

2->1

Then You initialize the iterator with p = head.next and q = head . 然后用p = head.nextq = head初始化迭代器。 Your hasNext() will return true, but what does your next() do? 你的hasNext()将返回true,但你的next()做什么?

public E next() { //doesn't work
    E data = q.data;
    q = p;
    p = p.next;
    return data;
}

So, it returns the 2 at the beginning, and moves the p and q . 因此,它在开头返回2 ,并移动pq That's OK, 2 is printed. 没关系,打印出2 But now q points at the 1 and p points again at the 2 . 但现在q在点1p再次在点2 And again, your hasNext() sees that p == head and says there are no more elements! 再次,你的hasNext()看到p == head并且说没有更多的元素!

So the element currently pointed to by q , the actual next element, is ignored. 因此,当前指向q的元素(实际的下一个元素)将被忽略。

What you should do is have some sort of a flag that tells you when you hit the head the second time as opposed to the first. 你应该做的是有一种标志告诉你第二次击中头部而不是第一次。 And there is really no need for two pointers. 并且实际上不需要两个指针。 Here is my version of the iterator: 这是我的迭代器版本:

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();
    }

}

This iterator has an atStart flag which starts out as true . 这个迭代器有一个atStart标志,开头为true So when hasNext() is called on a single-item list, it sees that p points at the head, but it also sees that this is the first time it does, and so it returns true . 因此,当在单项列表上hasNext()时,它会看到p指向头部,但它也会看到这是第一次,所以它返回true

And the next() method, in this case, will give you the data pointed at by p , which is the data in the head. 在这种情况下, next()方法将为您提供p指向的数据,这是头部中的数据。 At this point, atStart is changed to false, so although p is advanced and circles back, and is again head , the next time we call hasNext() , we won't return true again. 此时, atStart更改为false,因此虽然p是高级并且atStart回来,并且再次是head ,但是下次我们调用hasNext() ,我们将不会再次返回true

And if you have a longer list like 2->1 , you'll get the 2 the first time, and p is advanced to the 1 and atStart is false. 如果您有一个更长的列表,如2->1 ,您将第一次获得2 ,并且p将提前到1并且atStart为false。

Now the second time, hasNext() sees that p is pointing at the 1 which is not the head so it returns true . 现在第二次, hasNext()看到p指向不是head1 ,所以它返回true And in the next() we return the 1 , and advance p to the head. next()我们返回1 ,并将p前进到头部。

Calling hasNext() again will stop because p is back to the head, but atStart is false. 再次调用hasNext()将停止,因为p返回头部,但atStart为false。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM