【问题标题】:The Iterator interface迭代器接口
【发布时间】:2013-02-28 04:45:49
【问题描述】:

我有一个大学作业,要求我实现一个实现迭代器接口的内部类。迭代器适用于单链表超类。

目前我的内部类是这样的:

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。其他一切似乎都有效。我可能在某个地方忽略了一个逻辑缺陷,但我自己找不到。

【问题讨论】:

  • next 方法不仅应该返回值,而且应该以某种方式将迭代器移动到下一个位置。您的实现只存储一个标志。
  • 不应该在next() 方法中更改temp 的值吗?
  • 附带说明,在与 Iterator 相同的包中已经有一个名为 ListIterator 的接口...因此您可能需要选择不同的名称。

标签: java iterator linked-list iterable


【解决方案1】:

更改了您的实现以反映迭代器合约的需求。您需要记住,您需要能够遍历集合的所有元素,即next() 应该从第一个元素开始,并且在每次调用之后它必须将当前的下一个元素更改为列表中的下一个元素或抛出如果没有,则例外。

最好阅读Iterator interface doc 以了解您需要实施它并从那里开始的方式。

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

}

【讨论】:

    【解决方案2】:

    您需要跟踪您在列表中的位置,实现cursor,或者如果您的链表中的节点知道它们的next,只需询问它们是否有下一个元素。 当光标大于长度/您的节点没有 next 时,您在 hasNext() 中返回 false。

    在您的 hasNext() 方法中执行所有这些操作。请记住,如果 hasNext() 为 false,则可以让 next() 引发异常 - 因此您需要确保这是唯一一次引发异常。

    由于我不知道您列表的底层数据结构,因此我无法告诉您其中哪一个会更好。

    【讨论】:

      【解决方案3】:

      如果当前节点 (temp) 不是 nullhasNext 返回 true。

      如果您的链表实现使用头节点,则构造函数始终接收fo!=null 并且hasNext 将返回true,即使列表为空。你应该在你的实现中考虑这个事实。

      根据您的代码,似乎

      ListIterator(Node fo){
          this.temp = fo.getNext();
      }
      

      可以解决问题(如果header.getNext()==null 是一个空列表)。

      【讨论】:

        【解决方案4】:

        减少一些代码,使其更具可读性

        • temp重命名为next
        • 使用快捷方式,
        • 可能应该有current节点的一些概念,

        这使得更新看起来像:

        private Node next;
        private Node current;    //track deletion
        
        @Override
        public boolean hasNext() {
            return next != null;
        }
        
        public Node getNext() {
          if (hasNext()) {
            current = next;
            next = next.getNextNode();
          }
          return current;
        }
        

        删除可以将 current 设置为 null。我们不需要标志(假设如果有人在调用第一个 getNext() 之前删除,我们可以无所事事。哎呀,如果我们真的想争取金牌,让 remove() 抛出 @987654327 @如果current == null.

        【讨论】:

        • 在我看来,这个答案将调用(主)函数与节点混淆了,目前尚不清楚为什么要将节点命名为当前节点,然后将其设置为下一个,除非您将节点向后移动结构体? (这不是 getNext 应该做的)顺便说一句,我确实喜欢捷径建议,但这并不是问题的一部分。
        • @JasonK。我必须承认,我有点困惑。我不确定 (main) 函数是如何被调用的,在任何示例中都没有 public static void main(String[] args),这个答案对于提问者来说已经足够好了,早在四年前我回答它的时候。也许你可以详细说明?
        • 可以在getNext()函数的开头声明“private Node current”,还是被其他函数使用?
        • @JasonK。如果在getNext() 函数的开头声明Node current,那么每次调用getNext() 函数时都必须设置它(否则它将为空)。假设您有一个可以在集合中获取 second 元素的Iterator,那么您设置它的内容必须在getNext() 方法之外声明。这样,对getNext() 的第三次调用可以在第二次调用“之后”返回一些内容,依此类推。在我的示例中,current 保存您拥有的内容,next 保存下一个当前值。这简化了空列表上的迭代器的逻辑。
        • 感谢我多年来一直在编写自己的结构,但我仍在学习我不了解的迭代器。 getNext() 和 next() 一样吗?如果您可以稍微编辑一下您的答案,那也会有所帮助,否则我似乎也可以自己尝试这样做。
        猜你喜欢
        • 2014-03-31
        • 1970-01-01
        • 2010-11-25
        • 2012-11-07
        • 2014-08-13
        • 2012-07-06
        • 2011-05-05
        • 2014-04-18
        • 1970-01-01
        相关资源
        最近更新 更多