循环单链表迭代器的问题

时间:2015-07-16 14:45:42

标签: java data-structures linked-list singly-linked-list circular-list

我正在尝试为我的循环单链表创建一个迭代器,但我不承诺如何实现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;
    }

} 

2 个答案:

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

注意我没有完全检查您的insertdelete逻辑,如果这不起作用,请确保您的其他功能正确无误。如果有任何问题,请告诉我。

答案 1 :(得分:1)

是的,您的迭代器中存在问题。它忽略了最后一项(头部)。例如,假设您的列表中只有一个元素。因此,headtail都指向它,以及head.next

现在,如果我们在这样的列表上询问hasNext()新的迭代器,我们应该得到true一次,然后,在我们调用next()之后,得到错误

但你的条件是:

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

这意味着对于单个元素列表,无论如何,您都将返回false

此外,即使我们假设我们有多个元素,也可以说:

2->1

然后使用p = head.nextq = head初始化迭代器。您的hasNext()将返回true,但您的next()会做什么?

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

因此,它会在开头返回2,然后移动pq。没关系,打印2。但现在q再次指向1p2。同样,您的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,你将第一次获得2p会提前到1和{{1是假的。

现在第二次,atStart看到hasNext()指向不是p的{​​{1}},因此它返回1。在head我们返回true,然后将next()推进到头部。

再次拨打1将会停止,因为p已回到头部,但hasNext()为假。